Merging upstream version 0.6.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e39d8907e0
commit
f4329ad86e
13 changed files with 378 additions and 275 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2020-06-24 Antonio Diaz Diaz <antonio@gnu.org>
|
||||||
|
|
||||||
|
* Version 0.6 released.
|
||||||
|
* Make '-o' behave like '-c', but writing to file instead of stdout.
|
||||||
|
* in_place.c: Multimember decompression should now work for any file
|
||||||
|
that fits in memory and is smaller than (LONG_MAX - extra_bytes).
|
||||||
|
* README: Add an analysis of the in-place decompression.
|
||||||
|
|
||||||
2020-04-27 Antonio Diaz Diaz <antonio@gnu.org>
|
2020-04-27 Antonio Diaz Diaz <antonio@gnu.org>
|
||||||
|
|
||||||
* Version 0.5 released.
|
* Version 0.5 released.
|
||||||
|
|
6
INSTALL
6
INSTALL
|
@ -1,6 +1,6 @@
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
You will need a C compiler.
|
You will need a C99 compiler. (gcc 2.95 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 4.1.2, 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.
|
||||||
|
@ -41,8 +41,8 @@ the main archive.
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
Or type 'make install-compress', which additionally compresses the
|
Or type 'make install-compress', which additionally compresses the
|
||||||
man page after installation. (Installing compressed docs may become
|
man page after installation.
|
||||||
the default in the future).
|
(Installing compressed docs may become the default in the future).
|
||||||
|
|
||||||
You can install only the program or the man page by typing
|
You can install only the program or the man page by typing
|
||||||
'make install-bin' or 'make install-man' respectively.
|
'make install-bin' or 'make install-man' respectively.
|
||||||
|
|
|
@ -71,7 +71,7 @@ install-info :
|
||||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||||
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
|
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||||
-if $(CAN_RUN_INSTALLINFO) ; then \
|
-if $(CAN_RUN_INSTALLINFO) ; then \
|
||||||
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install-info-compress : install-info
|
install-info-compress : install-info
|
||||||
|
@ -96,7 +96,7 @@ uninstall-bin :
|
||||||
|
|
||||||
uninstall-info :
|
uninstall-info :
|
||||||
-if $(CAN_RUN_INSTALLINFO) ; then \
|
-if $(CAN_RUN_INSTALLINFO) ; then \
|
||||||
install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
||||||
fi
|
fi
|
||||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||||
|
|
||||||
|
|
35
NEWS
35
NEWS
|
@ -1,22 +1,19 @@
|
||||||
Changes in version 0.5:
|
Changes in version 0.6:
|
||||||
|
|
||||||
The lzip_decompress module has been updated to version 5.4.18.
|
Option '-o, --output' now behaves like '-c, --stdout', but sending the
|
||||||
|
output unconditionally to a file instead of to standard output. See the new
|
||||||
|
description of '-o' in the manual. This change is not backwards compatible.
|
||||||
|
Therefore commands like:
|
||||||
|
xlunzip -d -o foo - bar.lz < foo.lz
|
||||||
|
must now be split into:
|
||||||
|
xlunzip -d -o foo - < foo.lz
|
||||||
|
xlunzip -d bar.lz
|
||||||
|
or rewritten as:
|
||||||
|
xlunzip -d - bar.lz < foo.lz > foo
|
||||||
|
|
||||||
Xlunzip now reports an error if a file name is empty (xlunzip -t "").
|
In-place decompression of concatenated files should now work for any
|
||||||
|
combination of files as long as they fit in memory and their total
|
||||||
|
decompressed size is smaller than LONG_MAX minus a small extra space.
|
||||||
|
|
||||||
The words 'decompressed' and 'compressed' have been replaced with the
|
The README file now includes an analysis of the amount of memory required
|
||||||
shorter 'out' and 'in' in the verbose output when decompressing or testing.
|
for in-place decompression.
|
||||||
|
|
||||||
Decompression speed has been slightly increased.
|
|
||||||
|
|
||||||
A compilation error with GCC 10 has been fixed. (Reported by Daniel Baumann).
|
|
||||||
|
|
||||||
The commands needed to extract files from a tar.lz archive have been
|
|
||||||
documented in the output of '--help' and in the man page.
|
|
||||||
|
|
||||||
Xlunzip now compiles on DOS with DJGPP. (Patch from Robert Riebisch).
|
|
||||||
|
|
||||||
The configure script now accepts appending options to CFLAGS using the
|
|
||||||
syntax 'CFLAGS+=OPTIONS'.
|
|
||||||
|
|
||||||
9 new test files have been added to the testsuite.
|
|
||||||
|
|
96
README
96
README
|
@ -1,25 +1,23 @@
|
||||||
Description
|
Description
|
||||||
|
|
||||||
Xlunzip is a test tool for the lzip decompression code of my lzip patch
|
Xlunzip is a test tool for the lzip decompression code of my lzip patch for
|
||||||
for linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress
|
linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux
|
||||||
linux module as a backend. Xlunzip tests the module for stream,
|
module as a backend. Xlunzip tests the module for stream, buffer-to-buffer,
|
||||||
buffer-to-buffer and mixed decompression modes, including in-place
|
and mixed decompression modes, including in-place decompression (using the
|
||||||
decompression (using the same buffer for input and output). You can use
|
same buffer for input and output). You can use xlunzip to verify that the
|
||||||
xlunzip to verify that the module produces correct results when
|
module produces correct results when decompressing single member files,
|
||||||
decompressing single member files, multimember files, or the
|
multimember files, or the concatenation of two or more compressed files.
|
||||||
concatenation of two or more compressed files. Xlunzip can be used with
|
Xlunzip can be used with unzcrash to test the robustness of the module to
|
||||||
unzcrash to test the robustness of the module to the decompression of
|
the decompression of corrupted data.
|
||||||
corrupted data.
|
|
||||||
|
|
||||||
Note that the in-place decompression of concatenated files can't be
|
The distributed index feature of the lzip format allows xlunzip to
|
||||||
guaranteed to work because an arbitrarily low compression ratio of the
|
decompress concatenated files in place. This can't be guaranteed to work
|
||||||
last part of the data can be achieved by appending enough empty
|
with formats like gzip or bzip2 because they can't detect whether a high
|
||||||
compressed members to a file, masking a high compression ratio at the
|
compression ratio in the first members of the multimember data is being
|
||||||
beginning of the data.
|
masked by a low compression ratio in the last members.
|
||||||
|
|
||||||
The xlunzip tarball contains a copy of the lzip_decompress module and
|
The xlunzip tarball contains a copy of the lzip_decompress module and can be
|
||||||
can be compiled and tested without downloading or applying the patch to
|
compiled and tested without downloading or applying the patch to the kernel.
|
||||||
the kernel.
|
|
||||||
|
|
||||||
My lzip patch for linux can be found at
|
My lzip patch for linux can be found at
|
||||||
http://download.savannah.gnu.org/releases/lzip/kernel/
|
http://download.savannah.gnu.org/releases/lzip/kernel/
|
||||||
|
@ -29,14 +27,72 @@ 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
|
stream decompression with fill and flush callback functions. The usage of
|
||||||
of the function is documented in include/linux/lzip.h.
|
the function is documented in include/linux/lzip.h.
|
||||||
|
|
||||||
For decompressing the kernel image, initramfs, and initrd, there is a
|
For decompressing the kernel image, initramfs, and initrd, there is a
|
||||||
wrapper function in lib/decompress_lunzip.c providing the same common
|
wrapper function in lib/decompress_lunzip.c providing the same common
|
||||||
interface as the other decompress_*.c files, which is defined in
|
interface as the other decompress_*.c files, which is defined in
|
||||||
include/linux/decompress/generic.h.
|
include/linux/decompress/generic.h.
|
||||||
|
|
||||||
|
Analysis of the in-place decompression
|
||||||
|
======================================
|
||||||
|
|
||||||
|
In order to decompress the kernel in place (using the same buffer for input
|
||||||
|
and output), the compressed data is placed at the end of the buffer used to
|
||||||
|
hold the decompressed data. The buffer must be large enough to contain after
|
||||||
|
the decompressed data extra space for a marker, a trailer, the maximum
|
||||||
|
possible data expansion, and (if the compressed data consists of more than
|
||||||
|
one member) N-1 empty members.
|
||||||
|
|
||||||
|
|------ compressed data ------|
|
||||||
|
V V
|
||||||
|
|----------------|-------------------|---------|
|
||||||
|
^ ^ extra
|
||||||
|
|-------- decompressed data ---------|
|
||||||
|
|
||||||
|
The input pointer initially points to the beginning of the compressed data
|
||||||
|
and the output pointer initially points to the beginning of the buffer.
|
||||||
|
Decompressing compressible data reduces the distance between the pointers,
|
||||||
|
while decompressing uncompressible data increases the distance. The extra
|
||||||
|
space must be large enough that the output pointer does not overrun the
|
||||||
|
input pointer even if all the overlap between compressed and decompressed
|
||||||
|
data is uncompressible. The worst case is very compressible data followed by
|
||||||
|
uncompressible data because in this case the output pointer increases faster
|
||||||
|
when the input pointer is smaller.
|
||||||
|
|
||||||
|
| * <-- input pointer
|
||||||
|
| * , <-- output pointer
|
||||||
|
| * , '
|
||||||
|
| x ' <-- overrun (x)
|
||||||
|
memory | * ,'
|
||||||
|
address | * ,'
|
||||||
|
|* ,'
|
||||||
|
| ,'
|
||||||
|
| ,'
|
||||||
|
|,'
|
||||||
|
`--------------------------
|
||||||
|
time
|
||||||
|
|
||||||
|
All we need to know to calculate the minimum required extra space is:
|
||||||
|
The maximum expansion ratio.
|
||||||
|
The size of the last part of a member required to verify integrity.
|
||||||
|
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
|
||||||
|
to 1/64 (1.5625%) and adding 36 bytes per input member, the extra space
|
||||||
|
required to decompress lzip data in place is:
|
||||||
|
extra_bytes = ( compressed_size >> 6 ) + members * 36
|
||||||
|
|
||||||
|
Using the compressed size to calculate the extra_bytes (as in the equation
|
||||||
|
above) may slightly overestimate the amount of space required in the worst
|
||||||
|
case. But calculating the extra_bytes from the uncompressed size (as does
|
||||||
|
linux) is wrong (and inefficient for high compression ratios). The formula
|
||||||
|
used in arch/x86/boot/header.S
|
||||||
|
extra_bytes = (uncompressed_size >> 8) + 65536
|
||||||
|
fails with 1 MB of zeros followed by 8 MB of random data, and wastes memory
|
||||||
|
for compression ratios > 4:1.
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/* Arg_parser - POSIX/GNU command line argument parser. (C version)
|
/* Arg_parser - POSIX/GNU command line argument parser. (C version)
|
||||||
Copyright (C) 2006-2020 Antonio Diaz Diaz.
|
Copyright (C) 2006-2020 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
|
||||||
that the following conditions are met:
|
that the following conditions are met:
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
1. Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions, and the following disclaimer.
|
notice, this list of conditions, and the following disclaimer.
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions, and the following disclaimer in the
|
notice, this list of conditions, and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
/* Arg_parser - POSIX/GNU command line argument parser. (C version)
|
/* Arg_parser - POSIX/GNU command line argument parser. (C version)
|
||||||
Copyright (C) 2006-2020 Antonio Diaz Diaz.
|
Copyright (C) 2006-2020 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
|
||||||
that the following conditions are met:
|
that the following conditions are met:
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
1. Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions, and the following disclaimer.
|
notice, this list of conditions, and the following disclaimer.
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions, and the following disclaimer in the
|
notice, this list of conditions, and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Arg_parser reads the arguments in 'argv' and creates a number of
|
/* Arg_parser reads the arguments in 'argv' and creates a number of
|
||||||
option codes, option arguments, and non-option arguments.
|
option codes, option arguments, and non-option arguments.
|
||||||
|
|
||||||
In case of error, 'ap_error' returns a non-null pointer to an error
|
In case of error, 'ap_error' returns a non-null pointer to an error
|
||||||
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 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 option.
|
long-only 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
|
||||||
of parsing, even if the user of your program intermixed option and
|
of parsing, even if the user of your program intermixed option and
|
||||||
non-option arguments. If you want the arguments in the exact order
|
non-option arguments. If you want the arguments in the exact order
|
||||||
the user typed them, call 'ap_init' with 'in_order' = true.
|
the user typed them, call 'ap_init' with 'in_order' = true.
|
||||||
|
|
||||||
The argument '--' terminates all options; any following arguments are
|
The argument '--' terminates all options; any following arguments are
|
||||||
treated as non-option arguments, even if they begin with a hyphen.
|
treated as non-option arguments, even if they begin with a hyphen.
|
||||||
|
|
||||||
The syntax for optional option arguments is '-<short_option><argument>'
|
The syntax for optional option arguments is '-<short_option><argument>'
|
||||||
(without whitespace), or '--<long_option>=<argument>'.
|
(without whitespace), or '--<long_option>=<argument>'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -79,11 +79,11 @@ void ap_free( struct Arg_parser * const ap );
|
||||||
|
|
||||||
const char * ap_error( const struct Arg_parser * const ap );
|
const char * ap_error( const struct Arg_parser * const ap );
|
||||||
|
|
||||||
/* The number of arguments parsed (may be different from argc) */
|
/* The number of arguments parsed. May be different from argc. */
|
||||||
int ap_arguments( const struct Arg_parser * const ap );
|
int ap_arguments( const struct Arg_parser * const ap );
|
||||||
|
|
||||||
/* If ap_code( i ) is 0, ap_argument( i ) is a non-option.
|
/* If ap_code( i ) is 0, ap_argument( i ) is a non-option.
|
||||||
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 );
|
||||||
|
|
||||||
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 );
|
||||||
|
|
11
configure
vendored
11
configure
vendored
|
@ -6,7 +6,7 @@
|
||||||
# to copy, distribute, and modify it.
|
# to copy, distribute, and modify it.
|
||||||
|
|
||||||
pkgname=xlunzip
|
pkgname=xlunzip
|
||||||
pkgversion=0.5
|
pkgversion=0.6
|
||||||
progname=xlunzip
|
progname=xlunzip
|
||||||
srctrigger=doc/${progname}.1
|
srctrigger=doc/${progname}.1
|
||||||
|
|
||||||
|
@ -26,11 +26,7 @@ CFLAGS='-Wall -W -O2'
|
||||||
LDFLAGS=
|
LDFLAGS=
|
||||||
|
|
||||||
# checking whether we are using GNU C.
|
# checking whether we are using GNU C.
|
||||||
/bin/sh -c "${CC} --version" > /dev/null 2>&1 ||
|
/bin/sh -c "${CC} --version" > /dev/null 2>&1 || { CC=cc ; CFLAGS=-O2 ; }
|
||||||
{
|
|
||||||
CC=cc
|
|
||||||
CFLAGS=-O2
|
|
||||||
}
|
|
||||||
|
|
||||||
# Loop over all args
|
# Loop over all args
|
||||||
args=
|
args=
|
||||||
|
@ -42,7 +38,8 @@ while [ $# != 0 ] ; do
|
||||||
shift
|
shift
|
||||||
|
|
||||||
# Add the argument quoted to args
|
# Add the argument quoted to args
|
||||||
args="${args} \"${option}\""
|
if [ -z "${args}" ] ; then args="\"${option}\""
|
||||||
|
else args="${args} \"${option}\"" ; fi
|
||||||
|
|
||||||
# Split out the argument for options that take them
|
# Split out the argument for options that take them
|
||||||
case ${option} in
|
case ${option} in
|
||||||
|
|
|
@ -1,27 +1,26 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
|
||||||
.TH XLUNZIP "1" "April 2020" "xlunzip 0.5" "User Commands"
|
.TH XLUNZIP "1" "June 2020" "xlunzip 0.6" "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
|
||||||
.B xlunzip
|
.B xlunzip
|
||||||
[\fI\,options\/\fR] [\fI\,files\/\fR]
|
[\fI\,options\/\fR] [\fI\,files\/\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Xlunzip is a test tool for the lzip decompression code of my lzip patch
|
Xlunzip is a test tool for the lzip decompression code of my lzip patch for
|
||||||
for linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress
|
linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux
|
||||||
linux module as a backend. Xlunzip tests the module for stream,
|
module as a backend. Xlunzip tests the module for stream, buffer\-to\-buffer,
|
||||||
buffer\-to\-buffer and mixed decompression modes, including in\-place
|
and mixed decompression modes, including in\-place decompression (using the
|
||||||
decompression (using the same buffer for input and output). You can use
|
same buffer for input and output). You can use xlunzip to verify that the
|
||||||
xlunzip to verify that the module produces correct results when
|
module produces correct results when decompressing single member files,
|
||||||
decompressing single member files, multimember files, or the
|
multimember files, or the concatenation of two or more compressed files.
|
||||||
concatenation of two or more compressed files. Xlunzip can be used with
|
Xlunzip can be used with unzcrash to test the robustness of the module to
|
||||||
unzcrash to test the robustness of the module to the decompression of
|
the decompression of corrupted data.
|
||||||
corrupted data.
|
|
||||||
.PP
|
.PP
|
||||||
Note that the in\-place decompression of concatenated files can't be
|
The distributed index feature of the lzip format allows xlunzip to
|
||||||
guaranteed to work because an arbitrarily low compression ratio of the
|
decompress concatenated files in place. This can't be guaranteed to work
|
||||||
last part of the data can be achieved by appending enough empty
|
with formats like gzip or bzip2 because they can't detect whether a high
|
||||||
compressed members to a file, masking a high compression ratio at the
|
compression ratio in the first members of the multimember data is being
|
||||||
beginning of the data.
|
masked by a low compression ratio in the last members.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
@ -46,7 +45,7 @@ decompress or test using only one buffer
|
||||||
keep (don't delete) input files
|
keep (don't delete) input files
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR, \fB\-\-output=\fR<file>
|
\fB\-o\fR, \fB\-\-output=\fR<file>
|
||||||
if reading standard input, write to <file>
|
write to <file>, keep input files
|
||||||
.TP
|
.TP
|
||||||
\fB\-q\fR, \fB\-\-quiet\fR
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
suppress all messages
|
suppress all messages
|
||||||
|
|
72
in_place.c
72
in_place.c
|
@ -1,18 +1,18 @@
|
||||||
/* Xlunzip - Test tool for the lzip_decompress linux module
|
/* Xlunzip - Test tool for the lzip_decompress linux module
|
||||||
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
Copyright (C) 2016-2020 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
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
@ -58,8 +58,7 @@ static uint8_t * read_file( const int infd, long * const buffer_sizep,
|
||||||
{
|
{
|
||||||
long buffer_size = 1 << 20;
|
long buffer_size = 1 << 20;
|
||||||
uint8_t * buffer = (uint8_t *)malloc( buffer_size );
|
uint8_t * buffer = (uint8_t *)malloc( buffer_size );
|
||||||
if( !buffer )
|
if( !buffer ) { show_file_error( filename, mem_msg, 0 ); return 0; }
|
||||||
{ show_file_error( filename, "Not enough memory.", 0 ); return 0; }
|
|
||||||
|
|
||||||
long file_size = readblock( infd, buffer, buffer_size );
|
long file_size = readblock( infd, buffer, buffer_size );
|
||||||
while( file_size >= buffer_size && !errno )
|
while( file_size >= buffer_size && !errno )
|
||||||
|
@ -70,8 +69,7 @@ static uint8_t * read_file( const int infd, long * const buffer_sizep,
|
||||||
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 )
|
||||||
{ show_file_error( filename, "Not enough memory.", 0 ); free( buffer );
|
{ show_file_error( filename, mem_msg, 0 ); free( buffer ); return 0; }
|
||||||
return 0; }
|
|
||||||
buffer = tmp;
|
buffer = tmp;
|
||||||
file_size += readblock( infd, buffer + file_size, buffer_size - file_size );
|
file_size += readblock( infd, buffer + file_size, buffer_size - file_size );
|
||||||
}
|
}
|
||||||
|
@ -88,6 +86,7 @@ struct File_sizes
|
||||||
{
|
{
|
||||||
unsigned long long csize;
|
unsigned long long csize;
|
||||||
unsigned long long dsize;
|
unsigned long long dsize;
|
||||||
|
long members;
|
||||||
long trailing;
|
long trailing;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,7 +101,8 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes,
|
||||||
if( !Lh_verify_version( *header ) )
|
if( !Lh_verify_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->trailing = 0;
|
file_sizes->csize = file_sizes->dsize = 0;
|
||||||
|
file_sizes->members = file_sizes->trailing = 0;
|
||||||
unsigned long pos = file_size; /* always points to a header or to EOF */
|
unsigned long pos = file_size; /* always points to a header or to EOF */
|
||||||
while( pos >= min_member_size )
|
while( pos >= min_member_size )
|
||||||
{
|
{
|
||||||
|
@ -137,6 +137,7 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes,
|
||||||
pos -= member_size;
|
pos -= member_size;
|
||||||
file_sizes->csize += member_size;
|
file_sizes->csize += member_size;
|
||||||
file_sizes->dsize += Lt_get_data_size( *trailer );
|
file_sizes->dsize += Lt_get_data_size( *trailer );
|
||||||
|
++file_sizes->members;
|
||||||
}
|
}
|
||||||
if( pos != 0 || file_sizes->csize == 0 ) return "Can't get file sizes.";
|
if( pos != 0 || file_sizes->csize == 0 ) return "Can't get file sizes.";
|
||||||
if( file_sizes->csize + file_sizes->trailing != (unsigned long)file_size )
|
if( file_sizes->csize + file_sizes->trailing != (unsigned long)file_size )
|
||||||
|
@ -154,13 +155,15 @@ 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. Verify that the in-place decompression does not
|
||||||
* overwrite the compressed data.
|
* overwrite the compressed data. The buffer must be large enough to contain
|
||||||
|
* after the decompressed data extra space for a marker, a trailer, the
|
||||||
|
* maximum possible data expansion, and (if multimember) N-1 empty members.
|
||||||
*
|
*
|
||||||
* |----- compressed data ------|
|
* |------ compressed data ------|
|
||||||
* V V
|
* V V
|
||||||
* |---------------|-------------------|--------|
|
* |----------------|-------------------|---------|
|
||||||
* ^ ^
|
* ^ ^ extra
|
||||||
* |------- decompressed data ---------|
|
* |-------- decompressed data ---------|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int decompress_in_place( const int infd, struct Pretty_print * const pp,
|
int decompress_in_place( const int infd, struct Pretty_print * const pp,
|
||||||
|
@ -175,19 +178,22 @@ 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 trailing = file_sizes.trailing; */
|
/* const long extra_bytes = ( dsize >> 8 ) + 65536; wrong linux formula */
|
||||||
/* ( (csize-36+63) >> 6 ) + 36 never failed with single member */
|
const long extra_bytes = ( csize >> 6 ) + file_sizes.members * 36;
|
||||||
const long rextra = ( csize >> 5 ) + 72;
|
const long long target_buffer_size = max( dsize, csize ) + extra_bytes;
|
||||||
if( buffer_size < dsize + rextra ) /* avoid realloc if big enough */
|
if( target_buffer_size > LONG_MAX )
|
||||||
|
{ show_file_error( pp->name, "Buffer is larger than LONG_MAX.", 0 );
|
||||||
|
return 1; }
|
||||||
|
if( buffer_size < target_buffer_size ) /* avoid realloc if big enough */
|
||||||
{
|
{
|
||||||
buffer_size = dsize + rextra;
|
buffer = (uint8_t *)realloc( buffer, target_buffer_size );
|
||||||
buffer = (uint8_t *)realloc( buffer, buffer_size );
|
if( !buffer ) { show_file_error( pp->name, mem_msg, 0 ); return 1; }
|
||||||
if( !buffer )
|
|
||||||
{ show_file_error( pp->name, "Not enough memory.", 0 ); return 1; }
|
|
||||||
}
|
}
|
||||||
else buffer_size = max( dsize + rextra, csize );
|
buffer_size = target_buffer_size;
|
||||||
const long cbegin = buffer_size - csize;
|
const long cbegin = buffer_size - csize; /* overwrite trailing data */
|
||||||
if( cbegin > 0 ) memmove( buffer + cbegin, buffer, csize );
|
if( cbegin > 0 ) memmove( buffer + cbegin, buffer, csize );
|
||||||
|
/*fprintf( stderr, "buffer_size = %ld, cbegin = %ld, extra_bytes = %ld\n",
|
||||||
|
buffer_size, cbegin, extra_bytes );*/
|
||||||
|
|
||||||
long in_pos, out_pos;
|
long in_pos, out_pos;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
26
lzip.h
26
lzip.h
|
@ -1,18 +1,18 @@
|
||||||
/* Xlunzip - Test tool for the lzip_decompress linux module
|
/* Xlunzip - Test tool for the lzip_decompress linux module
|
||||||
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
Copyright (C) 2016-2020 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
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef max
|
#ifndef max
|
||||||
|
@ -75,6 +75,8 @@ static inline unsigned long long Lt_get_member_size( const Lzip_trailer data )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char * const mem_msg = "Not enough memory.";
|
||||||
|
|
||||||
/* defined in in_place.c */
|
/* defined in in_place.c */
|
||||||
int decompress_in_place( const int infd, struct Pretty_print * const pp,
|
int decompress_in_place( const int infd, struct Pretty_print * const pp,
|
||||||
const bool testing );
|
const bool testing );
|
||||||
|
|
178
main.c
178
main.c
|
@ -1,24 +1,24 @@
|
||||||
/* Xlunzip - Test tool for the lzip_decompress linux module
|
/* Xlunzip - Test tool for the lzip_decompress linux module
|
||||||
Copyright (C) 2016-2020 Antonio Diaz Diaz.
|
Copyright (C) 2016-2020 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
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
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 flags, I/O errors, etc), 2 to indicate a
|
||||||
corrupt or invalid input file, 3 for an internal consistency error
|
corrupt or invalid input file, 3 for an internal consistency error
|
||||||
(eg, bug) which caused xlunzip to panic.
|
(eg, bug) which caused xlunzip to panic.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
@ -94,21 +94,20 @@ static bool delete_output_on_interrupt = false;
|
||||||
|
|
||||||
static void show_help( void )
|
static void show_help( void )
|
||||||
{
|
{
|
||||||
printf( "Xlunzip is a test tool for the lzip decompression code of my lzip patch\n"
|
printf( "Xlunzip is a test tool for the lzip decompression code of my lzip patch for\n"
|
||||||
"for linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress\n"
|
"linux. Xlunzip is similar to lunzip, but it uses the lzip_decompress linux\n"
|
||||||
"linux module as a backend. Xlunzip tests the module for stream,\n"
|
"module as a backend. Xlunzip tests the module for stream, buffer-to-buffer,\n"
|
||||||
"buffer-to-buffer and mixed decompression modes, including in-place\n"
|
"and mixed decompression modes, including in-place decompression (using the\n"
|
||||||
"decompression (using the same buffer for input and output). You can use\n"
|
"same buffer for input and output). You can use xlunzip to verify that the\n"
|
||||||
"xlunzip to verify that the module produces correct results when\n"
|
"module produces correct results when decompressing single member files,\n"
|
||||||
"decompressing single member files, multimember files, or the\n"
|
"multimember files, or the concatenation of two or more compressed files.\n"
|
||||||
"concatenation of two or more compressed files. Xlunzip can be used with\n"
|
"Xlunzip can be used with unzcrash to test the robustness of the module to\n"
|
||||||
"unzcrash to test the robustness of the module to the decompression of\n"
|
"the decompression of corrupted data.\n"
|
||||||
"corrupted data.\n"
|
"\nThe distributed index feature of the lzip format allows xlunzip to\n"
|
||||||
"\nNote that the in-place decompression of concatenated files can't be\n"
|
"decompress concatenated files in place. This can't be guaranteed to work\n"
|
||||||
"guaranteed to work because an arbitrarily low compression ratio of the\n"
|
"with formats like gzip or bzip2 because they can't detect whether a high\n"
|
||||||
"last part of the data can be achieved by appending enough empty\n"
|
"compression ratio in the first members of the multimember data is being\n"
|
||||||
"compressed members to a file, masking a high compression ratio at the\n"
|
"masked by a low compression ratio in the last members.\n"
|
||||||
"beginning of the data.\n"
|
|
||||||
"\nUsage: %s [options] [files]\n", invocation_name );
|
"\nUsage: %s [options] [files]\n", invocation_name );
|
||||||
printf( "\nOptions:\n"
|
printf( "\nOptions:\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
|
@ -118,7 +117,7 @@ static void show_help( void )
|
||||||
" -f, --force overwrite existing output files\n"
|
" -f, --force overwrite existing output files\n"
|
||||||
" -I, --in-place decompress or test using only one buffer\n"
|
" -I, --in-place decompress or test using only one buffer\n"
|
||||||
" -k, --keep keep (don't delete) input files\n"
|
" -k, --keep keep (don't delete) input files\n"
|
||||||
" -o, --output=<file> if reading standard input, write to <file>\n"
|
" -o, --output=<file> write to <file>, keep input files\n"
|
||||||
" -q, --quiet suppress all messages\n"
|
" -q, --quiet suppress all messages\n"
|
||||||
" -t, --test test compressed file integrity\n"
|
" -t, --test test compressed file integrity\n"
|
||||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||||
|
@ -157,11 +156,7 @@ static void * resize_buffer( void * buf, const unsigned min_size )
|
||||||
{
|
{
|
||||||
if( buf ) buf = realloc( buf, min_size );
|
if( buf ) buf = realloc( buf, min_size );
|
||||||
else buf = malloc( min_size );
|
else buf = malloc( min_size );
|
||||||
if( !buf )
|
if( !buf ) { show_error( mem_msg, 0, false ); cleanup_and_fail( 1 ); }
|
||||||
{
|
|
||||||
show_error( "Not enough memory.", 0, false );
|
|
||||||
cleanup_and_fail( 1 );
|
|
||||||
}
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +311,7 @@ static void set_d_outname( const char * const name, const int eindex )
|
||||||
|
|
||||||
|
|
||||||
static int open_instream( const char * const name, struct stat * const in_statsp,
|
static int open_instream( const char * const name, struct stat * const in_statsp,
|
||||||
const bool no_ofile )
|
const bool one_to_one )
|
||||||
{
|
{
|
||||||
int infd = open( name, O_RDONLY | O_BINARY );
|
int infd = open( name, O_RDONLY | O_BINARY );
|
||||||
if( infd < 0 )
|
if( infd < 0 )
|
||||||
|
@ -328,13 +323,12 @@ static int open_instream( const char * const name, struct stat * const in_statsp
|
||||||
const bool can_read = ( i == 0 &&
|
const bool can_read = ( i == 0 &&
|
||||||
( S_ISBLK( mode ) || S_ISCHR( mode ) ||
|
( S_ISBLK( mode ) || S_ISCHR( mode ) ||
|
||||||
S_ISFIFO( mode ) || S_ISSOCK( mode ) ) );
|
S_ISFIFO( mode ) || S_ISSOCK( mode ) ) );
|
||||||
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) )
|
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) )
|
||||||
{
|
{
|
||||||
if( verbosity >= 0 )
|
if( verbosity >= 0 )
|
||||||
fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n",
|
fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n",
|
||||||
program_name, name,
|
program_name, name, ( can_read && one_to_one ) ?
|
||||||
( can_read && !no_ofile ) ?
|
",\n and neither '-c' nor '-o' were specified" : "" );
|
||||||
",\n and '--stdout' was not specified" : "" );
|
|
||||||
close( infd );
|
close( infd );
|
||||||
infd = -1;
|
infd = -1;
|
||||||
}
|
}
|
||||||
|
@ -343,11 +337,11 @@ static int open_instream( const char * const name, struct stat * const in_statsp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool open_outstream( const bool force, const bool from_stdin )
|
static bool open_outstream( const bool force, const bool protect )
|
||||||
{
|
{
|
||||||
const mode_t usr_rw = S_IRUSR | S_IWUSR;
|
const mode_t usr_rw = S_IRUSR | S_IWUSR;
|
||||||
const mode_t all_rw = usr_rw | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
const mode_t all_rw = usr_rw | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||||
const mode_t outfd_mode = from_stdin ? all_rw : usr_rw;
|
const mode_t outfd_mode = protect ? usr_rw : all_rw;
|
||||||
int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY;
|
int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY;
|
||||||
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
|
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
|
||||||
|
|
||||||
|
@ -399,7 +393,7 @@ static void signal_handler( int sig )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set permissions, owner, and times. */
|
/* Set permissions, owner, and times. */
|
||||||
static void close_and_set_permissions( const struct stat * const in_statsp )
|
static void close_and_set_permissions( const struct stat * const in_statsp )
|
||||||
{
|
{
|
||||||
bool warning = false;
|
bool warning = false;
|
||||||
|
@ -499,7 +493,7 @@ static int decompress( struct Pretty_print * const pp, const long cl_insize,
|
||||||
long in_pos, out_pos;
|
long in_pos, out_pos;
|
||||||
int retval;
|
int retval;
|
||||||
if( ( in_len > 0 && !inbuf ) || ( out_size > 0 && !outbuf ) )
|
if( ( in_len > 0 && !inbuf ) || ( out_size > 0 && !outbuf ) )
|
||||||
{ show_error( "Not enough memory.", 0, false ); return 1; }
|
{ show_error( mem_msg, 0, false ); return 1; }
|
||||||
|
|
||||||
if( inbuf )
|
if( inbuf )
|
||||||
{
|
{
|
||||||
|
@ -544,6 +538,9 @@ void show_results( struct Pretty_print * const pp, const long in_pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void set_retval( int * retval, const int new_val )
|
||||||
|
{ if( *retval < new_val ) *retval = new_val; }
|
||||||
|
|
||||||
static void show_error( const char * const msg, const int errcode,
|
static void show_error( const char * const msg, const int errcode,
|
||||||
const bool help )
|
const bool help )
|
||||||
{
|
{
|
||||||
|
@ -623,7 +620,7 @@ int main( const int argc, const char * const argv[] )
|
||||||
if( argc > 0 ) invocation_name = argv[0];
|
if( argc > 0 ) invocation_name = argv[0];
|
||||||
|
|
||||||
if( !ap_init( &parser, argc, argv, options, 0 ) )
|
if( !ap_init( &parser, argc, argv, options, 0 ) )
|
||||||
{ show_error( "Not enough memory.", 0, false ); return 1; }
|
{ show_error( mem_msg, 0, false ); return 1; }
|
||||||
if( ap_error( &parser ) ) /* bad option */
|
if( ap_error( &parser ) ) /* bad option */
|
||||||
{ show_error( ap_error( &parser ), 0, true ); return 1; }
|
{ show_error( ap_error( &parser ), 0, true ); return 1; }
|
||||||
|
|
||||||
|
@ -641,7 +638,8 @@ int main( const int argc, const char * const argv[] )
|
||||||
case 'I': in_place = true; break;
|
case 'I': in_place = true; break;
|
||||||
case 'k': keep_input_files = true; break;
|
case 'k': keep_input_files = true; break;
|
||||||
case 'n': break;
|
case 'n': break;
|
||||||
case 'o': default_output_filename = arg; break;
|
case 'o': if( strcmp( arg, "-" ) == 0 ) to_stdout = true;
|
||||||
|
else { default_output_filename = arg; } break;
|
||||||
case 'q': verbosity = -1; break;
|
case 'q': verbosity = -1; break;
|
||||||
case 't': testing = true; break;
|
case 't': testing = true; break;
|
||||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||||
|
@ -672,64 +670,44 @@ int main( const int argc, const char * const argv[] )
|
||||||
if( strcmp( filenames[i], "-" ) != 0 ) filenames_given = true;
|
if( strcmp( filenames[i], "-" ) != 0 ) filenames_given = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( testing )
|
if( testing ) to_stdout = false; /* apply overrides */
|
||||||
outfd = -1;
|
if( testing || to_stdout ) default_output_filename = "";
|
||||||
|
|
||||||
if( !to_stdout && !testing &&
|
output_filename = resize_buffer( output_filename, 1 );
|
||||||
( filenames_given || default_output_filename[0] ) )
|
output_filename[0] = 0;
|
||||||
|
if( to_stdout && !testing ) outfd = STDOUT_FILENO;
|
||||||
|
else outfd = -1;
|
||||||
|
|
||||||
|
const bool to_file = !to_stdout && !testing && default_output_filename[0];
|
||||||
|
if( !to_stdout && !testing && ( filenames_given || to_file ) )
|
||||||
set_signals( signal_handler );
|
set_signals( signal_handler );
|
||||||
|
|
||||||
Pp_init( &pp, filenames, num_filenames );
|
Pp_init( &pp, filenames, num_filenames );
|
||||||
|
|
||||||
output_filename = resize_buffer( output_filename, 1 );
|
const bool one_to_one = !to_stdout && !testing && !to_file;
|
||||||
for( i = 0; i < num_filenames; ++i )
|
for( i = 0; i < num_filenames; ++i )
|
||||||
{
|
{
|
||||||
const char * input_filename = "";
|
const char * input_filename = "";
|
||||||
int tmp;
|
int tmp;
|
||||||
struct stat in_stats;
|
struct stat in_stats;
|
||||||
const struct stat * in_statsp;
|
const struct stat * in_statsp;
|
||||||
output_filename[0] = 0;
|
|
||||||
|
|
||||||
if( strcmp( filenames[i], "-" ) == 0 )
|
if( strcmp( filenames[i], "-" ) == 0 )
|
||||||
{
|
{
|
||||||
if( stdin_used ) continue; else stdin_used = true;
|
if( stdin_used ) continue; else stdin_used = true;
|
||||||
infd = STDIN_FILENO;
|
infd = STDIN_FILENO;
|
||||||
if( !testing )
|
if( one_to_one ) { outfd = STDOUT_FILENO; output_filename[0] = 0; }
|
||||||
{
|
|
||||||
if( to_stdout || !default_output_filename[0] )
|
|
||||||
outfd = STDOUT_FILENO;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output_filename = resize_buffer( output_filename,
|
|
||||||
strlen( default_output_filename ) + 1 );
|
|
||||||
strcpy( output_filename, default_output_filename );
|
|
||||||
if( !open_outstream( force, true ) )
|
|
||||||
{
|
|
||||||
if( retval < 1 ) retval = 1;
|
|
||||||
close( infd ); infd = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
input_filename = filenames[i];
|
input_filename = filenames[i];
|
||||||
infd = open_instream( input_filename, &in_stats, to_stdout || testing );
|
infd = open_instream( input_filename, &in_stats, one_to_one );
|
||||||
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
|
if( infd < 0 ) { set_retval( &retval, 1 ); continue; }
|
||||||
if( !testing )
|
if( one_to_one )
|
||||||
{
|
{
|
||||||
if( to_stdout ) outfd = STDOUT_FILENO;
|
set_d_outname( input_filename, extension_index( input_filename ) );
|
||||||
else
|
if( !open_outstream( force, true ) )
|
||||||
{
|
{ set_retval( &retval, 1 ); close( infd ); infd = -1; continue; }
|
||||||
set_d_outname( input_filename, extension_index( input_filename ) );
|
|
||||||
if( !open_outstream( force, false ) )
|
|
||||||
{
|
|
||||||
if( retval < 1 ) retval = 1;
|
|
||||||
close( infd ); infd = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,37 +716,43 @@ int main( const int argc, const char * const argv[] )
|
||||||
{
|
{
|
||||||
show_file_error( pp.name,
|
show_file_error( pp.name,
|
||||||
"I won't read compressed data from a terminal.", 0 );
|
"I won't read compressed data from a terminal.", 0 );
|
||||||
if( retval < 1 ) retval = 1;
|
set_retval( &retval, 1 );
|
||||||
if( testing ) { close( infd ); infd = -1; continue; }
|
if( testing ) { close( infd ); infd = -1; continue; }
|
||||||
cleanup_and_fail( retval );
|
cleanup_and_fail( retval );
|
||||||
}
|
}
|
||||||
|
|
||||||
in_statsp = input_filename[0] ? &in_stats : 0;
|
if( to_file && outfd < 0 ) /* open outfd after verifying infd */
|
||||||
|
{
|
||||||
|
output_filename = resize_buffer( output_filename,
|
||||||
|
strlen( default_output_filename ) + 1 );
|
||||||
|
strcpy( output_filename, default_output_filename );
|
||||||
|
if( !open_outstream( force, false ) ) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_statsp = ( input_filename[0] && one_to_one ) ? &in_stats : 0;
|
||||||
if( in_place )
|
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( &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_error( input_filename[0] ? "Error closing input file" :
|
set_retval( &tmp, 1 ); }
|
||||||
"Error closing stdin", errno, false );
|
|
||||||
if( tmp < 1 ) tmp = 1;
|
|
||||||
}
|
|
||||||
infd = -1;
|
infd = -1;
|
||||||
if( tmp > retval ) retval = tmp;
|
set_retval( &retval, tmp );
|
||||||
if( tmp )
|
if( tmp )
|
||||||
{ if( !testing ) cleanup_and_fail( retval );
|
{ if( !testing ) cleanup_and_fail( retval );
|
||||||
else ++failed_tests; }
|
else ++failed_tests; }
|
||||||
|
|
||||||
if( delete_output_on_interrupt )
|
if( delete_output_on_interrupt && one_to_one )
|
||||||
close_and_set_permissions( in_statsp );
|
close_and_set_permissions( in_statsp );
|
||||||
if( input_filename[0] && !keep_input_files && !to_stdout && !testing )
|
if( input_filename[0] && !keep_input_files && one_to_one )
|
||||||
remove( input_filename );
|
remove( input_filename );
|
||||||
}
|
}
|
||||||
if( outfd >= 0 && close( outfd ) != 0 )
|
if( delete_output_on_interrupt ) close_and_set_permissions( 0 ); /* -o */
|
||||||
|
else if( outfd >= 0 && close( outfd ) != 0 ) /* -c */
|
||||||
{
|
{
|
||||||
show_error( "Error closing stdout", errno, false );
|
show_error( "Error closing stdout", errno, false );
|
||||||
if( retval < 1 ) retval = 1;
|
set_retval( &retval, 1 );
|
||||||
}
|
}
|
||||||
if( failed_tests > 0 && verbosity >= 1 && num_filenames > 1 )
|
if( failed_tests > 0 && verbosity >= 1 && num_filenames > 1 )
|
||||||
fprintf( stderr, "%s: warning: %d %s failed the test.\n",
|
fprintf( stderr, "%s: warning: %d %s failed the test.\n",
|
||||||
|
|
|
@ -48,8 +48,13 @@ printf "testing xlunzip-%s..." "$2"
|
||||||
[ $? = 2 ] || test_failed $LINENO
|
[ $? = 2 ] || test_failed $LINENO
|
||||||
"${LZIP}" -dq -o in < "${in_lz}"
|
"${LZIP}" -dq -o in < "${in_lz}"
|
||||||
[ $? = 1 ] || test_failed $LINENO
|
[ $? = 1 ] || test_failed $LINENO
|
||||||
|
"${LZIP}" -dq -o in "${in_lz}"
|
||||||
|
[ $? = 1 ] || test_failed $LINENO
|
||||||
|
"${LZIP}" -dq -o out nx_file.lz
|
||||||
|
[ $? = 1 ] || test_failed $LINENO
|
||||||
|
[ ! -e out ] || test_failed $LINENO
|
||||||
# these are for code coverage
|
# these are for code coverage
|
||||||
"${LZIP}" -t -- nx_file 2> /dev/null
|
"${LZIP}" -t -- nx_file.lz 2> /dev/null
|
||||||
[ $? = 1 ] || test_failed $LINENO
|
[ $? = 1 ] || test_failed $LINENO
|
||||||
"${LZIP}" -t "" < /dev/null 2> /dev/null
|
"${LZIP}" -t "" < /dev/null 2> /dev/null
|
||||||
[ $? = 1 ] || test_failed $LINENO
|
[ $? = 1 ] || test_failed $LINENO
|
||||||
|
@ -77,11 +82,17 @@ 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"
|
||||||
|
cmp in copy || test_failed $LINENO "$i"
|
||||||
"${LZIP}" -cd "$i" > copy || test_failed $LINENO "$i"
|
"${LZIP}" -cd "$i" > copy || test_failed $LINENO "$i"
|
||||||
cmp in 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
|
||||||
done
|
done
|
||||||
|
|
||||||
rm -f 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}" -dk copy.lz || test_failed $LINENO
|
||||||
cmp in copy || test_failed $LINENO
|
cmp in copy || test_failed $LINENO
|
||||||
|
@ -95,10 +106,16 @@ cmp in copy || test_failed $LINENO
|
||||||
printf "to be overwritten" > copy || framework_failure
|
printf "to be overwritten" > copy || framework_failure
|
||||||
"${LZIP}" -df -o copy < "${in_lz}" || test_failed $LINENO
|
"${LZIP}" -df -o copy < "${in_lz}" || test_failed $LINENO
|
||||||
cmp in copy || test_failed $LINENO
|
cmp in copy || test_failed $LINENO
|
||||||
|
rm -f out copy || framework_failure
|
||||||
|
"${LZIP}" -d -o ./- "${in_lz}" || test_failed $LINENO
|
||||||
|
cmp in ./- || test_failed $LINENO
|
||||||
|
rm -f ./- || framework_failure
|
||||||
|
"${LZIP}" -d -o ./- < "${in_lz}" || test_failed $LINENO
|
||||||
|
cmp in ./- || test_failed $LINENO
|
||||||
|
rm -f ./- || framework_failure
|
||||||
|
|
||||||
rm -f copy || framework_failure
|
|
||||||
cat "${in_lz}" > anyothername || framework_failure
|
cat "${in_lz}" > anyothername || framework_failure
|
||||||
"${LZIP}" -dv --output copy - anyothername - < "${in_lz}" 2> /dev/null ||
|
"${LZIP}" -dv - anyothername - < "${in_lz}" > copy 2> /dev/null ||
|
||||||
test_failed $LINENO
|
test_failed $LINENO
|
||||||
cmp in copy || test_failed $LINENO
|
cmp in copy || test_failed $LINENO
|
||||||
cmp in anyothername.out || test_failed $LINENO
|
cmp in anyothername.out || test_failed $LINENO
|
||||||
|
@ -128,12 +145,16 @@ cat "${in_lz}" > copy.lz || framework_failure
|
||||||
cmp in copy || test_failed $LINENO
|
cmp in copy || test_failed $LINENO
|
||||||
|
|
||||||
cat in in > in2 || framework_failure
|
cat in in > in2 || framework_failure
|
||||||
cat "${in_lz}" "${in_lz}" > in2.lz || framework_failure
|
"${LZIP}" -t "${in_lz}" "${in_lz}" || test_failed $LINENO
|
||||||
"${LZIP}" -t in2.lz || test_failed $LINENO
|
"${LZIP}" -cd "${in_lz}" "${in_lz}" -o out > copy2 || test_failed $LINENO
|
||||||
"${LZIP}" -cd in2.lz > copy2 || test_failed $LINENO
|
[ ! -e out ] || test_failed $LINENO # override -o
|
||||||
cmp in2 copy2 || test_failed $LINENO
|
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
|
||||||
|
|
||||||
cat in2.lz > copy2.lz || framework_failure
|
cat "${in_lz}" "${in_lz}" > copy2.lz || framework_failure
|
||||||
printf "\ngarbage" >> copy2.lz || framework_failure
|
printf "\ngarbage" >> copy2.lz || framework_failure
|
||||||
"${LZIP}" -tvvvv copy2.lz 2> /dev/null || test_failed $LINENO
|
"${LZIP}" -tvvvv copy2.lz 2> /dev/null || test_failed $LINENO
|
||||||
printf "to be overwritten" > copy2 || framework_failure
|
printf "to be overwritten" > copy2 || framework_failure
|
||||||
|
@ -183,6 +204,7 @@ for i in fox_bcrc.lz fox_crc0.lz fox_das46.lz fox_mes81.lz ; do
|
||||||
done
|
done
|
||||||
rm -f fox out || framework_failure
|
rm -f fox out || framework_failure
|
||||||
|
|
||||||
|
cat "${in_lz}" "${in_lz}" > in2.lz || framework_failure
|
||||||
cat "${in_lz}" "${in_lz}" "${in_lz}" > in3.lz || framework_failure
|
cat "${in_lz}" "${in_lz}" "${in_lz}" > in3.lz || framework_failure
|
||||||
if dd if=in3.lz of=trunc.lz bs=14752 count=1 2> /dev/null &&
|
if dd if=in3.lz of=trunc.lz bs=14752 count=1 2> /dev/null &&
|
||||||
[ -e trunc.lz ] && cmp in2.lz trunc.lz > /dev/null 2>&1 ; then
|
[ -e trunc.lz ] && cmp in2.lz trunc.lz > /dev/null 2>&1 ; then
|
||||||
|
@ -283,30 +305,62 @@ cmp -s in copy && test_failed $LINENO
|
||||||
[ $? = 1 ] || test_failed $LINENO
|
[ $? = 1 ] || test_failed $LINENO
|
||||||
cmp -s in copy && test_failed $LINENO
|
cmp -s in copy && test_failed $LINENO
|
||||||
|
|
||||||
|
# decompress in place
|
||||||
|
rm -f copy copy2 || 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}" -d --in-place "${in_lz}" -o copy || test_failed $LINENO
|
||||||
|
cmp in copy || test_failed $LINENO
|
||||||
|
rm -f copy || framework_failure
|
||||||
|
"${LZIP}" -d --in-place < "${in_lz}" -o copy || test_failed $LINENO
|
||||||
|
cmp in copy || test_failed $LINENO
|
||||||
"${LZIP}" -cd --in-place "${in_lz}" > copy || test_failed $LINENO
|
"${LZIP}" -cd --in-place "${in_lz}" > copy || test_failed $LINENO
|
||||||
cmp in copy || test_failed $LINENO
|
cmp in copy || test_failed $LINENO
|
||||||
|
"${LZIP}" -cd --in-place < "${in_lz}" > copy || test_failed $LINENO
|
||||||
|
cmp in copy || 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
|
||||||
|
cmp in2 copy2 || test_failed $LINENO
|
||||||
|
"${LZIP}" -cd --in-place "${in_lz}" "${in_lz}" > copy2 || test_failed $LINENO
|
||||||
|
cmp in2 copy2 || test_failed $LINENO
|
||||||
|
|
||||||
|
# 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
|
||||||
|
rm -f copy || framework_failure
|
||||||
|
"${LZIP}" -d --in-place $i.lz -o copy || test_failed $LINENO
|
||||||
|
cmp $i copy || test_failed $LINENO
|
||||||
|
rm -f copy || framework_failure
|
||||||
|
"${LZIP}" -d --in-place < $i.lz -o copy || test_failed $LINENO
|
||||||
|
cmp $i copy || test_failed $LINENO
|
||||||
"${LZIP}" -cd --in-place $i.lz > copy || test_failed $LINENO
|
"${LZIP}" -cd --in-place $i.lz > copy || test_failed $LINENO
|
||||||
cmp $i copy || test_failed $LINENO
|
cmp $i copy || test_failed $LINENO
|
||||||
|
"${LZIP}" -cd --in-place < $i.lz > copy || test_failed $LINENO
|
||||||
|
cmp $i copy || 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
|
||||||
|
|
||||||
cat "${in_lz}" "${zero_lz}" "${zero_lz}" "${zero_lz}" "${zero_lz}" \
|
cat "${in_lz}" > inz.lz || framework_failure
|
||||||
"${zero_lz}" "${zero_lz}" "${zero_lz}" > inz.lz || framework_failure
|
counter=0
|
||||||
"${LZIP}" -t --in-place inz.lz || test_failed $LINENO
|
while [ ${counter} -lt 20 ] ; do
|
||||||
"${LZIP}" -cd --in-place inz.lz > copy || test_failed $LINENO
|
cat "${zero_lz}" >> inz.lz || framework_failure
|
||||||
|
"${LZIP}" -t --in-place inz.lz || test_failed $LINENO
|
||||||
|
"${LZIP}" -cd --in-place inz.lz > copy || test_failed $LINENO
|
||||||
|
cmp in copy || test_failed $LINENO
|
||||||
|
counter=$((counter+1))
|
||||||
|
done
|
||||||
|
rm -f copy inz.lz || framework_failure
|
||||||
|
|
||||||
|
# decompress with trailing data in place
|
||||||
|
cat "${in_lz}" in in in in > int.lz || framework_failure
|
||||||
|
"${LZIP}" -t --in-place int.lz || test_failed $LINENO
|
||||||
|
"${LZIP}" -cd --in-place int.lz > copy || test_failed $LINENO
|
||||||
cmp in copy || test_failed $LINENO
|
cmp in copy || test_failed $LINENO
|
||||||
cat "${zero_lz}" >> inz.lz || framework_failure
|
rm -f copy int.lz || framework_failure
|
||||||
"${LZIP}" -tq --in-place inz.lz
|
|
||||||
[ $? = 2 ] || test_failed $LINENO
|
|
||||||
"${LZIP}" -cdq --in-place inz.lz > copy
|
|
||||||
[ $? = 2 ] || test_failed $LINENO
|
|
||||||
cmp -s in copy && test_failed $LINENO
|
|
||||||
rm -f copy ingin.lz in2 in2.lz in3 in3.lz || framework_failure
|
|
||||||
|
|
||||||
echo
|
echo
|
||||||
if [ ${fail} = 0 ] ; then
|
if [ ${fail} = 0 ] ; then
|
||||||
|
|
Loading…
Add table
Reference in a new issue