diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-01-23 05:35:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-01-23 05:35:03 +0000 |
commit | 3ac1eed6033500851faea31f0e07945491685d56 (patch) | |
tree | 28b1c8d5af47dd63f3ca1318081ce56cba92c3bc | |
parent | Adding upstream version 1.13. (diff) | |
download | lunzip-3ac1eed6033500851faea31f0e07945491685d56.tar.xz lunzip-3ac1eed6033500851faea31f0e07945491685d56.zip |
Adding upstream version 1.14~rc1.upstream/1.14_rc1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | INSTALL | 17 | ||||
-rw-r--r-- | Makefile.in | 9 | ||||
-rw-r--r-- | NEWS | 23 | ||||
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | carg_parser.c | 4 | ||||
-rw-r--r-- | carg_parser.h | 4 | ||||
-rwxr-xr-x | configure | 25 | ||||
-rw-r--r-- | decoder.c | 62 | ||||
-rw-r--r-- | decoder.h | 12 | ||||
-rw-r--r-- | doc/lunzip.1 | 26 | ||||
-rw-r--r-- | list.c | 7 | ||||
-rw-r--r-- | lzip.h | 67 | ||||
-rw-r--r-- | lzip_index.c | 90 | ||||
-rw-r--r-- | lzip_index.h | 14 | ||||
-rw-r--r-- | main.c | 255 | ||||
-rwxr-xr-x | testsuite/check.sh | 206 | ||||
-rw-r--r-- | testsuite/fox6.lz | bin | 0 -> 480 bytes | |||
-rw-r--r-- | testsuite/fox6_mark.lz | bin | 0 -> 480 bytes |
20 files changed, 490 insertions, 367 deletions
@@ -1,7 +1,7 @@ Lunzip was written by Antonio Diaz Diaz. The ideas embodied in lunzip are due to (at least) the following people: -Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the +Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the definition of Markov chains), G.N.N. Martin (for the definition of range encoding), Igor Pavlov (for putting all the above together in LZMA), and Julian Seward (for bzip2's CLI). @@ -1,3 +1,15 @@ +2023-12-21 Antonio Diaz Diaz <antonio@gnu.org> + + * Version 1.14-rc1 released. + * New options '--empty-error' and '--marking-error'. + * main.c: Reformat file diagnostics as 'PROGRAM: FILE: MESSAGE'. + (show_option_error): New function showing argument and option name. + (open_outstream): Create missing intermediate directories. + * lzip.h: Rename verify_* to check_*. + * configure, Makefile.in: New variable 'MAKEINFO'. + * INSTALL: Document use of CFLAGS+='--std=c99 -D_XOPEN_SOURCE=500'. + * testsuite: New test files fox6.lz, fox6_mark.lz. + 2022-01-22 Antonio Diaz Diaz <antonio@gnu.org> * Version 1.13 released. @@ -55,7 +67,7 @@ * Version 1.8 released. * main.c: New option '-a, --trailing-error'. - * main.c (main): With '-u', verify that output file is regular. + * main.c (main): With '-u', check that output file is regular. * main.c (decompress): Print up to 6 bytes of trailing data when '-vvvv' is specified. * decoder.c (LZd_verify_trailer): Remove test of final code. @@ -121,7 +133,7 @@ * Created from the decompression code of clzip 1.1. -Copyright (C) 2010-2022 Antonio Diaz Diaz. +Copyright (C) 2010-2023 Antonio Diaz Diaz. 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 @@ -18,8 +18,8 @@ Procedure or lzip -cd lunzip[version].tar.lz | tar -xf - -This creates the directory ./lunzip[version] containing the source from -the main archive. +This creates the directory ./lunzip[version] containing the source code +extracted from the archive. 2. Change to lunzip directory and run configure. (Try 'configure --help' for usage instructions). @@ -27,6 +27,10 @@ the main archive. cd lunzip[version] ./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: ./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 lunzip. 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 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 in the directory that 'configure' is in. -'configure' recognizes the option '--srcdir=DIR' to control where to -look for the sources. Usually 'configure' can determine that directory +'configure' recognizes the option '--srcdir=DIR' to control where to look +for the source code. Usually 'configure' can determine that directory automatically. After running 'configure', you can run 'make' and 'make install' as explained above. -Copyright (C) 2010-2022 Antonio Diaz Diaz. +Copyright (C) 2010-2023 Antonio Diaz Diaz. This file is free documentation: you have unlimited permission to copy, distribute, and modify it. diff --git a/Makefile.in b/Makefile.in index ffc4ce8..ea04dd8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,6 +28,10 @@ main.o : main.c %.o : %.c $(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 carg_parser.o : carg_parser.h decoder.o : lzip.h decoder.h @@ -35,13 +39,12 @@ list.o : lzip.h lzip_index.h lzip_index.o : lzip.h lzip_index.h main.o : carg_parser.h lzip.h decoder.h - doc : man info : $(VPATH)/doc/$(pkgname).info $(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 @@ -121,6 +124,8 @@ dist : doc $(DISTNAME)/testsuite/test.txt \ $(DISTNAME)/testsuite/fox.lz \ $(DISTNAME)/testsuite/fox_*.lz \ + $(DISTNAME)/testsuite/fox6.lz \ + $(DISTNAME)/testsuite/fox6_mark.lz \ $(DISTNAME)/testsuite/test.txt.lz \ $(DISTNAME)/testsuite/test_em.txt.lz rm -f $(DISTNAME) @@ -1,6 +1,21 @@ -Changes in version 1.13: +Changes in version 1.14: -Decompression time has been reduced by 5-12% depending on the file. +The option '--empty-error', which forces exit status 2 if any empty member +is found, has been added. -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. +The option '--marking-error', which forces exit status 2 if the first LZMA +byte is non-zero in any member, has been added. + +File diagnostics have been reformatted as 'PROGRAM: FILE: MESSAGE'. + +Diagnostics caused by invalid arguments to command-line options now show the +argument and the name of the option. + +The option '-o, --output' now creates missing intermediate directories when +writing to a 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' @@ -61,25 +61,25 @@ filename.tlz becomes filename.tar anyothername becomes anyothername.out Decompressing a file is much like copying or moving it. Therefore lunzip -preserves the access and modification dates, permissions, and, when -possible, ownership of the file just as 'cp -p' does. (If the user ID or -the group ID can't be duplicated, the file permission bits S_ISUID and -S_ISGID are cleared). +preserves the access and modification dates, permissions, and, if you have +appropriate privileges, ownership of the file just as 'cp -p' does. (If the +user ID or the group ID can't be duplicated, the file permission bits +S_ISUID and S_ISGID are cleared). Lunzip is able to read from some types of non-regular files if either the option '-c' or the option '-o' is specified. If no file names are specified, lunzip decompresses from standard input to -standard output. In this case, lunzip will refuse to read compressed input -from a terminal, as this might leave the terminal in an abnormal state. +standard output. In this case, lunzip refuses to read compressed input from +a terminal, as this might leave the terminal in an abnormal state. -Lunzip will correctly decompress a file which is the concatenation of two or +Lunzip correctly decompresses a file which is the concatenation of two or more compressed files. The result is the concatenation of the corresponding decompressed files. Integrity testing of concatenated compressed files is also supported. The ideas embodied in lunzip are due to (at least) the following people: -Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the +Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the definition of Markov chains), G.N.N. Martin (for the definition of range encoding), Igor Pavlov (for putting all the above together in LZMA), and Julian Seward (for bzip2's CLI). @@ -89,7 +89,7 @@ been compressed. Decompressed is used to refer to data which have undergone the process of decompression. -Copyright (C) 2010-2022 Antonio Diaz Diaz. +Copyright (C) 2010-2023 Antonio Diaz Diaz. This file is free documentation: you have unlimited permission to copy, distribute, and modify it. diff --git a/carg_parser.c b/carg_parser.c index 181ba23..8882b97 100644 --- a/carg_parser.c +++ b/carg_parser.c @@ -1,5 +1,5 @@ -/* Arg_parser - POSIX/GNU command line argument parser. (C version) - Copyright (C) 2006-2022 Antonio Diaz Diaz. +/* Arg_parser - POSIX/GNU command-line argument parser. (C version) + Copyright (C) 2006-2023 Antonio Diaz Diaz. This library is free software. Redistribution and use in source and binary forms, with or without modification, are permitted provided diff --git a/carg_parser.h b/carg_parser.h index 0c64861..ec5d3d0 100644 --- a/carg_parser.h +++ b/carg_parser.h @@ -1,5 +1,5 @@ -/* Arg_parser - POSIX/GNU command line argument parser. (C version) - Copyright (C) 2006-2022 Antonio Diaz Diaz. +/* Arg_parser - POSIX/GNU command-line argument parser. (C version) + Copyright (C) 2006-2023 Antonio Diaz Diaz. This library is free software. Redistribution and use in source and binary forms, with or without modification, are permitted provided @@ -1,12 +1,12 @@ #! /bin/sh # configure script for Lunzip - Decompressor for the lzip format -# Copyright (C) 2010-2022 Antonio Diaz Diaz. +# Copyright (C) 2010-2023 Antonio Diaz Diaz. # # This configure script is free software: you have unlimited permission # to copy, distribute, and modify it. pkgname=lunzip -pkgversion=1.13 +pkgversion=1.14-rc1 progname=lunzip srctrigger=doc/${progname}.1 @@ -24,6 +24,7 @@ CC=gcc CPPFLAGS= CFLAGS='-Wall -W -O2' LDFLAGS= +MAKEINFO=makeinfo # checking whether we are using GNU C. /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 " -h, --help display this help 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 " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]" echo " --bindir=DIR user executables directory [${bindir}]" @@ -65,10 +66,11 @@ while [ $# != 0 ] ; do echo " --infodir=DIR info files directory [${infodir}]" echo " --mandir=DIR man pages directory [${mandir}]" echo " CC=COMPILER C compiler to use [${CC}]" - echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]" - echo " CFLAGS=OPTIONS command line options for the C compiler [${CFLAGS}]" + echo " CPPFLAGS=OPTIONS command-line options for the preprocessor [${CPPFLAGS}]" + echo " CFLAGS=OPTIONS command-line options for the C compiler [${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 exit 0 ;; --version | -V) @@ -96,6 +98,7 @@ while [ $# != 0 ] ; do CFLAGS=*) CFLAGS=${optarg} ;; CFLAGS+=*) CFLAGS="${CFLAGS} ${optarg}" ;; LDFLAGS=*) LDFLAGS=${optarg} ;; + MAKEINFO=*) MAKEINFO=${optarg} ;; --*) echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;; @@ -115,7 +118,7 @@ while [ $# != 0 ] ; do fi done -# Find the source files, if location was not specified. +# Find the source code, if location was not specified. srcdirtext= if [ -z "${srcdir}" ] ; then srcdirtext="or . or .." ; srcdir=. @@ -127,7 +130,7 @@ if [ -z "${srcdir}" ] ; then fi 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 exit 1 fi @@ -147,7 +150,7 @@ if [ -z "${no_create}" ] ; then # This script is free software: you have unlimited permission # to copy, distribute, and modify it. -exec /bin/sh $0 ${args} --no-create +exec /bin/sh "$0" ${args} --no-create EOF chmod +x config.status fi @@ -164,10 +167,11 @@ echo "CC = ${CC}" echo "CPPFLAGS = ${CPPFLAGS}" echo "CFLAGS = ${CFLAGS}" echo "LDFLAGS = ${LDFLAGS}" +echo "MAKEINFO = ${MAKEINFO}" rm -f Makefile cat > Makefile << EOF # Makefile for Lunzip - Decompressor for the lzip format -# Copyright (C) 2010-2022 Antonio Diaz Diaz. +# Copyright (C) 2010-2023 Antonio Diaz Diaz. # This file was generated automatically by configure. Don't edit. # # This Makefile is free software: you have unlimited permission @@ -187,6 +191,7 @@ CC = ${CC} CPPFLAGS = ${CPPFLAGS} CFLAGS = ${CFLAGS} LDFLAGS = ${LDFLAGS} +MAKEINFO = ${MAKEINFO} EOF cat "${srcdir}/Makefile.in" >> Makefile @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -111,24 +111,21 @@ void LZd_flush_data( struct LZ_decoder * const d ) } -static bool LZd_verify_trailer( struct LZ_decoder * const d, - struct Pretty_print * const pp ) +static int LZd_check_trailer( struct LZ_decoder * const d, + struct Pretty_print * const pp, + const bool ignore_empty ) { Lzip_trailer trailer; int size = Rd_read_data( d->rdec, trailer, Lt_size ); - const unsigned long long data_size = LZd_data_position( d ); - const unsigned long long member_size = Rd_member_position( d->rdec ); bool error = false; if( size < Lt_size ) { error = true; if( verbosity >= 0 ) - { - Pp_show_msg( pp, 0 ); - fprintf( stderr, "Trailer truncated at trailer position %d;" - " some checks may fail.\n", size ); - } + { Pp_show_msg( pp, 0 ); + fprintf( stderr, "Trailer truncated at trailer position %d;" + " some checks may fail.\n", size ); } while( size < Lt_size ) trailer[size++] = 0; } @@ -137,35 +134,32 @@ static bool LZd_verify_trailer( struct LZ_decoder * const d, { error = true; if( verbosity >= 0 ) - { - Pp_show_msg( pp, 0 ); - fprintf( stderr, "CRC mismatch; stored %08X, computed %08X\n", - td_crc, LZd_crc( d ) ); - } + { Pp_show_msg( pp, 0 ); + fprintf( stderr, "CRC mismatch; stored %08X, computed %08X\n", + td_crc, LZd_crc( d ) ); } } + const unsigned long long data_size = LZd_data_position( d ); const unsigned long long td_size = Lt_get_data_size( trailer ); if( td_size != data_size ) { error = true; if( verbosity >= 0 ) - { - Pp_show_msg( pp, 0 ); - fprintf( stderr, "Data size mismatch; stored %llu (0x%llX), computed %llu (0x%llX)\n", - td_size, td_size, data_size, data_size ); - } + { Pp_show_msg( pp, 0 ); + fprintf( stderr, "Data size mismatch; stored %llu (0x%llX), computed %llu (0x%llX)\n", + td_size, td_size, data_size, data_size ); } } + const unsigned long long member_size = Rd_member_position( d->rdec ); const unsigned long long tm_size = Lt_get_member_size( trailer ); if( tm_size != member_size ) { error = true; if( verbosity >= 0 ) - { - Pp_show_msg( pp, 0 ); - fprintf( stderr, "Member size mismatch; stored %llu (0x%llX), computed %llu (0x%llX)\n", - tm_size, tm_size, member_size, member_size ); - } + { Pp_show_msg( pp, 0 ); + fprintf( stderr, "Member size mismatch; stored %llu (0x%llX), computed %llu (0x%llX)\n", + tm_size, tm_size, member_size, member_size ); } } - if( error ) return false; + if( error ) return 3; + if( !ignore_empty && data_size == 0 ) return 5; if( verbosity >= 2 ) { if( verbosity >= 4 ) show_header( d->dictionary_size ); @@ -180,13 +174,15 @@ static bool LZd_verify_trailer( struct LZ_decoder * const d, if( verbosity >= 3 ) fprintf( stderr, "%9llu out, %8llu in. ", data_size, member_size ); } - return true; + return 0; } /* Return value: 0 = OK, 1 = decoder error, 2 = unexpected EOF, - 3 = trailer error, 4 = unknown marker found. */ + 3 = trailer error, 4 = unknown marker found, + 5 = empty member found, 6 = marked member found. */ int LZd_decode_member( struct LZ_decoder * const d, + const struct Cl_options * const cl_opts, struct Pretty_print * const pp ) { struct Range_decoder * const rdec = d->rdec; @@ -222,7 +218,7 @@ int LZd_decode_member( struct LZ_decoder * const d, Lm_init( &match_len_model ); Lm_init( &rep_len_model ); - Rd_load( rdec ); + if( !Rd_load( rdec, cl_opts->ignore_marking ) ) return 6; while( !Rd_finished( rdec ) ) { const int pos_state = LZd_data_position( d ) & pos_state_mask; @@ -287,13 +283,9 @@ int LZd_decode_member( struct LZ_decoder * const d, Rd_normalize( rdec ); LZd_flush_data( d ); if( len == min_match_len ) /* End Of Stream marker */ - { - if( LZd_verify_trailer( d, pp ) ) return 0; else return 3; - } + return LZd_check_trailer( d, pp, cl_opts->ignore_empty ); if( len == min_match_len + 1 ) /* Sync Flush marker */ - { - Rd_load( rdec ); continue; - } + { Rd_load( rdec, true ); continue; } if( verbosity >= 0 ) { Pp_show_msg( pp, 0 ); @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -79,13 +79,16 @@ static inline int Rd_read_data( struct Range_decoder * const rdec, return sz; } -static inline void Rd_load( struct Range_decoder * const rdec ) +static inline bool Rd_load( struct Range_decoder * const rdec, + const bool ignore_marking ) { int i; rdec->code = 0; - for( i = 0; i < 5; ++i ) rdec->code = (rdec->code << 8) | Rd_get_byte( rdec ); rdec->range = 0xFFFFFFFFU; - rdec->code &= rdec->range; /* make sure that first byte is discarded */ + /* check and discard first byte of the LZMA stream */ + if( Rd_get_byte( rdec ) != 0 && !ignore_marking ) return false; + for( i = 0; i < 4; ++i ) rdec->code = (rdec->code << 8) | Rd_get_byte( rdec ); + return true; } static inline void Rd_normalize( struct Range_decoder * const rdec ) @@ -390,4 +393,5 @@ LZd_data_position( const struct LZ_decoder * const d ) { return d->partial_data_pos + d->pos; } int LZd_decode_member( struct LZ_decoder * const d, + const struct Cl_options * const cl_opts, struct Pretty_print * const pp ); diff --git a/doc/lunzip.1 b/doc/lunzip.1 index 9aa0300..3b9fb99 100644 --- a/doc/lunzip.1 +++ b/doc/lunzip.1 @@ -1,5 +1,5 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. -.TH LUNZIP "1" "January 2022" "lunzip 1.13" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. +.TH LUNZIP "1" "December 2023" "lunzip 1.14-rc1" "User Commands" .SH NAME lunzip \- decompressor for the lzip format .SH SYNOPSIS @@ -62,6 +62,12 @@ set output buffer size in bytes \fB\-v\fR, \fB\-\-verbose\fR be verbose (a 2nd \fB\-v\fR gives more) .TP +\fB\-\-empty\-error\fR +exit with error status if empty member in file +.TP +\fB\-\-marking\-error\fR +exit with error status if 1st LZMA byte not 0 +.TP \fB\-\-loose\-trailing\fR allow trailing data seeming corrupt header .PP @@ -69,19 +75,19 @@ If no file names are given, or if a file is '\-', lunzip decompresses from standard input to standard output. Numbers may be followed by a multiplier: k = kB = 10^3 = 1000, Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc... -Buffer sizes 12 to 29 are interpreted as powers of two, meaning 2^12 -to 2^29 bytes. +Buffer sizes 12 to 29 are interpreted as powers of two, meaning 2^12 to +2^29 bytes. .PP To extract all the files from archive 'foo.tar.lz', use the commands \&'tar \fB\-xf\fR foo.tar.lz' or 'lunzip \fB\-cd\fR foo.tar.lz | tar \fB\-xf\fR \-'. .PP -Exit status: 0 for a normal exit, 1 for environmental problems (file -not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or -invalid input file, 3 for an internal consistency error (e.g., bug) which -caused lunzip to panic. +Exit status: 0 for a normal exit, 1 for environmental problems +(file not found, invalid command\-line options, I/O errors, etc), 2 to +indicate a corrupt or invalid input file, 3 for an internal consistency +error (e.g., bug) which caused lunzip to panic. .PP The ideas embodied in lunzip are due to (at least) the following people: -Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the +Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the definition of Markov chains), G.N.N. Martin (for the definition of range encoding), Igor Pavlov (for putting all the above together in LZMA), and Julian Seward (for bzip2's CLI). @@ -90,7 +96,7 @@ Report bugs to lzip\-bug@nongnu.org .br Lunzip home page: http://www.nongnu.org/lzip/lunzip.html .SH COPYRIGHT -Copyright \(co 2022 Antonio Diaz Diaz. +Copyright \(co 2023 Antonio Diaz Diaz. License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> .br This is free software: you are free to change and redistribute it. @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,13 +43,14 @@ static void list_line( const unsigned long long uncomp_size, int list_files( const char * const filenames[], const int num_filenames, - const bool ignore_trailing, const bool loose_trailing ) + const struct Cl_options * const cl_opts ) { unsigned long long total_comp = 0, total_uncomp = 0; int files = 0, retval = 0; int i; bool first_post = true; bool stdin_used = false; + for( i = 0; i < num_filenames; ++i ) { const bool from_stdin = ( strcmp( filenames[i], "-" ) == 0 ); @@ -61,7 +62,7 @@ int list_files( const char * const filenames[], const int num_filenames, if( infd < 0 ) { set_retval( &retval, 1 ); continue; } struct Lzip_index lzip_index; - Li_init( &lzip_index, infd, ignore_trailing, loose_trailing ); + Li_init( &lzip_index, infd, cl_opts ); close( infd ); if( lzip_index.retval != 0 ) { @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ typedef int State; enum { states = 12 }; - static inline bool St_is_char( const State st ) { return st < 7; } static inline State St_set_char( const State st ) @@ -33,15 +32,12 @@ static inline State St_set_char( const State st ) static const State next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; return next[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 ) - { return ( ( st < 7 ) ? 8 : 11 ); } - + { return ( st < 7 ) ? 8 : 11; } static inline State St_set_short_rep( const State st ) - { return ( ( st < 7 ) ? 9 : 11 ); } + { return ( st < 7 ) ? 9 : 11; } enum { @@ -60,7 +56,7 @@ enum { dis_slot_bits = 6, start_dis_model = 4, end_dis_model = 14, - modeled_distances = 1 << (end_dis_model / 2), /* 128 */ + modeled_distances = 1 << ( end_dis_model / 2 ), /* 128 */ dis_align_bits = 4, dis_align_size = 1 << dis_align_bits, @@ -145,63 +141,63 @@ static inline void CRC32_update_buf( uint32_t * const crc, static inline bool isvalid_ds( const unsigned dictionary_size ) - { return ( dictionary_size >= min_dictionary_size && - dictionary_size <= max_dictionary_size ); } + { return dictionary_size >= min_dictionary_size && + dictionary_size <= max_dictionary_size; } 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 */ /* 5 coded dictionary size */ -enum { Lh_size = 6 }; -static inline bool Lh_verify_magic( const Lzip_header data ) - { return ( memcmp( data, lzip_magic, 4 ) == 0 ); } +static inline bool Lh_check_magic( const Lzip_header data ) + { return memcmp( data, lzip_magic, 4 ) == 0; } /* 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; for( i = 0; i < sz && i < 4; ++i ) if( data[i] != lzip_magic[i] ) return false; - return ( sz > 0 ); + return sz > 0; } /* 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 i; for( i = 0; i < 4; ++i ) if( data[i] == lzip_magic[i] ) ++matches; - return ( matches > 1 && matches < 4 ); + return matches > 1 && matches < 4; } static inline uint8_t Lh_version( const Lzip_header data ) { return data[4]; } -static inline bool Lh_verify_version( const Lzip_header data ) - { return ( data[4] == 1 ); } +static inline bool Lh_check_version( const Lzip_header data ) + { return data[4] == 1; } 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 ) sz -= ( sz / 16 ) * ( ( data[5] >> 5 ) & 7 ); return sz; } -static inline bool Lh_verify( const Lzip_header data ) +static inline bool Lh_check( const Lzip_header data ) { - return Lh_verify_magic( data ) && Lh_verify_version( data ) && + return Lh_check_magic( data ) && Lh_check_version( data ) && isvalid_ds( Lh_get_dictionary_size( 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 */ /* 4-11 size of the uncompressed data */ /* 12-19 member size including header and trailer */ -enum { Lt_size = 20 }; static inline unsigned Lt_get_data_crc( const Lzip_trailer data ) { @@ -225,7 +221,7 @@ static inline unsigned long long Lt_get_member_size( const Lzip_trailer data ) } /* check internal consistency */ -static inline bool Lt_verify_consistency( const Lzip_trailer data ) +static inline bool Lt_check_consistency( const Lzip_trailer data ) { const unsigned crc = Lt_get_data_crc( data ); const unsigned long long dsize = Lt_get_data_size( data ); @@ -240,12 +236,27 @@ static inline bool Lt_verify_consistency( const Lzip_trailer data ) } +struct Cl_options /* command-line options */ + { + bool ignore_empty; + bool ignore_marking; + bool ignore_trailing; + bool loose_trailing; + }; + +static inline void Cl_options_init( struct Cl_options * cl_opts ) + { cl_opts->ignore_empty = true; cl_opts->ignore_marking = true; + cl_opts->ignore_trailing = true; cl_opts->loose_trailing = false; } + + static inline void set_retval( int * retval, const int new_val ) { if( *retval < new_val ) *retval = new_val; } static const char * const bad_magic_msg = "Bad magic number (file not in lzip format)."; static const char * const bad_dict_msg = "Invalid dictionary size in member header."; static const char * const corrupt_mm_msg = "Corrupt header in multimember file."; +static const char * const empty_msg = "Empty member not allowed."; +static const char * const marking_msg = "Marking data not allowed."; static const char * const trailing_msg = "Trailing data not allowed."; static const char * const mem_msg = "Not enough memory."; @@ -254,7 +265,7 @@ int readblock( const int fd, uint8_t * const buf, const int size ); /* defined in list.c */ int list_files( const char * const filenames[], const int num_filenames, - const bool ignore_trailing, const bool loose_trailing ); + const struct Cl_options * const cl_opts ); /* defined in main.c */ struct stat; diff --git a/lzip_index.c b/lzip_index.c index 559fd7a..688a370 100644 --- a/lzip_index.c +++ b/lzip_index.c @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -88,17 +88,17 @@ static void Li_reverse_member_vector( struct Lzip_index * const li ) } -static bool Li_check_header_error( struct Lzip_index * const li, - const Lzip_header header ) +static bool Li_check_header( struct Lzip_index * const li, + const Lzip_header header ) { - if( !Lh_verify_magic( header ) ) - { add_error( li, bad_magic_msg ); li->retval = 2; return true; } - if( !Lh_verify_version( header ) ) + if( !Lh_check_magic( header ) ) + { add_error( li, bad_magic_msg ); li->retval = 2; return false; } + if( !Lh_check_version( header ) ) { add_error( li, bad_version( Lh_version( header ) ) ); li->retval = 2; - return true; } + return false; } if( !isvalid_ds( Lh_get_dictionary_size( header ) ) ) - { add_error( li, bad_dict_msg ); li->retval = 2; return true; } - return false; + { add_error( li, bad_dict_msg ); li->retval = 2; return false; } + return true; } static void Li_set_errno_error( struct Lzip_index * const li, @@ -119,10 +119,13 @@ static void Li_set_num_error( struct Lzip_index * const li, static bool Li_read_header( struct Lzip_index * const li, const int fd, - Lzip_header header, const long long pos ) + Lzip_header header, const long long pos, const bool ignore_marking ) { if( seek_read( fd, header, Lh_size, pos ) != Lh_size ) { Li_set_errno_error( li, "Error reading member header: " ); return false; } + uint8_t byte; + if( !ignore_marking && readblock( fd, &byte, 1 ) == 1 && byte != 0 ) + { add_error( li, marking_msg ); li->retval = 2; return false; } return true; } @@ -130,8 +133,7 @@ static bool Li_read_header( struct Lzip_index * const li, const int fd, /* If successful, push last member and set pos to member header. */ static bool Li_skip_trailing_data( struct Lzip_index * const li, const int fd, unsigned long long * const pos, - const bool ignore_trailing, - const bool loose_trailing ) + const struct Cl_options * const cl_opts ) { if( *pos < min_member_size ) return false; enum { block_size = 16384, @@ -157,31 +159,34 @@ static bool Li_skip_trailing_data( struct Lzip_index * const li, const int fd, const unsigned long long member_size = Lt_get_member_size( *trailer ); if( member_size == 0 ) /* skip trailing zeros */ { while( i > Lt_size && buffer[i-9] == 0 ) --i; continue; } - if( member_size > ipos + i || !Lt_verify_consistency( *trailer ) ) + if( member_size > ipos + i || !Lt_check_consistency( *trailer ) ) continue; Lzip_header header; - if( !Li_read_header( li, fd, header, ipos + i - member_size ) ) - return false; - if( !Lh_verify( header ) ) continue; + if( !Li_read_header( li, fd, header, ipos + i - member_size, + cl_opts->ignore_marking ) ) return false; + if( !Lh_check( header ) ) continue; const Lzip_header * header2 = (const Lzip_header *)( buffer + i ); const bool full_h2 = bsize - i >= Lh_size; - if( Lh_verify_prefix( *header2, bsize - i ) ) /* last member */ + if( Lh_check_prefix( *header2, bsize - i ) ) /* last member */ { if( !full_h2 ) add_error( li, "Last member in input file is truncated." ); - else if( !Li_check_header_error( li, *header2 ) ) + else if( Li_check_header( li, *header2 ) ) add_error( li, "Last member in input file is truncated or corrupt." ); li->retval = 2; return false; } - if( !loose_trailing && full_h2 && Lh_verify_corrupt( *header2 ) ) + if( !cl_opts->loose_trailing && full_h2 && Lh_check_corrupt( *header2 ) ) { add_error( li, corrupt_mm_msg ); li->retval = 2; return false; } - if( !ignore_trailing ) + if( !cl_opts->ignore_trailing ) { add_error( li, trailing_msg ); li->retval = 2; return false; } - *pos = ipos + i - member_size; + const unsigned long long data_size = Lt_get_data_size( *trailer ); + if( !cl_opts->ignore_empty && data_size == 0 ) + { add_error( li, empty_msg ); li->retval = 2; return false; } + *pos = ipos + i - member_size; /* good member */ const unsigned dictionary_size = Lh_get_dictionary_size( header ); if( li->dictionary_size < dictionary_size ) li->dictionary_size = dictionary_size; - return push_back_member( li, 0, Lt_get_data_size( *trailer ), *pos, - member_size, dictionary_size ); + return push_back_member( li, 0, data_size, *pos, member_size, + dictionary_size ); } if( ipos == 0 ) { Li_set_num_error( li, "Bad trailer at pos ", *pos - Lt_size ); @@ -196,7 +201,7 @@ static bool Li_skip_trailing_data( struct Lzip_index * const li, const int fd, bool Li_init( struct Lzip_index * const li, const int infd, - const bool ignore_trailing, const bool loose_trailing ) + const struct Cl_options * const cl_opts ) { li->member_vector = 0; li->error = 0; @@ -215,8 +220,8 @@ bool Li_init( struct Lzip_index * const li, const int infd, li->retval = 2; return false; } Lzip_header header; - if( !Li_read_header( li, infd, header, 0 ) ) return false; - if( Li_check_header_error( li, header ) ) return false; + if( !Li_read_header( li, infd, header, 0, cl_opts->ignore_marking ) || + !Li_check_header( li, header ) ) return false; unsigned long long pos = li->insize; /* always points to a header or to EOF */ while( pos >= min_member_size ) @@ -225,32 +230,33 @@ bool Li_init( struct Lzip_index * const li, const int infd, if( seek_read( infd, trailer, Lt_size, pos - Lt_size ) != Lt_size ) { Li_set_errno_error( li, "Error reading member trailer: " ); break; } const unsigned long long member_size = Lt_get_member_size( trailer ); - if( member_size > pos || !Lt_verify_consistency( trailer ) ) + if( member_size > pos || !Lt_check_consistency( trailer ) ) { /* bad trailer */ if( li->members <= 0 ) - { if( Li_skip_trailing_data( li, infd, &pos, ignore_trailing, - loose_trailing ) ) continue; else return false; } - Li_set_num_error( li, "Bad trailer at pos ", pos - Lt_size ); - break; + { if( Li_skip_trailing_data( li, infd, &pos, cl_opts ) ) continue; + return false; } + Li_set_num_error( li, "Bad trailer at pos ", pos - Lt_size ); break; } - if( !Li_read_header( li, infd, header, pos - member_size ) ) break; - if( !Lh_verify( header ) ) /* bad header */ + if( !Li_read_header( li, infd, header, pos - member_size, + cl_opts->ignore_marking ) ) break; + if( !Lh_check( header ) ) /* bad header */ { if( li->members <= 0 ) - { if( Li_skip_trailing_data( li, infd, &pos, ignore_trailing, - loose_trailing ) ) continue; else return false; } - Li_set_num_error( li, "Bad header at pos ", pos - member_size ); - break; + { if( Li_skip_trailing_data( li, infd, &pos, cl_opts ) ) continue; + return false; } + Li_set_num_error( li, "Bad header at pos ", pos - member_size ); break; } - pos -= member_size; + const unsigned long long data_size = Lt_get_data_size( trailer ); + if( !cl_opts->ignore_empty && data_size == 0 ) + { add_error( li, empty_msg ); li->retval = 2; break; } + pos -= member_size; /* good member */ const unsigned dictionary_size = Lh_get_dictionary_size( header ); if( li->dictionary_size < dictionary_size ) li->dictionary_size = dictionary_size; - if( !push_back_member( li, 0, Lt_get_data_size( trailer ), pos, - member_size, dictionary_size ) ) - return false; + if( !push_back_member( li, 0, data_size, pos, member_size, + dictionary_size ) ) return false; } - if( pos != 0 || li->members <= 0 ) + if( pos != 0 || li->members <= 0 || li->retval != 0 ) { Li_free_member_vector( li ); if( li->retval == 0 ) diff --git a/lzip_index.h b/lzip_index.h index 0938533..df2aeca 100644 --- a/lzip_index.h +++ b/lzip_index.h @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,13 +16,13 @@ */ #ifndef INT64_MAX -#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL +#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL #endif struct Block { - long long pos, size; /* pos + size <= INT64_MAX */ + long long pos, size; /* pos >= 0, size >= 0, pos + size <= INT64_MAX */ }; static inline void init_block( struct Block * const b, @@ -40,10 +40,10 @@ struct Member }; static inline void init_member( struct Member * const m, - const long long dp, const long long ds, - const long long mp, const long long ms, + const long long dpos, const long long dsize, + const long long mpos, const long long msize, const unsigned dict_size ) - { init_block( &m->dblock, dp, ds ); init_block( &m->mblock, mp, ms ); + { init_block( &m->dblock, dpos, dsize ); init_block( &m->mblock, mpos, msize ); m->dictionary_size = dict_size; } struct Lzip_index @@ -58,7 +58,7 @@ struct Lzip_index }; bool Li_init( struct Lzip_index * const li, const int infd, - const bool ignore_trailing, const bool loose_trailing ); + const struct Cl_options * const cl_opts ); void Li_free( struct Lzip_index * const li ); @@ -1,5 +1,5 @@ /* Lunzip - Decompressor for the lzip format - Copyright (C) 2010-2022 Antonio Diaz Diaz. + Copyright (C) 2010-2023 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,9 +16,9 @@ */ /* Exit status: 0 for a normal exit, 1 for environmental problems - (file not found, invalid flags, I/O errors, etc), 2 to indicate a - corrupt or invalid input file, 3 for an internal consistency error - (e.g., bug) which caused lunzip to panic. + (file not found, invalid command-line options, I/O errors, etc), 2 to + indicate a corrupt or invalid input file, 3 for an internal consistency + error (e.g., bug) which caused lunzip to panic. */ #define _FILE_OFFSET_BITS 64 @@ -26,10 +26,10 @@ #include <ctype.h> #include <errno.h> #include <fcntl.h> -#include <limits.h> +#include <limits.h> /* SSIZE_MAX */ #include <signal.h> #include <stdbool.h> -#include <stdint.h> +#include <stdint.h> /* SIZE_MAX */ #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -76,7 +76,7 @@ int verbosity = 0; static const char * const program_name = "lunzip"; -static const char * const program_year = "2022"; +static const char * const program_year = "2023"; static const char * invocation_name = "lunzip"; /* default value */ static const struct { const char * from; const char * to; } known_extensions[] = { @@ -124,21 +124,23 @@ static void show_help( void ) " -t, --test test compressed file integrity\n" " -u, --buffer-size=<bytes> set output buffer size in bytes\n" " -v, --verbose be verbose (a 2nd -v gives more)\n" + " --empty-error exit with error status if empty member in file\n" + " --marking-error exit with error status if 1st LZMA byte not 0\n" " --loose-trailing allow trailing data seeming corrupt header\n" "\nIf no file names are given, or if a file is '-', lunzip decompresses\n" "from standard input to standard output.\n" "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" - "Buffer sizes 12 to 29 are interpreted as powers of two, meaning 2^12\n" - "to 2^29 bytes.\n" + "Buffer sizes 12 to 29 are interpreted as powers of two, meaning 2^12 to\n" + "2^29 bytes.\n" "\nTo extract all the files from archive 'foo.tar.lz', use the commands\n" "'tar -xf foo.tar.lz' or 'lunzip -cd foo.tar.lz | tar -xf -'.\n" - "\nExit status: 0 for a normal exit, 1 for environmental problems (file\n" - "not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n" - "invalid input file, 3 for an internal consistency error (e.g., bug) which\n" - "caused lunzip to panic.\n" + "\nExit status: 0 for a normal exit, 1 for environmental problems\n" + "(file not found, invalid command-line options, I/O errors, etc), 2 to\n" + "indicate a corrupt or invalid input file, 3 for an internal consistency\n" + "error (e.g., bug) which caused lunzip to panic.\n" "\nThe ideas embodied in lunzip are due to (at least) the following people:\n" - "Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the\n" + "Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the\n" "definition of Markov chains), G.N.N. Martin (for the definition of range\n" "encoding), Igor Pavlov (for putting all the above together in LZMA), and\n" "Julian Seward (for bzip2's CLI).\n" @@ -243,16 +245,15 @@ const char * bad_version( const unsigned version ) const char * format_ds( const unsigned dictionary_size ) { - enum { bufsize = 16, factor = 1024 }; + enum { bufsize = 16, factor = 1024, n = 3 }; static char buf[bufsize]; - const char * const prefix[8] = - { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; + const char * const prefix[n] = { "Ki", "Mi", "Gi" }; const char * p = ""; const char * np = " "; unsigned num = dictionary_size; bool exact = ( num % factor == 0 ); - int i; for( i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i ) + int i; for( i = 0; i < n && ( num > 9999 || ( exact && num >= factor ) ); ++i ) { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; np = ""; } snprintf( buf, bufsize, "%s%4u %sB", np, num, p ); @@ -266,12 +267,12 @@ void show_header( const unsigned dictionary_size ) } -/* separate large numbers >= 100_000 in groups of 3 digits using '_' */ +/* separate numbers of 5 or more digits in groups of 3 digits using '_' */ static const char * format_num3( unsigned long long num ) { - const char * const si_prefix = "kMGTPEZY"; - const char * const binary_prefix = "KMGTPEZY"; - enum { buffers = 8, bufsize = 4 * sizeof (long long) }; + 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; @@ -281,15 +282,15 @@ static const char * format_num3( unsigned long long num ) if( num > 1024 ) { char prefix = 0; /* try binary first, then si */ - for( i = 0; i < 8 && num >= 1024 && num % 1024 == 0; ++i ) + 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 < 8 && num >= 1000 && num % 1000 == 0; ++i ) + 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 >= 100000; + const bool split = num >= 10000; for( i = 0; ; ) { @@ -300,6 +301,16 @@ static const char * format_num3( unsigned long long num ) } +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, @@ -307,14 +318,10 @@ static unsigned long getnum( const char * const arg, { char * tail; errno = 0; - unsigned long long result = strtoul( arg, &tail, 0 ); + unsigned long result = strtoul( arg, &tail, 0 ); if( tail == arg ) - { - if( verbosity >= 0 ) - fprintf( stderr, "%s: Bad or missing numerical argument in " - "option '%s'.\n", program_name, option_name ); - exit( 1 ); - } + { show_option_error( arg, "Bad or missing numerical argument in", + option_name ); exit( 1 ); } if( !errno && tail[0] ) { @@ -323,6 +330,8 @@ static unsigned long getnum( const char * const arg, int i; switch( tail[0] ) { + case 'Q': exponent = 10; break; + case 'R': exponent = 9; break; case 'Y': exponent = 8; break; case 'Z': exponent = 7; break; case 'E': exponent = 6; break; @@ -334,12 +343,8 @@ static unsigned long getnum( const char * const arg, case 'k': if( factor == 1000 ) exponent = 1; break; } if( exponent <= 0 ) - { - if( verbosity >= 0 ) - fprintf( stderr, "%s: Bad multiplier in numerical argument of " - "option '%s'.\n", program_name, option_name ); - exit( 1 ); - } + { show_option_error( arg, "Bad multiplier in numerical argument of", + option_name ); exit( 1 ); } for( i = 0; i < exponent; ++i ) { if( ulimit / factor >= result ) result *= factor; @@ -350,8 +355,8 @@ static unsigned long getnum( const char * const arg, if( errno ) { if( verbosity >= 0 ) - fprintf( stderr, "%s: Numerical argument out of limits [%s,%s] " - "in option '%s'.\n", program_name, format_num3( llimit ), + 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 ); } @@ -417,7 +422,7 @@ static void set_d_outname( const char * const name, const int eindex ) strcpy( output_filename, name ); strcat( output_filename, ".out" ); 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 ); } @@ -438,9 +443,9 @@ int open_instream( const char * const name, struct stat * const in_statsp, if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) ) { if( verbosity >= 0 ) - fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n", + fprintf( stderr, "%s: %s: Input file is not a regular file%s.\n", 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 ); infd = -1; } @@ -449,6 +454,33 @@ int open_instream( const char * const name, struct stat * const in_statsp, } +static bool make_dirs( const char * const name ) + { + int i = strlen( name ); + while( i > 0 && name[i-1] != '/' ) --i; /* remove last component */ + while( i > 0 && name[i-1] == '/' ) --i; /* remove slash(es) */ + const int dirsize = i; /* size of dirname without trailing slash(es) */ + + for( i = 0; i < dirsize; ) /* if dirsize == 0, dirname is '/' or empty */ + { + while( i < dirsize && name[i] == '/' ) ++i; + const int first = i; + while( i < dirsize && name[i] != '/' ) ++i; + if( first < i ) + { + char partial[i+1]; memcpy( partial, name, i ); partial[i] = 0; + const mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + struct stat st; + if( stat( partial, &st ) == 0 ) + { if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } } + else if( mkdir( partial, mode ) != 0 && errno != EEXIST ) + return false; /* if EEXIST, another process created the dir */ + } + } + return true; + } + + static bool open_outstream( const bool force, const bool protect ) { const mode_t usr_rw = S_IRUSR | S_IWUSR; @@ -457,18 +489,21 @@ static bool open_outstream( const bool force, const bool protect ) int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY; if( force ) flags |= O_TRUNC; else flags |= O_EXCL; - outfd = open( output_filename, flags, outfd_mode ); - if( outfd >= 0 ) delete_output_on_interrupt = true; - else if( verbosity >= 0 ) - { + outfd = -1; + const int len = strlen( output_filename ); + if( len > 0 && output_filename[len-1] == '/' ) errno = EISDIR; + else { + if( !protect && !make_dirs( output_filename ) ) + { show_file_error( output_filename, + "Error creating intermediate directory", errno ); return false; } + outfd = open( output_filename, flags, outfd_mode ); + if( outfd >= 0 ) { delete_output_on_interrupt = true; return true; } if( errno == EEXIST ) - fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n", - program_name, output_filename ); - else - fprintf( stderr, "%s: Can't create output file '%s': %s\n", - program_name, output_filename, strerror( errno ) ); + { show_file_error( output_filename, + "Output file already exists, skipping.", 0 ); return false; } } - return ( outfd >= 0 ); + show_file_error( output_filename, "Can't create output file", errno ); + return false; } @@ -486,12 +521,10 @@ void cleanup_and_fail( const int retval ) if( delete_output_on_interrupt ) { delete_output_on_interrupt = false; - if( verbosity >= 0 ) - fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n", - program_name, output_filename ); + show_file_error( output_filename, "Deleting output file, if it exists.", 0 ); if( outfd >= 0 ) { close( outfd ); outfd = -1; } 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 ); } @@ -534,10 +567,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp ) warning = true; } if( close( outfd ) != 0 ) - { - show_error( "Error closing output file", errno, false ); - cleanup_and_fail( 1 ); - } + { show_file_error( output_filename, "Error closing output file", errno ); + cleanup_and_fail( 1 ); } outfd = -1; delete_output_on_interrupt = false; if( in_statsp ) @@ -548,11 +579,12 @@ static void close_and_set_permissions( const struct stat * const in_statsp ) if( utime( output_filename, &t ) != 0 ) warning = true; } 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 ); } -static unsigned char xdigit( const unsigned value ) +static unsigned char xdigit( const unsigned value ) /* hex digit for 'value' */ { if( value <= 9 ) return '0' + value; if( value <= 15 ) return 'A' + value - 10; @@ -584,14 +616,14 @@ static bool show_trailing_data( const uint8_t * const data, const int size, Pp_show_msg( pp, buf ); if( ignore_trailing == 0 ) show_file_error( pp->name, trailing_msg, 0 ); } - return ( ignore_trailing > 0 ); + return ignore_trailing > 0; } static int decompress( const unsigned long long cfile_size, const int infd, - struct Pretty_print * const pp, const unsigned buffer_size, - const bool ignore_trailing, const bool loose_trailing, - const bool testing ) + const struct Cl_options * const cl_opts, + struct Pretty_print * const pp, + const unsigned buffer_size, const bool testing ) { unsigned long long partial_file_pos = 0; struct Range_decoder rdec; @@ -610,28 +642,25 @@ static int decompress( const unsigned long long cfile_size, const int infd, if( first_member ) { show_file_error( pp->name, "File ends unexpectedly at member header.", 0 ); retval = 2; } - else if( Lh_verify_prefix( header, size ) ) + else if( Lh_check_prefix( header, size ) ) { Pp_show_msg( pp, "Truncated header in multimember file." ); - show_trailing_data( header, size, pp, true, -1 ); - retval = 2; } - else if( size > 0 && !show_trailing_data( header, size, pp, - true, ignore_trailing ) ) - retval = 2; + show_trailing_data( header, size, pp, true, -1 ); retval = 2; } + else if( size > 0 && !show_trailing_data( header, size, pp, true, + cl_opts->ignore_trailing ) ) retval = 2; break; } - if( !Lh_verify_magic( header ) ) + if( !Lh_check_magic( header ) ) { if( first_member ) { show_file_error( pp->name, bad_magic_msg, 0 ); retval = 2; } - else if( !loose_trailing && Lh_verify_corrupt( header ) ) + else if( !cl_opts->loose_trailing && Lh_check_corrupt( header ) ) { Pp_show_msg( pp, corrupt_mm_msg ); - show_trailing_data( header, size, pp, false, -1 ); - retval = 2; } - else if( !show_trailing_data( header, size, pp, false, ignore_trailing ) ) - retval = 2; + show_trailing_data( header, size, pp, false, -1 ); retval = 2; } + else if( !show_trailing_data( header, size, pp, false, + cl_opts->ignore_trailing ) ) retval = 2; break; } - if( !Lh_verify_version( header ) ) + if( !Lh_check_version( header ) ) { Pp_show_msg( pp, bad_version( Lh_version( header ) ) ); retval = 2; break; } const unsigned dictionary_size = Lh_get_dictionary_size( header ); @@ -648,7 +677,7 @@ static int decompress( const unsigned long long cfile_size, const int infd, retval = 1; break; } show_dprogress( cfile_size, partial_file_pos, &rdec, pp ); /* init */ - const int result = LZd_decode_member( &decoder, pp ); + const int result = LZd_decode_member( &decoder, cl_opts, pp ); partial_file_pos += Rd_member_position( &rdec ); LZd_free( &decoder ); if( result != 0 ) @@ -660,6 +689,8 @@ static int decompress( const unsigned long long cfile_size, const int infd, "File ends unexpectedly" : "Decoder error", partial_file_pos ); } + else if( result == 5 ) Pp_show_msg( pp, empty_msg ); + else if( result == 6 ) Pp_show_msg( pp, marking_msg ); retval = 2; break; } if( verbosity >= 2 ) @@ -740,32 +771,34 @@ int main( const int argc, const char * const argv[] ) unsigned buffer_size = max_dictionary_size; enum Mode program_mode = m_compress; int i; + struct Cl_options cl_opts; /* command-line options */ + Cl_options_init( &cl_opts ); bool force = false; - bool ignore_trailing = true; bool keep_input_files = false; - bool loose_trailing = false; bool to_stdout = false; if( argc > 0 ) invocation_name = argv[0]; - enum { opt_lt = 256 }; + enum { opt_eer = 256, opt_lt, opt_mer }; const struct ap_Option options[] = { - { 'a', "trailing-error", ap_no }, - { 'c', "stdout", ap_no }, - { 'd', "decompress", ap_no }, - { 'f', "force", ap_no }, - { 'h', "help", ap_no }, - { 'k', "keep", ap_no }, - { 'l', "list", ap_no }, - { 'n', "threads", ap_yes }, - { 'o', "output", ap_yes }, - { 'q', "quiet", ap_no }, - { 't', "test", ap_no }, - { 'u', "buffer-size", ap_yes }, - { 'v', "verbose", ap_no }, - { 'V', "version", ap_no }, - { opt_lt, "loose-trailing", ap_no }, - { 0 , 0, ap_no } }; + { 'a', "trailing-error", ap_no }, + { 'c', "stdout", ap_no }, + { 'd', "decompress", ap_no }, + { 'f', "force", ap_no }, + { 'h', "help", ap_no }, + { 'k', "keep", ap_no }, + { 'l', "list", ap_no }, + { 'n', "threads", ap_yes }, + { 'o', "output", ap_yes }, + { 'q', "quiet", ap_no }, + { 't', "test", ap_no }, + { 'u', "buffer-size", ap_yes }, + { 'v', "verbose", ap_no }, + { 'V', "version", ap_no }, + { opt_eer, "empty-error", ap_no }, + { opt_lt, "loose-trailing", ap_no }, + { opt_mer, "marking-error", ap_no }, + { 0, 0, ap_no } }; CRC32_init(); @@ -785,7 +818,7 @@ int main( const int argc, const char * const argv[] ) const char * const arg = ap_argument( &parser, argind ); switch( code ) { - case 'a': ignore_trailing = false; break; + case 'a': cl_opts.ignore_trailing = false; break; case 'c': to_stdout = true; break; case 'd': set_mode( &program_mode, m_decompress ); break; case 'f': force = true; break; @@ -800,8 +833,10 @@ int main( const int argc, const char * const argv[] ) case 'u': buffer_size = get_dict_size( arg, pn ); break; case 'v': if( verbosity < 4 ) ++verbosity; break; case 'V': show_version(); return 0; - case opt_lt: loose_trailing = true; break; - default : internal_error( "uncaught option." ); + case opt_eer: cl_opts.ignore_empty = false; break; + case opt_lt: cl_opts.loose_trailing = true; break; + case opt_mer: cl_opts.ignore_marking = false; break; + default: internal_error( "uncaught option." ); } } /* end process options */ @@ -823,7 +858,7 @@ int main( const int argc, const char * const argv[] ) } if( program_mode == m_list ) - return list_files( filenames, num_filenames, ignore_trailing, loose_trailing ); + return list_files( filenames, num_filenames, &cl_opts ); if( program_mode == m_compress ) program_mode = m_decompress; /* default mode */ @@ -881,7 +916,7 @@ int main( const int argc, const char * const argv[] ) infd = open_instream( input_filename, &in_stats, one_to_one, false ); if( infd < 0 ) { set_retval( &retval, 1 ); continue; } if( !check_tty_in( pp.name, infd, program_mode, &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 ) ); if( !open_outstream( force, true ) ) @@ -889,7 +924,7 @@ int main( const int argc, const char * const argv[] ) } } - 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, strlen( default_output_filename ) + 1 ); @@ -903,8 +938,8 @@ int main( const int argc, const char * const argv[] ) if( fstat( outfd, &st ) != 0 || !S_ISREG( st.st_mode ) ) { if( verbosity >= 0 ) - fprintf( stderr, "%s: Output file '%s' is not a regular file,\n" - " and 'low memory' mode has been requested.\n", + fprintf( stderr, "%s: %s: Output file is not a regular file,\n" + " and 'low memory' mode has been requested.\n", program_name, output_filename ); set_retval( &retval, 1 ); return retval; /* don't try to delete a non-regular file */ @@ -916,8 +951,8 @@ int main( const int argc, const char * const argv[] ) const unsigned long long cfile_size = ( input_filename[0] && S_ISREG( in_stats.st_mode ) ) ? ( in_stats.st_size + 99 ) / 100 : 0; - int tmp = decompress( cfile_size, infd, &pp, buffer_size, ignore_trailing, - loose_trailing, program_mode == m_test ); + int tmp = decompress( cfile_size, infd, &cl_opts, &pp, buffer_size, + program_mode == m_test ); if( close( infd ) != 0 ) { show_file_error( pp.name, "Error closing input file", errno ); set_retval( &tmp, 1 ); } diff --git a/testsuite/check.sh b/testsuite/check.sh index c495ba1..16682a7 100755 --- a/testsuite/check.sh +++ b/testsuite/check.sh @@ -1,6 +1,6 @@ #! /bin/sh # check script for Lunzip - Decompressor for the lzip format -# Copyright (C) 2010-2022 Antonio Diaz Diaz. +# Copyright (C) 2010-2023 Antonio Diaz Diaz. # # This script is free software: you have unlimited permission # to copy, distribute, and modify it. @@ -32,6 +32,8 @@ cat "${testdir}"/test.txt > in || framework_failure in_lz="${testdir}"/test.txt.lz in_em="${testdir}"/test_em.txt.lz fox_lz="${testdir}"/fox.lz +fox6_lz="${testdir}"/fox6.lz +f6mk_lz="${testdir}"/fox6_mark.lz fail=0 test_failed() { fail=1 ; printf " $1" ; [ -z "$2" ] || printf "($2)" ; } @@ -64,9 +66,9 @@ rm -f uin.lz || framework_failure # these are for code coverage "${LZIP}" -lt "${in_lz}" 2> /dev/null [ $? = 1 ] || test_failed $LINENO -"${LZIP}" -cdl "${in_lz}" > out 2> /dev/null +"${LZIP}" -cdl "${in_lz}" 2> /dev/null [ $? = 1 ] || test_failed $LINENO -"${LZIP}" -cdt "${in_lz}" > out 2> /dev/null +"${LZIP}" -cdt "${in_lz}" 2> /dev/null [ $? = 1 ] || test_failed $LINENO "${LZIP}" -t -- nx_file.lz 2> /dev/null [ $? = 1 ] || test_failed $LINENO @@ -91,50 +93,54 @@ rm -f uin.lz || framework_failure printf "LZIP\001-.............................." | "${LZIP}" -t 2> /dev/null printf "LZIP\002-.............................." | "${LZIP}" -t 2> /dev/null printf "LZIP\001+.............................." | "${LZIP}" -t 2> /dev/null -rm -f out || framework_failure printf "\ntesting decompression..." for i in "${in_lz}" "${in_em}" ; do "${LZIP}" -lq "$i" || test_failed $LINENO "$i" "${LZIP}" -t "$i" || test_failed $LINENO "$i" - "${LZIP}" -d "$i" -o copy || test_failed $LINENO "$i" - cmp in copy || test_failed $LINENO "$i" - "${LZIP}" -cd "$i" > copy || test_failed $LINENO "$i" - cmp in copy || test_failed $LINENO "$i" - "${LZIP}" -d "$i" -o - > copy || test_failed $LINENO "$i" - cmp in copy || test_failed $LINENO "$i" - "${LZIP}" -d < "$i" > copy || test_failed $LINENO "$i" - cmp in copy || test_failed $LINENO "$i" - rm -f copy || framework_failure + "${LZIP}" -d "$i" -o out || test_failed $LINENO "$i" + cmp in out || test_failed $LINENO "$i" + "${LZIP}" -cd "$i" > out || test_failed $LINENO "$i" + cmp in out || test_failed $LINENO "$i" + "${LZIP}" -d "$i" -o - > out || test_failed $LINENO "$i" + cmp in out || test_failed $LINENO "$i" + "${LZIP}" -d < "$i" > out || test_failed $LINENO "$i" + cmp in out || test_failed $LINENO "$i" + rm -f out || framework_failure done -lines=$("${LZIP}" -tvv "${in_em}" 2>&1 | wc -l) || test_failed $LINENO +lines=`"${LZIP}" -tvv "${in_em}" 2>&1 | wc -l` || test_failed $LINENO [ "${lines}" -eq 8 ] || test_failed $LINENO "${lines}" +"${LZIP}" -tq "${in_em}" --empty-error +[ $? = 2 ] || test_failed $LINENO -lines=$("${LZIP}" -lvv "${in_em}" | wc -l) || test_failed $LINENO +lines=`"${LZIP}" -lvv "${in_em}" | wc -l` || test_failed $LINENO [ "${lines}" -eq 11 ] || test_failed $LINENO "${lines}" +"${LZIP}" -lq "${in_em}" --empty-error +[ $? = 2 ] || test_failed $LINENO -"${LZIP}" -cd "${fox_lz}" > fox || test_failed $LINENO -cat "${in_lz}" > copy.lz || framework_failure -"${LZIP}" -dk copy.lz || test_failed $LINENO -cmp in copy || test_failed $LINENO -cat fox > copy || framework_failure 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 "${LZIP}" -d copy.lz out.lz 2> /dev/null # skip copy, decompress out [ $? = 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 [ ! -e copy.lz ] || test_failed $LINENO cmp in copy || test_failed $LINENO -rm -f out || framework_failure +rm -f copy out || framework_failure -printf "to be overwritten" > copy || framework_failure -"${LZIP}" -df -o copy < "${in_lz}" || test_failed $LINENO -cmp in copy || test_failed $LINENO -rm -f out copy || framework_failure +printf "to be overwritten" > out || framework_failure +"${LZIP}" -df -o out < "${in_lz}" || test_failed $LINENO +cmp in out || test_failed $LINENO +rm -f out || framework_failure "${LZIP}" -d -o ./- "${in_lz}" || test_failed $LINENO cmp in ./- || test_failed $LINENO rm -f ./- || framework_failure @@ -143,11 +149,11 @@ cmp in ./- || test_failed $LINENO rm -f ./- || 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 -cmp in copy || test_failed $LINENO +cmp in 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}" -lq in "${in_lz}" [ $? = 2 ] || test_failed $LINENO @@ -157,87 +163,107 @@ rm -f copy anyothername.out || framework_failure [ $? = 2 ] || test_failed $LINENO "${LZIP}" -tq nx_file.lz "${in_lz}" [ $? = 1 ] || test_failed $LINENO -"${LZIP}" -cdq in "${in_lz}" > copy +"${LZIP}" -cdq in "${in_lz}" > out [ $? = 2 ] || test_failed $LINENO -cat copy in | cmp in - || test_failed $LINENO # copy must be empty -"${LZIP}" -cdq nx_file.lz "${in_lz}" > copy +cat out in | cmp in - || test_failed $LINENO # out must be empty +"${LZIP}" -cdq nx_file.lz "${in_lz}" > out # skip nx_file, decompress in [ $? = 1 ] || test_failed $LINENO -cmp in copy || test_failed $LINENO -rm -f copy || framework_failure -cat "${in_lz}" > copy.lz || framework_failure +cmp in out || test_failed $LINENO +rm -f out || framework_failure +cat "${in_lz}" > out.lz || framework_failure for i in 1 2 3 4 5 6 7 ; do - printf "g" >> copy.lz || framework_failure - "${LZIP}" -alvv copy.lz "${in_lz}" > /dev/null 2>&1 + printf "g" >> out.lz || framework_failure + "${LZIP}" -alvv out.lz "${in_lz}" > /dev/null 2>&1 [ $? = 2 ] || test_failed $LINENO $i - "${LZIP}" -atvvvv copy.lz "${in_lz}" 2> /dev/null + "${LZIP}" -atvvvv out.lz "${in_lz}" 2> /dev/null [ $? = 2 ] || test_failed $LINENO $i done -"${LZIP}" -dq in copy.lz +"${LZIP}" -dq in out.lz [ $? = 2 ] || test_failed $LINENO -[ -e copy.lz ] || test_failed $LINENO -[ ! -e copy ] || test_failed $LINENO +[ -e out.lz ] || test_failed $LINENO +[ ! -e 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 -[ ! -e copy.lz ] || test_failed $LINENO +[ ! -e out.lz ] || 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 "${LZIP}" -lq "${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 -cmp in2 copy2 || test_failed $LINENO -rm -f copy2 || framework_failure -"${LZIP}" -d "${in_lz}" "${in_lz}" -o copy2 || test_failed $LINENO -cmp in2 copy2 || test_failed $LINENO -rm -f copy2 || framework_failure +cmp in2 out2 || test_failed $LINENO +rm -f out2 || framework_failure +"${LZIP}" -d "${in_lz}" "${in_lz}" -o out2 || test_failed $LINENO +cmp in2 out2 || test_failed $LINENO +rm -f out2 || framework_failure -cat "${in_lz}" "${in_lz}" > copy2.lz || framework_failure -printf "\ngarbage" >> copy2.lz || framework_failure -"${LZIP}" -tvvvv copy2.lz 2> /dev/null || test_failed $LINENO -"${LZIP}" -alq copy2.lz +cat "${in_lz}" "${in_lz}" > out2.lz || framework_failure +printf "\ngarbage" >> out2.lz || framework_failure +"${LZIP}" -tvvvv out2.lz 2> /dev/null || test_failed $LINENO +"${LZIP}" -alq out2.lz [ $? = 2 ] || test_failed $LINENO -"${LZIP}" -atq copy2.lz +"${LZIP}" -atq out2.lz [ $? = 2 ] || test_failed $LINENO -"${LZIP}" -atq < copy2.lz +"${LZIP}" -atq < out2.lz [ $? = 2 ] || test_failed $LINENO -"${LZIP}" -adkq copy2.lz +"${LZIP}" -adkq out2.lz [ $? = 2 ] || test_failed $LINENO -[ ! -e copy2 ] || test_failed $LINENO -"${LZIP}" -adkq -o copy2 < copy2.lz +[ ! -e out2 ] || test_failed $LINENO +"${LZIP}" -adkq -o out2 < out2.lz [ $? = 2 ] || test_failed $LINENO -[ ! -e copy2 ] || test_failed $LINENO -printf "to be overwritten" > copy2 || framework_failure -"${LZIP}" -df copy2.lz || test_failed $LINENO -cmp in2 copy2 || test_failed $LINENO -rm -f copy2 || framework_failure +[ ! -e out2 ] || test_failed $LINENO +printf "to be overwritten" > out2 || framework_failure +"${LZIP}" -df out2.lz || test_failed $LINENO +cmp in2 out2 || test_failed $LINENO +rm -f out2 || framework_failure for i in 12 5120 6Ki 29 512KiB ; do - printf "to be overwritten" > copy || framework_failure - "${LZIP}" -df -u$i -o copy < "${in_lz}" || test_failed $LINENO $i - cmp in copy || test_failed $LINENO $i - rm -f copy || framework_failure - "${LZIP}" -d -u$i -o copy "${in_lz}" || test_failed $LINENO $i - cmp in copy || test_failed $LINENO $i - "${LZIP}" -d -u$i -o copy2 "${in_lz}" "${in_lz}" || + printf "to be overwritten" > out || framework_failure + "${LZIP}" -df -u$i -o out < "${in_lz}" || test_failed $LINENO $i + cmp in out || test_failed $LINENO $i + rm -f out || framework_failure + "${LZIP}" -d -u$i -o out "${in_lz}" || test_failed $LINENO $i + cmp in out || test_failed $LINENO $i + "${LZIP}" -d -u$i -o out2 "${in_lz}" "${in_lz}" || test_failed $LINENO $i - cmp in2 copy2 || test_failed $LINENO $i - rm -f copy2 || framework_failure + cmp in2 out2 || test_failed $LINENO $i + rm -f out2 || framework_failure done -rm -f in2 copy || framework_failure +rm -f in2 out || framework_failure + +"${LZIP}" -cd "${fox6_lz}" > out || test_failed $LINENO +"${LZIP}" -cd "${f6mk_lz}" > copy || test_failed $LINENO +cmp copy out || test_failed $LINENO +rm -f copy out || framework_failure +"${LZIP}" -lq "${f6mk_lz}" --marking-error +[ $? = 2 ] || test_failed $LINENO +"${LZIP}" -tq "${f6mk_lz}" --marking-error +[ $? = 2 ] || test_failed $LINENO + +"${LZIP}" -d "${fox_lz}" -o a/b/c/fox || test_failed $LINENO +cmp fox a/b/c/fox || test_failed $LINENO +rm -rf a || framework_failure +"${LZIP}" -d -o a/b/c/fox < "${fox_lz}" || test_failed $LINENO +cmp fox a/b/c/fox || test_failed $LINENO +rm -rf a || framework_failure +"${LZIP}" -dq "${fox_lz}" -o a/b/c/ +[ $? = 1 ] || test_failed $LINENO +[ ! -e a ] || test_failed $LINENO printf "\ntesting bad input..." 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' -cat "${in_lz}" > int.lz -printf "LZIP${body}" >> int.lz +cat "${in_lz}" > int.lz || framework_failure +printf "LZIP${body}" >> int.lz || framework_failure if "${LZIP}" -tq int.lz ; then for header in ${headers} ; do - printf "${header}${body}" > int.lz # first member - "${LZIP}" -lq int.lz + printf "${header}${body}" > int.lz || framework_failure + "${LZIP}" -lq int.lz # first member [ $? = 2 ] || test_failed $LINENO ${header} "${LZIP}" -tq int.lz [ $? = 2 ] || test_failed $LINENO ${header} @@ -253,9 +279,9 @@ if "${LZIP}" -tq int.lz ; then [ $? = 2 ] || test_failed $LINENO ${header} "${LZIP}" -cdq --loose-trailing int.lz > /dev/null [ $? = 2 ] || test_failed $LINENO ${header} - cat "${in_lz}" > int.lz - printf "${header}${body}" >> int.lz # trailing data - "${LZIP}" -lq int.lz + cat "${in_lz}" > int.lz || framework_failure + printf "${header}${body}" >> int.lz || framework_failure + "${LZIP}" -lq int.lz # trailing data [ $? = 2 ] || test_failed $LINENO ${header} "${LZIP}" -tq int.lz [ $? = 2 ] || test_failed $LINENO ${header} @@ -310,15 +336,15 @@ if dd if=in3.lz of=trunc.lz bs=14752 count=1 2> /dev/null && [ $? = 2 ] || test_failed $LINENO $i "${LZIP}" -tq < trunc.lz [ $? = 2 ] || test_failed $LINENO $i - "${LZIP}" -cdq trunc.lz > out + "${LZIP}" -cdq trunc.lz > /dev/null [ $? = 2 ] || test_failed $LINENO $i - "${LZIP}" -dq < trunc.lz > out + "${LZIP}" -dq < trunc.lz > /dev/null [ $? = 2 ] || test_failed $LINENO $i done else printf "\nwarning: skipping truncation test: 'dd' does not work on your system." fi -rm -f in2.lz in3.lz trunc.lz out || framework_failure +rm -f in2.lz in3.lz trunc.lz || framework_failure cat "${in_lz}" > ingin.lz || framework_failure printf "g" >> ingin.lz || framework_failure @@ -329,17 +355,17 @@ cat "${in_lz}" >> ingin.lz || framework_failure [ $? = 2 ] || test_failed $LINENO "${LZIP}" -atq < ingin.lz [ $? = 2 ] || test_failed $LINENO -"${LZIP}" -acdq ingin.lz > out +"${LZIP}" -acdq ingin.lz > /dev/null [ $? = 2 ] || test_failed $LINENO -"${LZIP}" -adq < ingin.lz > out +"${LZIP}" -adq < ingin.lz > /dev/null [ $? = 2 ] || 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 -cmp in copy || test_failed $LINENO -"${LZIP}" -d < ingin.lz > copy || test_failed $LINENO -cmp in copy || test_failed $LINENO -rm -f copy ingin.lz out || framework_failure +"${LZIP}" -cd ingin.lz > out || test_failed $LINENO +cmp in out || test_failed $LINENO +"${LZIP}" -d < ingin.lz > out || test_failed $LINENO +cmp in out || test_failed $LINENO +rm -f out ingin.lz || framework_failure echo if [ ${fail} = 0 ] ; then diff --git a/testsuite/fox6.lz b/testsuite/fox6.lz Binary files differnew file mode 100644 index 0000000..8401b99 --- /dev/null +++ b/testsuite/fox6.lz diff --git a/testsuite/fox6_mark.lz b/testsuite/fox6_mark.lz Binary files differnew file mode 100644 index 0000000..32b2ac0 --- /dev/null +++ b/testsuite/fox6_mark.lz |