Merging upstream version 1.17~pre1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
7d611f6ad4
commit
8f2eadfbb8
17 changed files with 419 additions and 186 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2014-10-16 Antonio Diaz Diaz <antonio@gnu.org>
|
||||||
|
|
||||||
|
* Version 1.17-pre1 released.
|
||||||
|
* merge.cc: New block selection algorithm makes merge much faster.
|
||||||
|
* Makefile.in: Added new targets 'install*-compress'.
|
||||||
|
* testsuite/unzcrash.cc: Moved to top directory.
|
||||||
|
* Added chapter 'File names' to the manual.
|
||||||
|
|
||||||
2014-08-29 Antonio Diaz Diaz <antonio@gnu.org>
|
2014-08-29 Antonio Diaz Diaz <antonio@gnu.org>
|
||||||
|
|
||||||
* Version 1.16 released.
|
* Version 1.16 released.
|
||||||
|
|
4
INSTALL
4
INSTALL
|
@ -32,6 +32,10 @@ the main archive.
|
||||||
5. Type 'make install' to install the program and any data files and
|
5. Type 'make install' to install the program and any data files and
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
|
Or type 'make install-compress', which additionally compresses the
|
||||||
|
info manual and the man page after installation. (Installing
|
||||||
|
compressed docs may become the default in the future).
|
||||||
|
|
||||||
You can install only the program, the info manual or the man page by
|
You can install only the program, the info manual or the man page by
|
||||||
typing 'make install-bin', 'make install-info' or 'make install-man'
|
typing 'make install-bin', 'make install-info' or 'make install-man'
|
||||||
respectively.
|
respectively.
|
||||||
|
|
33
Makefile.in
33
Makefile.in
|
@ -11,7 +11,9 @@ objs = arg_parser.o file_index.o merge.o mtester.o range_dec.o repair.o \
|
||||||
unzobjs = arg_parser.o unzcrash.o
|
unzobjs = arg_parser.o unzcrash.o
|
||||||
|
|
||||||
|
|
||||||
.PHONY : all install install-bin install-info install-man install-strip \
|
.PHONY : all install install-bin install-info install-man \
|
||||||
|
install-strip install-compress install-strip-compress \
|
||||||
|
install-bin-strip install-info-compress install-man-compress \
|
||||||
install-as-lzip uninstall uninstall-bin uninstall-info uninstall-man \
|
install-as-lzip uninstall uninstall-bin uninstall-info uninstall-man \
|
||||||
doc info man check dist clean distclean
|
doc info man check dist clean distclean
|
||||||
|
|
||||||
|
@ -20,16 +22,13 @@ all : $(progname)
|
||||||
$(progname) : $(objs)
|
$(progname) : $(objs)
|
||||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(objs)
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(objs)
|
||||||
|
|
||||||
$(progname)_profiled : $(objs)
|
|
||||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -pg -o $@ $(objs)
|
|
||||||
|
|
||||||
unzcrash : $(unzobjs)
|
unzcrash : $(unzobjs)
|
||||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(unzobjs)
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(unzobjs)
|
||||||
|
|
||||||
main.o : main.cc
|
main.o : main.cc
|
||||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||||
|
|
||||||
unzcrash.o : testsuite/unzcrash.cc
|
unzcrash.o : unzcrash.cc
|
||||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||||
|
|
||||||
%.o : %.cc
|
%.o : %.cc
|
||||||
|
@ -67,38 +66,49 @@ check : all
|
||||||
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
|
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
|
||||||
|
|
||||||
install : install-bin install-info install-man
|
install : install-bin install-info install-man
|
||||||
|
install-strip : install-bin-strip install-info install-man
|
||||||
|
install-compress : install-bin install-info-compress install-man-compress
|
||||||
|
install-strip-compress : install-bin-strip install-info-compress install-man-compress
|
||||||
|
|
||||||
install-bin : all
|
install-bin : all
|
||||||
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
|
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
|
||||||
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
|
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
|
||||||
|
|
||||||
|
install-bin-strip : all
|
||||||
|
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install-bin
|
||||||
|
|
||||||
install-info :
|
install-info :
|
||||||
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
|
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
|
||||||
|
-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"
|
||||||
-install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info"
|
-install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||||
|
|
||||||
|
install-info-compress : install-info
|
||||||
|
lzip -v -9 "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||||
|
|
||||||
install-man :
|
install-man :
|
||||||
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
|
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
|
||||||
|
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"*
|
||||||
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||||
|
|
||||||
install-strip : all
|
install-man-compress : install-man
|
||||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
lzip -v -9 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||||
|
|
||||||
install-as-lzip : install
|
install-as-lzip : install
|
||||||
-rm -f "$(DESTDIR)$(bindir)/lzip"
|
-rm -f "$(DESTDIR)$(bindir)/lzip"
|
||||||
cd "$(DESTDIR)$(bindir)" && ln -s $(progname) lzip
|
cd "$(DESTDIR)$(bindir)" && ln -s $(progname) lzip
|
||||||
|
|
||||||
uninstall : uninstall-bin uninstall-info uninstall-man
|
uninstall : uninstall-man uninstall-info uninstall-bin
|
||||||
|
|
||||||
uninstall-bin :
|
uninstall-bin :
|
||||||
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
|
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
|
||||||
|
|
||||||
uninstall-info :
|
uninstall-info :
|
||||||
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
|
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"
|
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||||
|
|
||||||
uninstall-man :
|
uninstall-man :
|
||||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"*
|
||||||
|
|
||||||
dist : doc
|
dist : doc
|
||||||
ln -sf $(VPATH) $(DISTNAME)
|
ln -sf $(VPATH) $(DISTNAME)
|
||||||
|
@ -122,14 +132,13 @@ dist : doc
|
||||||
$(DISTNAME)/testsuite/test.txt.lz \
|
$(DISTNAME)/testsuite/test.txt.lz \
|
||||||
$(DISTNAME)/testsuite/test21723.txt \
|
$(DISTNAME)/testsuite/test21723.txt \
|
||||||
$(DISTNAME)/testsuite/test_bad[1-5].lz \
|
$(DISTNAME)/testsuite/test_bad[1-5].lz \
|
||||||
$(DISTNAME)/testsuite/unzcrash.cc \
|
|
||||||
$(DISTNAME)/*.h \
|
$(DISTNAME)/*.h \
|
||||||
$(DISTNAME)/*.cc
|
$(DISTNAME)/*.cc
|
||||||
rm -f $(DISTNAME)
|
rm -f $(DISTNAME)
|
||||||
lzip -v -9 $(DISTNAME).tar
|
lzip -v -9 $(DISTNAME).tar
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
-rm -f $(progname) $(progname)_profiled $(objs)
|
-rm -f $(progname) $(objs)
|
||||||
-rm -f unzcrash unzcrash.o
|
-rm -f unzcrash unzcrash.o
|
||||||
|
|
||||||
distclean : clean
|
distclean : clean
|
||||||
|
|
21
NEWS
21
NEWS
|
@ -1,14 +1,13 @@
|
||||||
Changes in version 1.16:
|
Changes in version 1.17:
|
||||||
|
|
||||||
Repairing of single-byte errors is now about 10 times faster depending
|
Merging files now uses an algorithm similar to the ones used to solve
|
||||||
on file size and position of error.
|
the "Master Mind" game, which makes it much faster. Up to 2 orders of
|
||||||
|
magnitude faster depending on number of files and number of errors.
|
||||||
|
Please, report as a bug any files correctly merged by lziprecover 1.16
|
||||||
|
that this version can't merge.
|
||||||
|
|
||||||
Copying of file dates, permissions, and ownership now behaves like "cp -p".
|
The targets "install-compress", "install-strip-compress",
|
||||||
(If the user ID or the group ID can't be duplicated, the file permission
|
"install-info-compress" and "install-man-compress" have been added to
|
||||||
bits S_ISUID and S_ISGID are cleared).
|
the Makefile.
|
||||||
|
|
||||||
Some minor improvements have been made.
|
The chapter "File names" has been added to the manual.
|
||||||
|
|
||||||
"lziprecover.texinfo" has been renamed to "lziprecover.texi".
|
|
||||||
|
|
||||||
The license has been changed to GPL version 2 or later.
|
|
||||||
|
|
17
README
17
README
|
@ -2,11 +2,13 @@ Description
|
||||||
|
|
||||||
Lziprecover is a data recovery tool and decompressor for files in the
|
Lziprecover is a data recovery tool and decompressor for files in the
|
||||||
lzip compressed data format (.lz), able to repair slightly damaged
|
lzip compressed data format (.lz), able to repair slightly damaged
|
||||||
files, recover badly damaged files from two or more copies, extract data
|
files, produce a correct file by merging the good parts of two or more
|
||||||
from damaged files, decompress files and test integrity of files.
|
damaged copies, extract data from damaged files, decompress files and
|
||||||
|
test integrity of files.
|
||||||
|
|
||||||
The lzip file format is designed for long-term data archiving, taking
|
The lzip file format is designed for data sharing and long-term
|
||||||
into account both data integrity and decoder availability:
|
archiving, taking into account both data integrity and decoder
|
||||||
|
availability:
|
||||||
|
|
||||||
* The lzip format provides very safe integrity checking and some data
|
* The lzip format provides very safe integrity checking and some data
|
||||||
recovery means. The lziprecover program can repair bit-flip errors
|
recovery means. The lziprecover program can repair bit-flip errors
|
||||||
|
@ -21,8 +23,8 @@ into account both data integrity and decoder availability:
|
||||||
extract the data from a lzip file long after quantum computers
|
extract the data from a lzip file long after quantum computers
|
||||||
eventually render LZMA obsolete.
|
eventually render LZMA obsolete.
|
||||||
|
|
||||||
* Additionally lzip is copylefted, which guarantees that it will
|
* Additionally the lzip reference implementation is copylefted, which
|
||||||
remain free forever.
|
guarantees that it will remain free forever.
|
||||||
|
|
||||||
A nice feature of the lzip format is that a corrupt byte is easier to
|
A nice feature of the lzip format is that a corrupt byte is easier to
|
||||||
repair the nearer it is from the beginning of the file. Therefore, with
|
repair the nearer it is from the beginning of the file. Therefore, with
|
||||||
|
@ -61,7 +63,8 @@ of them with one damaged area affecting 1 percent of the copy, the
|
||||||
probability of obtaining a correct file is about 98 percent. With three
|
probability of obtaining a correct file is about 98 percent. With three
|
||||||
such copies the probability rises to 99.97 percent. For large files (a
|
such copies the probability rises to 99.97 percent. For large files (a
|
||||||
few MB) with small errors (one sector damaged per copy), the probability
|
few MB) with small errors (one sector damaged per copy), the probability
|
||||||
approaches 100 percent even with only two copies.
|
approaches 100 percent even with only two copies. (Supposing that the
|
||||||
|
errors are randomly located inside each copy).
|
||||||
|
|
||||||
Lziprecover is not a replacement for regular backups, but a last line of
|
Lziprecover is not a replacement for regular backups, but a last line of
|
||||||
defense for the case where the backups are also damaged.
|
defense for the case where the backups are also damaged.
|
||||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -6,7 +6,7 @@
|
||||||
# to copy, distribute and modify it.
|
# to copy, distribute and modify it.
|
||||||
|
|
||||||
pkgname=lziprecover
|
pkgname=lziprecover
|
||||||
pkgversion=1.16
|
pkgversion=1.17-pre1
|
||||||
progname=lziprecover
|
progname=lziprecover
|
||||||
srctrigger=doc/${pkgname}.texi
|
srctrigger=doc/${pkgname}.texi
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,7 @@ long readblock( const int fd, uint8_t * const buf, const long size )
|
||||||
errno = 0;
|
errno = 0;
|
||||||
while( sz < size )
|
while( sz < size )
|
||||||
{
|
{
|
||||||
const int psz = std::min( 65536L, size - sz );
|
const int n = read( fd, buf + sz, std::min( 1L << 20, size - sz ) );
|
||||||
const int n = read( fd, buf + sz, psz );
|
|
||||||
if( n > 0 ) sz += n;
|
if( n > 0 ) sz += n;
|
||||||
else if( n == 0 ) break; // EOF
|
else if( n == 0 ) break; // EOF
|
||||||
else if( errno != EINTR ) break;
|
else if( errno != EINTR ) break;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.\" 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 LZIPRECOVER "1" "August 2014" "lziprecover 1.16" "User Commands"
|
.TH LZIPRECOVER "1" "October 2014" "lziprecover 1.17-pre1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
lziprecover \- recovers data from damaged lzip files
|
lziprecover \- recovers data from damaged lzip files
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -7,6 +7,13 @@ lziprecover \- recovers data from damaged lzip files
|
||||||
[\fI\,options\/\fR] [\fI\,files\/\fR]
|
[\fI\,options\/\fR] [\fI\,files\/\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Lziprecover \- Data recovery tool and decompressor for the lzip format.
|
Lziprecover \- Data recovery tool and decompressor for the lzip format.
|
||||||
|
Lziprecover can repair perfectly most files with small errors (up to one
|
||||||
|
single\-byte error per member), without the need of any extra redundance
|
||||||
|
at all. Losing an entire archive just because of a corrupt byte near the
|
||||||
|
beginning is a thing of the past.
|
||||||
|
Lziprecover can also produce a correct file by merging the good parts of
|
||||||
|
two or more damaged copies, extract data from damaged files, decompress
|
||||||
|
files and test integrity of files.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
|
|
@ -12,7 +12,7 @@ File: lziprecover.info, Node: Top, Next: Introduction, Up: (dir)
|
||||||
Lziprecover Manual
|
Lziprecover Manual
|
||||||
******************
|
******************
|
||||||
|
|
||||||
This manual is for Lziprecover (version 1.16, 29 August 2014).
|
This manual is for Lziprecover (version 1.17-pre1, 16 October 2014).
|
||||||
|
|
||||||
* Menu:
|
* Menu:
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ This manual is for Lziprecover (version 1.16, 29 August 2014).
|
||||||
* Invoking lziprecover:: Command line interface
|
* Invoking lziprecover:: Command line interface
|
||||||
* Repairing files:: Fixing bit-flip and similar errors
|
* Repairing files:: Fixing bit-flip and similar errors
|
||||||
* Merging files:: Fixing several damaged copies
|
* Merging files:: Fixing several damaged copies
|
||||||
|
* File names:: Names of the files produced by lziprecover
|
||||||
* File format:: Detailed format of the compressed file
|
* File format:: Detailed format of the compressed file
|
||||||
* Examples:: A small tutorial with examples
|
* Examples:: A small tutorial with examples
|
||||||
* Unzcrash:: Testing the robustness of decompressors
|
* Unzcrash:: Testing the robustness of decompressors
|
||||||
|
@ -40,11 +41,13 @@ File: lziprecover.info, Node: Introduction, Next: Invoking lziprecover, Prev:
|
||||||
|
|
||||||
Lziprecover is a data recovery tool and decompressor for files in the
|
Lziprecover is a data recovery tool and decompressor for files in the
|
||||||
lzip compressed data format (.lz), able to repair slightly damaged
|
lzip compressed data format (.lz), able to repair slightly damaged
|
||||||
files, recover badly damaged files from two or more copies, extract data
|
files, produce a correct file by merging the good parts of two or more
|
||||||
from damaged files, decompress files and test integrity of files.
|
damaged copies, extract data from damaged files, decompress files and
|
||||||
|
test integrity of files.
|
||||||
|
|
||||||
The lzip file format is designed for long-term data archiving, taking
|
The lzip file format is designed for data sharing and long-term
|
||||||
into account both data integrity and decoder availability:
|
archiving, taking into account both data integrity and decoder
|
||||||
|
availability:
|
||||||
|
|
||||||
* The lzip format provides very safe integrity checking and some data
|
* The lzip format provides very safe integrity checking and some data
|
||||||
recovery means. The lziprecover program can repair bit-flip errors
|
recovery means. The lziprecover program can repair bit-flip errors
|
||||||
|
@ -59,8 +62,8 @@ into account both data integrity and decoder availability:
|
||||||
archaeologist to extract the data from a lzip file long after
|
archaeologist to extract the data from a lzip file long after
|
||||||
quantum computers eventually render LZMA obsolete.
|
quantum computers eventually render LZMA obsolete.
|
||||||
|
|
||||||
* Additionally lzip is copylefted, which guarantees that it will
|
* Additionally the lzip reference implementation is copylefted, which
|
||||||
remain free forever.
|
guarantees that it will remain free forever.
|
||||||
|
|
||||||
A nice feature of the lzip format is that a corrupt byte is easier to
|
A nice feature of the lzip format is that a corrupt byte is easier to
|
||||||
repair the nearer it is from the beginning of the file. Therefore, with
|
repair the nearer it is from the beginning of the file. Therefore, with
|
||||||
|
@ -168,11 +171,12 @@ The format for running lziprecover is:
|
||||||
|
|
||||||
'-m'
|
'-m'
|
||||||
'--merge'
|
'--merge'
|
||||||
Try to produce a correct file merging the good parts of two or more
|
Try to produce a correct file by merging the good parts of two or
|
||||||
damaged copies. If successful, a repaired copy is written to the
|
more damaged copies. If successful, a repaired copy is written to
|
||||||
file 'FILE_fixed.lz'. The exit status is 0 if a correct file could
|
the file 'FILE_fixed.lz'. The exit status is 0 if a correct file
|
||||||
be produced, 2 otherwise. See the chapter 'Merging files' (*note
|
could be produced, 2 otherwise. See the chapter 'Merging files'
|
||||||
Merging files::) for a complete description of the merge mode.
|
(*note Merging files::) for a complete description of the merge
|
||||||
|
mode.
|
||||||
|
|
||||||
'-o FILE'
|
'-o FILE'
|
||||||
'--output=FILE'
|
'--output=FILE'
|
||||||
|
@ -203,11 +207,11 @@ The format for running lziprecover is:
|
||||||
undamaged, and try to repair or partially decompress those which
|
undamaged, and try to repair or partially decompress those which
|
||||||
are damaged.
|
are damaged.
|
||||||
|
|
||||||
The names of the files produced are in the form 'rec01FILE.lz',
|
The names of the files produced are in the form 'rec01FILE',
|
||||||
'rec02FILE.lz', etc, and are designed so that the use of wildcards
|
'rec02FILE', etc, and are designed so that the use of wildcards in
|
||||||
in subsequent processing, for example,
|
subsequent processing, for example,
|
||||||
'lziprecover -cd rec*FILE.lz > recovered_data', processes the
|
'lziprecover -cd rec*FILE > recovered_data', processes the files
|
||||||
files in the correct order. The number of digits used in the names
|
in the correct order. The number of digits used in the names
|
||||||
varies depending on the number of members in 'FILE'.
|
varies depending on the number of members in 'FILE'.
|
||||||
|
|
||||||
'-t'
|
'-t'
|
||||||
|
@ -253,17 +257,26 @@ File: lziprecover.info, Node: Repairing files, Next: Merging files, Prev: Inv
|
||||||
3 Repairing files
|
3 Repairing files
|
||||||
*****************
|
*****************
|
||||||
|
|
||||||
Lziprecover is usually able to repair files with small errors (up to one
|
Lziprecover can repair perfectly most files with small errors (up to one
|
||||||
byte error per member). The error may be located anywhere in the file
|
single-byte error per member), without the need of any extra redundance
|
||||||
except in the header (first 6 bytes of each member) or in the 'Member
|
at all. If the reparation is successful, the repaired file will be
|
||||||
size' field of the trailer (last 8 bytes of each member). This makes
|
identical bit for bit to the original.
|
||||||
lzip files resistant to bit-flip, one of the most common forms of data
|
|
||||||
corruption.
|
The error may be located anywhere in the file except in the header
|
||||||
|
(first 6 bytes of each member) or in the 'Member size' field of the
|
||||||
|
trailer (last 8 bytes of each member). This makes lzip files resistant
|
||||||
|
to bit-flip, one of the most common forms of data corruption.
|
||||||
|
|
||||||
Bit-flip happens when one bit in the file is changed from 0 to 1 or
|
Bit-flip happens when one bit in the file is changed from 0 to 1 or
|
||||||
vice versa. It may be caused by bad RAM or even by natural radiation. I
|
vice versa. It may be caused by bad RAM or even by natural radiation. I
|
||||||
have seen a case of bit-flip in a file stored on an USB flash drive.
|
have seen a case of bit-flip in a file stored on an USB flash drive.
|
||||||
|
|
||||||
|
One byte may seem small, but most file corruptions not produced by
|
||||||
|
I/O errors just affect one byte, or even one bit, of the file. Also,
|
||||||
|
unlike magnetic media, where errors usually affect a whole sector,
|
||||||
|
solid-state storage devices tend to produce single-byte errors, making
|
||||||
|
of lzip the perfect format for data stored on such devices.
|
||||||
|
|
||||||
Repairing a file can take some time. Small files or files with the
|
Repairing a file can take some time. Small files or files with the
|
||||||
error located near the beginning can be repaired in a few seconds. But
|
error located near the beginning can be repaired in a few seconds. But
|
||||||
repairing a large file compressed with a large dictionary size and with
|
repairing a large file compressed with a large dictionary size and with
|
||||||
|
@ -274,14 +287,14 @@ cause much more loss of data than errors located near the end. So
|
||||||
lziprecover repairs more efficiently the worst errors.
|
lziprecover repairs more efficiently the worst errors.
|
||||||
|
|
||||||
|
|
||||||
File: lziprecover.info, Node: Merging files, Next: File format, Prev: Repairing files, Up: Top
|
File: lziprecover.info, Node: Merging files, Next: File names, Prev: Repairing files, Up: Top
|
||||||
|
|
||||||
4 Merging files
|
4 Merging files
|
||||||
***************
|
***************
|
||||||
|
|
||||||
If you have several copies of a file but all of them are too damaged to
|
If you have several copies of a file but all of them are too damaged to
|
||||||
repair them (*note Repairing files::), lziprecover can try to produce a
|
repair them (*note Repairing files::), lziprecover can try to produce a
|
||||||
correct file merging the good parts of the damaged copies.
|
correct file by merging the good parts of the damaged copies.
|
||||||
|
|
||||||
The merge may succeed even if some copies of the file have all the
|
The merge may succeed even if some copies of the file have all the
|
||||||
headers and trailers damaged, as long as there is at least one copy of
|
headers and trailers damaged, as long as there is at least one copy of
|
||||||
|
@ -293,14 +306,14 @@ is damaged in all copies), or are adjacent and the boundary can't be
|
||||||
determined, or if the copies have too many damaged areas.
|
determined, or if the copies have too many damaged areas.
|
||||||
|
|
||||||
All the copies must have the same size. If some of them have been
|
All the copies must have the same size. If some of them have been
|
||||||
truncated and are therefore smaller than they should, you can extend
|
truncated and are therefore smaller than they should, they can be
|
||||||
them to the correct size with the following command before merging them
|
extended to the correct size with the following command before merging
|
||||||
with the other copies:
|
them with the other copies:
|
||||||
|
|
||||||
ddrescue --extend-outfile=<correct_size> small_file.lz extended_file.lz
|
ddrescue --extend-outfile=<correct_size> small_file.lz extended_file.lz
|
||||||
|
|
||||||
If some of the copies have got garbage data at the end and are
|
If some of the copies have got garbage data at the end and are
|
||||||
therefore larger than they should, you can reduce their sizes to the
|
therefore larger than they should, their sizes can be reduced to the
|
||||||
correct value with the following command before merging them with the
|
correct value with the following command before merging them with the
|
||||||
other copies:
|
other copies:
|
||||||
|
|
||||||
|
@ -311,12 +324,24 @@ each of them with one damaged area affecting 1 percent of the copy, the
|
||||||
probability of obtaining a correct file is about 98 percent. With three
|
probability of obtaining a correct file is about 98 percent. With three
|
||||||
such copies the probability rises to 99.97 percent. For large files (a
|
such copies the probability rises to 99.97 percent. For large files (a
|
||||||
few MB) with small errors (one sector damaged per copy), the probability
|
few MB) with small errors (one sector damaged per copy), the probability
|
||||||
approaches 100 percent even with only two copies.
|
approaches 100 percent even with only two copies. (Supposing that the
|
||||||
|
errors are randomly located inside each copy).
|
||||||
|
|
||||||
|
|
||||||
File: lziprecover.info, Node: File format, Next: Examples, Prev: Merging files, Up: Top
|
File: lziprecover.info, Node: File names, Next: File format, Prev: Merging files, Up: Top
|
||||||
|
|
||||||
5 File format
|
5 Names of the files produced by lziprecover
|
||||||
|
********************************************
|
||||||
|
|
||||||
|
The name of the fixed file produced by '--merge' and '--repair' is made
|
||||||
|
by appending the string '_fixed.lz' to the original file name. If the
|
||||||
|
original file name ends with one of the extensions '.tar.lz', '.lz' or
|
||||||
|
'.tlz', the string '_fixed' is inserted before the extension.
|
||||||
|
|
||||||
|
|
||||||
|
File: lziprecover.info, Node: File format, Next: Examples, Prev: File names, Up: Top
|
||||||
|
|
||||||
|
6 File format
|
||||||
*************
|
*************
|
||||||
|
|
||||||
Perfection is reached, not when there is no longer anything to add, but
|
Perfection is reached, not when there is no longer anything to add, but
|
||||||
|
@ -389,7 +414,7 @@ additional information before, between, or after them.
|
||||||
|
|
||||||
File: lziprecover.info, Node: Examples, Next: Unzcrash, Prev: File format, Up: Top
|
File: lziprecover.info, Node: Examples, Next: Unzcrash, Prev: File format, Up: Top
|
||||||
|
|
||||||
6 A small tutorial with examples
|
7 A small tutorial with examples
|
||||||
********************************
|
********************************
|
||||||
|
|
||||||
Example 1: Restore a regular file from its compressed version
|
Example 1: Restore a regular file from its compressed version
|
||||||
|
@ -460,7 +485,7 @@ correct file produced is saved in 'big_db_00001.lz'.
|
||||||
|
|
||||||
File: lziprecover.info, Node: Unzcrash, Next: Problems, Prev: Examples, Up: Top
|
File: lziprecover.info, Node: Unzcrash, Next: Problems, Prev: Examples, Up: Top
|
||||||
|
|
||||||
7 Testing the robustness of decompressors
|
8 Testing the robustness of decompressors
|
||||||
*****************************************
|
*****************************************
|
||||||
|
|
||||||
The lziprecover package also includes unzcrash, a program written to
|
The lziprecover package also includes unzcrash, a program written to
|
||||||
|
@ -476,9 +501,9 @@ memory accesses. If it does, please, report it as a bug.
|
||||||
Unzcrash really executes as a subprocess the shell command specified
|
Unzcrash really executes as a subprocess the shell command specified
|
||||||
in the first non-option argument, and then writes the file specified in
|
in the first non-option argument, and then writes the file specified in
|
||||||
the second non-option argument to the standard input of the subprocess,
|
the second non-option argument to the standard input of the subprocess,
|
||||||
modifying the corresponding byte each time. Therefore you can use
|
modifying the corresponding byte each time. Therefore unzcrash can be
|
||||||
unzcrash to test any decompressor (not only lzip), or even other decoder
|
used to test any decompressor (not only lzip), or even other decoder
|
||||||
programs with a suitable command line syntax.
|
programs having a suitable command line syntax.
|
||||||
|
|
||||||
The format for running unzcrash is:
|
The format for running unzcrash is:
|
||||||
|
|
||||||
|
@ -537,7 +562,7 @@ caused unzcrash to panic.
|
||||||
|
|
||||||
File: lziprecover.info, Node: Problems, Next: Concept index, Prev: Unzcrash, Up: Top
|
File: lziprecover.info, Node: Problems, Next: Concept index, Prev: Unzcrash, Up: Top
|
||||||
|
|
||||||
8 Reporting bugs
|
9 Reporting bugs
|
||||||
****************
|
****************
|
||||||
|
|
||||||
There are probably bugs in lziprecover. There are certainly errors and
|
There are probably bugs in lziprecover. There are certainly errors and
|
||||||
|
@ -561,6 +586,7 @@ Concept index
|
||||||
* bugs: Problems. (line 6)
|
* bugs: Problems. (line 6)
|
||||||
* examples: Examples. (line 6)
|
* examples: Examples. (line 6)
|
||||||
* file format: File format. (line 6)
|
* file format: File format. (line 6)
|
||||||
|
* file names: File names. (line 6)
|
||||||
* getting help: Problems. (line 6)
|
* getting help: Problems. (line 6)
|
||||||
* introduction: Introduction. (line 6)
|
* introduction: Introduction. (line 6)
|
||||||
* invoking: Invoking lziprecover. (line 6)
|
* invoking: Invoking lziprecover. (line 6)
|
||||||
|
@ -572,16 +598,17 @@ Concept index
|
||||||
|
|
||||||
Tag Table:
|
Tag Table:
|
||||||
Node: Top231
|
Node: Top231
|
||||||
Node: Introduction1077
|
Node: Introduction1153
|
||||||
Node: Invoking lziprecover4105
|
Node: Invoking lziprecover4249
|
||||||
Node: Repairing files9543
|
Node: Repairing files9686
|
||||||
Node: Merging files10733
|
Node: Merging files11371
|
||||||
Node: File format12504
|
Node: File names13212
|
||||||
Node: Examples15014
|
Node: File format13676
|
||||||
Ref: ddrescue-example16215
|
Node: Examples16183
|
||||||
Node: Unzcrash17324
|
Ref: ddrescue-example17384
|
||||||
Node: Problems19876
|
Node: Unzcrash18493
|
||||||
Node: Concept index20426
|
Node: Problems21047
|
||||||
|
Node: Concept index21597
|
||||||
|
|
||||||
End Tag Table
|
End Tag Table
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
@finalout
|
@finalout
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@set UPDATED 29 August 2014
|
@set UPDATED 16 October 2014
|
||||||
@set VERSION 1.16
|
@set VERSION 1.17-pre1
|
||||||
|
|
||||||
@dircategory Data Compression
|
@dircategory Data Compression
|
||||||
@direntry
|
@direntry
|
||||||
|
@ -39,6 +39,7 @@ This manual is for Lziprecover (version @value{VERSION}, @value{UPDATED}).
|
||||||
* Invoking lziprecover:: Command line interface
|
* Invoking lziprecover:: Command line interface
|
||||||
* Repairing files:: Fixing bit-flip and similar errors
|
* Repairing files:: Fixing bit-flip and similar errors
|
||||||
* Merging files:: Fixing several damaged copies
|
* Merging files:: Fixing several damaged copies
|
||||||
|
* File names:: Names of the files produced by lziprecover
|
||||||
* File format:: Detailed format of the compressed file
|
* File format:: Detailed format of the compressed file
|
||||||
* Examples:: A small tutorial with examples
|
* Examples:: A small tutorial with examples
|
||||||
* Unzcrash:: Testing the robustness of decompressors
|
* Unzcrash:: Testing the robustness of decompressors
|
||||||
|
@ -59,11 +60,13 @@ to copy, distribute and modify it.
|
||||||
|
|
||||||
Lziprecover is a data recovery tool and decompressor for files in the
|
Lziprecover is a data recovery tool and decompressor for files in the
|
||||||
lzip compressed data format (.lz), able to repair slightly damaged
|
lzip compressed data format (.lz), able to repair slightly damaged
|
||||||
files, recover badly damaged files from two or more copies, extract data
|
files, produce a correct file by merging the good parts of two or more
|
||||||
from damaged files, decompress files and test integrity of files.
|
damaged copies, extract data from damaged files, decompress files and
|
||||||
|
test integrity of files.
|
||||||
|
|
||||||
The lzip file format is designed for long-term data archiving, taking
|
The lzip file format is designed for data sharing and long-term
|
||||||
into account both data integrity and decoder availability:
|
archiving, taking into account both data integrity and decoder
|
||||||
|
availability:
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
|
@ -82,8 +85,8 @@ data from a lzip file long after quantum computers eventually render
|
||||||
LZMA obsolete.
|
LZMA obsolete.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Additionally lzip is copylefted, which guarantees that it will remain
|
Additionally the lzip reference implementation is copylefted, which
|
||||||
free forever.
|
guarantees that it will remain free forever.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
A nice feature of the lzip format is that a corrupt byte is easier to
|
A nice feature of the lzip format is that a corrupt byte is easier to
|
||||||
|
@ -196,7 +199,7 @@ information about the members in the file.
|
||||||
|
|
||||||
@item -m
|
@item -m
|
||||||
@itemx --merge
|
@itemx --merge
|
||||||
Try to produce a correct file merging the good parts of two or more
|
Try to produce a correct file by merging the good parts of two or more
|
||||||
damaged copies. If successful, a repaired copy is written to the file
|
damaged copies. If successful, a repaired copy is written to the file
|
||||||
@samp{@var{file}_fixed.lz}. The exit status is 0 if a correct file could
|
@samp{@var{file}_fixed.lz}. The exit status is 0 if a correct file could
|
||||||
be produced, 2 otherwise. See the chapter @samp{Merging files}
|
be produced, 2 otherwise. See the chapter @samp{Merging files}
|
||||||
|
@ -231,12 +234,12 @@ Search for members in @samp{@var{file}} and write each member in its own
|
||||||
integrity of the resulting files, decompress those which are undamaged,
|
integrity of the resulting files, decompress those which are undamaged,
|
||||||
and try to repair or partially decompress those which are damaged.
|
and try to repair or partially decompress those which are damaged.
|
||||||
|
|
||||||
The names of the files produced are in the form
|
The names of the files produced are in the form @samp{rec01@var{file}},
|
||||||
@samp{rec01@var{file}.lz}, @samp{rec02@var{file}.lz}, etc, and are
|
@samp{rec02@var{file}}, etc, and are designed so that the use of
|
||||||
designed so that the use of wildcards in subsequent processing, for
|
wildcards in subsequent processing, for example, @w{@samp{lziprecover
|
||||||
example, @w{@samp{lziprecover -cd rec*@var{file}.lz > recovered_data}},
|
-cd rec*@var{file} > recovered_data}}, processes the files in the
|
||||||
processes the files in the correct order. The number of digits used in
|
correct order. The number of digits used in the names varies depending
|
||||||
the names varies depending on the number of members in @samp{@var{file}}.
|
on the number of members in @samp{@var{file}}.
|
||||||
|
|
||||||
@item -t
|
@item -t
|
||||||
@itemx --test
|
@itemx --test
|
||||||
|
@ -282,17 +285,26 @@ caused lziprecover to panic.
|
||||||
@chapter Repairing files
|
@chapter Repairing files
|
||||||
@cindex repairing files
|
@cindex repairing files
|
||||||
|
|
||||||
Lziprecover is usually able to repair files with small errors (up to one
|
Lziprecover can repair perfectly most files with small errors (up to one
|
||||||
byte error per member). The error may be located anywhere in the file
|
single-byte error per member), without the need of any extra redundance
|
||||||
except in the header (first 6 bytes of each member) or in the
|
at all. If the reparation is successful, the repaired file will be
|
||||||
@samp{Member size} field of the trailer (last 8 bytes of each member).
|
identical bit for bit to the original.
|
||||||
This makes lzip files resistant to bit-flip, one of the most common
|
|
||||||
forms of data corruption.
|
The error may be located anywhere in the file except in the header
|
||||||
|
(first 6 bytes of each member) or in the @samp{Member size} field of the
|
||||||
|
trailer (last 8 bytes of each member). This makes lzip files resistant
|
||||||
|
to bit-flip, one of the most common forms of data corruption.
|
||||||
|
|
||||||
Bit-flip happens when one bit in the file is changed from 0 to 1 or vice
|
Bit-flip happens when one bit in the file is changed from 0 to 1 or vice
|
||||||
versa. It may be caused by bad RAM or even by natural radiation. I have
|
versa. It may be caused by bad RAM or even by natural radiation. I have
|
||||||
seen a case of bit-flip in a file stored on an USB flash drive.
|
seen a case of bit-flip in a file stored on an USB flash drive.
|
||||||
|
|
||||||
|
One byte may seem small, but most file corruptions not produced by I/O
|
||||||
|
errors just affect one byte, or even one bit, of the file. Also, unlike
|
||||||
|
magnetic media, where errors usually affect a whole sector, solid-state
|
||||||
|
storage devices tend to produce single-byte errors, making of lzip the
|
||||||
|
perfect format for data stored on such devices.
|
||||||
|
|
||||||
Repairing a file can take some time. Small files or files with the error
|
Repairing a file can take some time. Small files or files with the error
|
||||||
located near the beginning can be repaired in a few seconds. But
|
located near the beginning can be repaired in a few seconds. But
|
||||||
repairing a large file compressed with a large dictionary size and with
|
repairing a large file compressed with a large dictionary size and with
|
||||||
|
@ -309,7 +321,7 @@ repairs more efficiently the worst errors.
|
||||||
|
|
||||||
If you have several copies of a file but all of them are too damaged to
|
If you have several copies of a file but all of them are too damaged to
|
||||||
repair them (@pxref{Repairing files}), lziprecover can try to produce a
|
repair them (@pxref{Repairing files}), lziprecover can try to produce a
|
||||||
correct file merging the good parts of the damaged copies.
|
correct file by merging the good parts of the damaged copies.
|
||||||
|
|
||||||
The merge may succeed even if some copies of the file have all the
|
The merge may succeed even if some copies of the file have all the
|
||||||
headers and trailers damaged, as long as there is at least one copy of
|
headers and trailers damaged, as long as there is at least one copy of
|
||||||
|
@ -321,16 +333,16 @@ damaged in all copies), or are adjacent and the boundary can't be
|
||||||
determined, or if the copies have too many damaged areas.
|
determined, or if the copies have too many damaged areas.
|
||||||
|
|
||||||
All the copies must have the same size. If some of them have been
|
All the copies must have the same size. If some of them have been
|
||||||
truncated and are therefore smaller than they should, you can extend
|
truncated and are therefore smaller than they should, they can be
|
||||||
them to the correct size with the following command before merging them
|
extended to the correct size with the following command before merging
|
||||||
with the other copies:
|
them with the other copies:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
ddrescue --extend-outfile=<correct_size> small_file.lz extended_file.lz
|
ddrescue --extend-outfile=<correct_size> small_file.lz extended_file.lz
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
If some of the copies have got garbage data at the end and are therefore
|
If some of the copies have got garbage data at the end and are therefore
|
||||||
larger than they should, you can reduce their sizes to the correct value
|
larger than they should, their sizes can be reduced to the correct value
|
||||||
with the following command before merging them with the other copies:
|
with the following command before merging them with the other copies:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
|
@ -342,7 +354,19 @@ of them with one damaged area affecting 1 percent of the copy, the
|
||||||
probability of obtaining a correct file is about 98 percent. With three
|
probability of obtaining a correct file is about 98 percent. With three
|
||||||
such copies the probability rises to 99.97 percent. For large files (a
|
such copies the probability rises to 99.97 percent. For large files (a
|
||||||
few MB) with small errors (one sector damaged per copy), the probability
|
few MB) with small errors (one sector damaged per copy), the probability
|
||||||
approaches 100 percent even with only two copies.
|
approaches 100 percent even with only two copies. (Supposing that the
|
||||||
|
errors are randomly located inside each copy).
|
||||||
|
|
||||||
|
|
||||||
|
@node File names
|
||||||
|
@chapter Names of the files produced by lziprecover
|
||||||
|
@cindex file names
|
||||||
|
|
||||||
|
The name of the fixed file produced by @samp{--merge} and
|
||||||
|
@samp{--repair} is made by appending the string @samp{_fixed.lz} to the
|
||||||
|
original file name. If the original file name ends with one of the
|
||||||
|
extensions @samp{.tar.lz}, @samp{.lz} or @samp{.tlz}, the string
|
||||||
|
@samp{_fixed} is inserted before the extension.
|
||||||
|
|
||||||
|
|
||||||
@node File format
|
@node File format
|
||||||
|
@ -541,9 +565,9 @@ accesses. If it does, please, report it as a bug.
|
||||||
Unzcrash really executes as a subprocess the shell command specified in
|
Unzcrash really executes as a subprocess the shell command specified in
|
||||||
the first non-option argument, and then writes the file specified in the
|
the first non-option argument, and then writes the file specified in the
|
||||||
second non-option argument to the standard input of the subprocess,
|
second non-option argument to the standard input of the subprocess,
|
||||||
modifying the corresponding byte each time. Therefore you can use
|
modifying the corresponding byte each time. Therefore unzcrash can be
|
||||||
unzcrash to test any decompressor (not only lzip), or even other decoder
|
used to test any decompressor (not only lzip), or even other decoder
|
||||||
programs with a suitable command line syntax.
|
programs having a suitable command line syntax.
|
||||||
|
|
||||||
The format for running unzcrash is:
|
The format for running unzcrash is:
|
||||||
|
|
||||||
|
|
15
main.cc
15
main.cc
|
@ -92,7 +92,14 @@ bool delete_output_on_interrupt = false;
|
||||||
void show_help()
|
void show_help()
|
||||||
{
|
{
|
||||||
std::printf( "%s - Data recovery tool and decompressor for the lzip format.\n", Program_name );
|
std::printf( "%s - Data recovery tool and decompressor for the lzip format.\n", Program_name );
|
||||||
std::printf( "\nUsage: %s [options] [files]\n", invocation_name );
|
std::printf( "Lziprecover can repair perfectly most files with small errors (up to one\n"
|
||||||
|
"single-byte error per member), without the need of any extra redundance\n"
|
||||||
|
"at all. Losing an entire archive just because of a corrupt byte near the\n"
|
||||||
|
"beginning is a thing of the past.\n"
|
||||||
|
"Lziprecover can also produce a correct file by merging the good parts of\n"
|
||||||
|
"two or more damaged copies, extract data from damaged files, decompress\n"
|
||||||
|
"files and test integrity of files.\n"
|
||||||
|
"\nUsage: %s [options] [files]\n", invocation_name );
|
||||||
std::printf( "\nOptions:\n"
|
std::printf( "\nOptions:\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
" -V, --version output version information and exit\n"
|
" -V, --version output version information and exit\n"
|
||||||
|
@ -304,10 +311,12 @@ void close_and_set_permissions( const struct stat * const in_statsp )
|
||||||
|
|
||||||
std::string insert_fixed( std::string name )
|
std::string insert_fixed( std::string name )
|
||||||
{
|
{
|
||||||
if( name.size() > 4 && name.compare( name.size() - 4, 4, ".tlz" ) == 0 )
|
if( name.size() > 7 && name.compare( name.size() - 7, 7, ".tar.lz" ) == 0 )
|
||||||
name.insert( name.size() - 4, "_fixed" );
|
name.insert( name.size() - 7, "_fixed" );
|
||||||
else if( name.size() > 3 && name.compare( name.size() - 3, 3, ".lz" ) == 0 )
|
else if( name.size() > 3 && name.compare( name.size() - 3, 3, ".lz" ) == 0 )
|
||||||
name.insert( name.size() - 3, "_fixed" );
|
name.insert( name.size() - 3, "_fixed" );
|
||||||
|
else if( name.size() > 4 && name.compare( name.size() - 4, 4, ".tlz" ) == 0 )
|
||||||
|
name.insert( name.size() - 4, "_fixed" );
|
||||||
else name += "_fixed.lz";
|
else name += "_fixed.lz";
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
200
merge.cc
200
merge.cc
|
@ -78,18 +78,22 @@ void combine( std::vector< Block > & block_vector, std::vector< Block > & bv )
|
||||||
// positions in 'block_vector' are absolute file positions.
|
// positions in 'block_vector' are absolute file positions.
|
||||||
bool diff_member( const long long mpos, const long long msize,
|
bool diff_member( const long long mpos, const long long msize,
|
||||||
const std::vector< int > & infd_vector,
|
const std::vector< int > & infd_vector,
|
||||||
std::vector< Block > & block_vector )
|
std::vector< Block > & block_vector,
|
||||||
|
std::vector< int > & color_vector )
|
||||||
{
|
{
|
||||||
const int files = infd_vector.size();
|
const int files = infd_vector.size();
|
||||||
const int buffer_size = 65536;
|
const int buffer_size = 65536;
|
||||||
uint8_t * const buffer1 = new uint8_t[buffer_size];
|
uint8_t * const buffer1 = new uint8_t[buffer_size];
|
||||||
uint8_t * const buffer2 = new uint8_t[buffer_size];
|
uint8_t * const buffer2 = new uint8_t[buffer_size];
|
||||||
|
int next_color = 1;
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
for( int i1 = 0; i1 + 1 < files && !error; ++i1 )
|
for( int i1 = 0; i1 < files && !error; ++i1 )
|
||||||
{
|
{
|
||||||
for( int i2 = i1 + 1; i2 < files && !error; ++i2 )
|
for( int i2 = i1 + 1; i2 < files && !error; ++i2 )
|
||||||
{
|
{
|
||||||
|
if( color_vector[i1] != 0 && color_vector[i1] == color_vector[i2] )
|
||||||
|
continue;
|
||||||
std::vector< Block > bv;
|
std::vector< Block > bv;
|
||||||
long long partial_pos = 0;
|
long long partial_pos = 0;
|
||||||
const int fd1 = infd_vector[i1], fd2 = infd_vector[i2];
|
const int fd1 = infd_vector[i1], fd2 = infd_vector[i2];
|
||||||
|
@ -98,7 +102,7 @@ bool diff_member( const long long mpos, const long long msize,
|
||||||
if( !safe_seek( fd1, mpos ) || !safe_seek( fd2, mpos ) )
|
if( !safe_seek( fd1, mpos ) || !safe_seek( fd2, mpos ) )
|
||||||
{ error = true; break; }
|
{ error = true; break; }
|
||||||
|
|
||||||
while( msize > partial_pos )
|
while( partial_pos < msize )
|
||||||
{
|
{
|
||||||
const int size = std::min( (long long)buffer_size, msize - partial_pos );
|
const int size = std::min( (long long)buffer_size, msize - partial_pos );
|
||||||
const int rd = readblock( fd1, buffer1, size );
|
const int rd = readblock( fd1, buffer1, size );
|
||||||
|
@ -133,21 +137,32 @@ bool diff_member( const long long mpos, const long long msize,
|
||||||
Block b( mpos + begin, partial_pos - prev_equal - begin );
|
Block b( mpos + begin, partial_pos - prev_equal - begin );
|
||||||
bv.push_back( b );
|
bv.push_back( b );
|
||||||
}
|
}
|
||||||
|
if( bv.empty() ) // members are identical, set to same color
|
||||||
|
{
|
||||||
|
if( color_vector[i1] == 0 )
|
||||||
|
{
|
||||||
|
if( color_vector[i2] != 0 ) color_vector[i1] = color_vector[i2];
|
||||||
|
else color_vector[i1] = color_vector[i2] = next_color++;
|
||||||
|
}
|
||||||
|
else if( color_vector[i2] == 0 ) color_vector[i2] = color_vector[i1];
|
||||||
|
else internal_error( "different colors assigned to identical members." );
|
||||||
|
}
|
||||||
combine( block_vector, bv );
|
combine( block_vector, bv );
|
||||||
}
|
}
|
||||||
|
if( color_vector[i1] == 0 ) color_vector[i1] = next_color++;
|
||||||
}
|
}
|
||||||
delete[] buffer2; delete[] buffer1;
|
delete[] buffer2; delete[] buffer1;
|
||||||
return !error;
|
return !error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ipow( const unsigned base, const unsigned exponent )
|
long ipow( const unsigned base, const unsigned exponent )
|
||||||
{
|
{
|
||||||
unsigned result = 1;
|
unsigned long result = 1;
|
||||||
for( unsigned i = 0; i < exponent; ++i )
|
for( unsigned i = 0; i < exponent; ++i )
|
||||||
{
|
{
|
||||||
if( INT_MAX / base >= result ) result *= base;
|
if( LONG_MAX / base >= result ) result *= base;
|
||||||
else { result = INT_MAX; break; }
|
else { result = LONG_MAX; break; }
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -239,6 +254,116 @@ int open_input_files( const std::vector< std::string > & filenames,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool try_merge_member( const long long mpos, const long long msize,
|
||||||
|
const std::vector< Block > & block_vector,
|
||||||
|
const std::vector< int > & color_vector,
|
||||||
|
const std::vector< int > & infd_vector,
|
||||||
|
const std::string & output_filename,
|
||||||
|
const int outfd, const int verbosity )
|
||||||
|
{
|
||||||
|
const int blocks = block_vector.size();
|
||||||
|
const int files = infd_vector.size();
|
||||||
|
const long variations = ipow( files, blocks );
|
||||||
|
if( variations >= LONG_MAX )
|
||||||
|
{
|
||||||
|
if( files > 2 )
|
||||||
|
show_error( "Too many damaged blocks. Try merging fewer files." );
|
||||||
|
else
|
||||||
|
show_error( "Too many damaged blocks. Merging is not possible." );
|
||||||
|
cleanup_and_fail( output_filename, outfd, 2 );
|
||||||
|
}
|
||||||
|
int bi = 0; // block index
|
||||||
|
std::vector< int > file_idx( blocks, 0 ); // file to read each block from
|
||||||
|
|
||||||
|
while( bi >= 0 )
|
||||||
|
{
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
{
|
||||||
|
long var = 0;
|
||||||
|
for( int i = 0; i < blocks; ++i )
|
||||||
|
var = ( var * files ) + file_idx[i];
|
||||||
|
std::printf( "Trying variation %ld of %ld \r", var + 1, variations );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
while( bi < blocks )
|
||||||
|
{
|
||||||
|
const int infd = infd_vector[file_idx[bi]];
|
||||||
|
if( !safe_seek( infd, block_vector[bi].pos() ) ||
|
||||||
|
!safe_seek( outfd, block_vector[bi].pos() ) ||
|
||||||
|
!copy_file( infd, outfd, block_vector[bi].size() ) )
|
||||||
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
|
++bi;
|
||||||
|
}
|
||||||
|
if( !safe_seek( outfd, mpos ) )
|
||||||
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
|
long long failure_pos = 0;
|
||||||
|
if( try_decompress_member( outfd, msize, &failure_pos ) ) return true;
|
||||||
|
while( bi > 0 && mpos + failure_pos < block_vector[bi-1].pos() ) --bi;
|
||||||
|
while( --bi >= 0 )
|
||||||
|
{
|
||||||
|
while( ++file_idx[bi] < files )
|
||||||
|
{
|
||||||
|
const int color = color_vector[file_idx[bi]];
|
||||||
|
bool done = true;
|
||||||
|
for( int i = file_idx[bi] - 1; i >= 0; --i )
|
||||||
|
if( color_vector[i] == color ) { done = false; break; }
|
||||||
|
if( done ) break;
|
||||||
|
}
|
||||||
|
if( file_idx[bi] < files ) break;
|
||||||
|
file_idx[bi] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool try_merge_member1( const long long mpos, const long long msize,
|
||||||
|
const std::vector< Block > & block_vector,
|
||||||
|
const std::vector< int > & color_vector,
|
||||||
|
const std::vector< int > & infd_vector,
|
||||||
|
const std::string & output_filename,
|
||||||
|
const int outfd, const int verbosity )
|
||||||
|
{
|
||||||
|
if( block_vector.size() != 1 || block_vector[0].size() <= 1 ) return false;
|
||||||
|
const long long pos = block_vector[0].pos();
|
||||||
|
const long long size = block_vector[0].size();
|
||||||
|
const int files = infd_vector.size();
|
||||||
|
const int variations = files * ( files - 1 );
|
||||||
|
uint8_t byte;
|
||||||
|
|
||||||
|
for( int i1 = 0; i1 < files; ++i1 )
|
||||||
|
for( int i2 = 0; i2 < files; ++i2 )
|
||||||
|
{
|
||||||
|
if( i1 == i2 || color_vector[i1] == color_vector[i2] ) continue;
|
||||||
|
const int infd = infd_vector[i1];
|
||||||
|
if( !safe_seek( infd, pos ) ||
|
||||||
|
!safe_seek( infd_vector[i2], pos ) ||
|
||||||
|
!safe_seek( outfd, pos ) ||
|
||||||
|
!copy_file( infd_vector[i2], outfd, size ) )
|
||||||
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
|
const int var = ( i1 * ( files - 1 ) ) + i2 - ( i2 > i1 ) + 1;
|
||||||
|
for( long long i = 0; i < size; ++i )
|
||||||
|
{
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
{
|
||||||
|
std::printf( "Trying variation %d of %d, position %lld \r",
|
||||||
|
var, variations, pos + i );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
if( !safe_seek( outfd, pos + i ) ||
|
||||||
|
readblock( infd, &byte, 1 ) != 1 ||
|
||||||
|
writeblock( outfd, &byte, 1 ) != 1 ||
|
||||||
|
!safe_seek( outfd, mpos ) )
|
||||||
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
|
long long failure_pos = 0;
|
||||||
|
if( try_decompress_member( outfd, msize, &failure_pos ) ) return true;
|
||||||
|
if( mpos + failure_pos <= pos + i ) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -327,7 +452,8 @@ int merge_files( const std::vector< std::string > & filenames,
|
||||||
const long long msize = file_index.mblock( j ).size();
|
const long long msize = file_index.mblock( j ).size();
|
||||||
// vector of data blocks differing among the copies of the current member
|
// vector of data blocks differing among the copies of the current member
|
||||||
std::vector< Block > block_vector;
|
std::vector< Block > block_vector;
|
||||||
if( !diff_member( mpos, msize, infd_vector, block_vector ) ||
|
std::vector< int > color_vector( files, 0 );
|
||||||
|
if( !diff_member( mpos, msize, infd_vector, block_vector, color_vector ) ||
|
||||||
!safe_seek( outfd, mpos ) )
|
!safe_seek( outfd, mpos ) )
|
||||||
cleanup_and_fail( output_filename, outfd, 1 );
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
|
|
||||||
|
@ -335,63 +461,33 @@ int merge_files( const std::vector< std::string > & filenames,
|
||||||
{
|
{
|
||||||
if( file_index.members() > 1 && try_decompress_member( outfd, msize ) )
|
if( file_index.members() > 1 && try_decompress_member( outfd, msize ) )
|
||||||
continue;
|
continue;
|
||||||
show_error( "Input files are (partially) identical. Recovery is not possible." );
|
show_error( "Input files are (partially) identical. Merging is not possible." );
|
||||||
cleanup_and_fail( output_filename, outfd, 2 );
|
cleanup_and_fail( output_filename, outfd, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
const int size0 = block_vector[0].size();
|
|
||||||
const bool single_block = ( block_vector.size() == 1 );
|
|
||||||
if( ipow( files, block_vector.size() ) >= INT_MAX ||
|
|
||||||
( single_block && ipow( files, 2 ) >= INT_MAX / size0 ) )
|
|
||||||
{ show_error( "Input files are too damaged. Recovery is not possible." );
|
|
||||||
cleanup_and_fail( output_filename, outfd, 2 ); }
|
|
||||||
|
|
||||||
const int shifts = ( single_block && size0 > 1 ) ? size0 - 1 : 1;
|
|
||||||
if( single_block && size0 > 1 )
|
|
||||||
{
|
|
||||||
Block b( block_vector[0].pos() + 1, size0 - 1 );
|
|
||||||
block_vector[0].size( 1 );
|
|
||||||
block_vector.push_back( b );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( verbosity >= 1 && file_index.members() > 1 )
|
if( verbosity >= 1 && file_index.members() > 1 )
|
||||||
{
|
{
|
||||||
std::printf( "Merging member %ld\n", j + 1 );
|
std::printf( "Merging member %ld of %ld\n",
|
||||||
|
j + 1, (long)file_index.members() );
|
||||||
std::fflush( stdout );
|
std::fflush( stdout );
|
||||||
}
|
}
|
||||||
const int base_variations = ipow( files, block_vector.size() );
|
|
||||||
const int variations = base_variations * shifts;
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
for( int var = 0; var < variations; ++var )
|
if( file_index.members() > 1 || block_vector.size() > 1 )
|
||||||
{
|
{
|
||||||
if( verbosity >= 1 )
|
done = try_merge_member( mpos, msize, block_vector, color_vector,
|
||||||
{
|
infd_vector, output_filename, outfd, verbosity );
|
||||||
std::printf( "Trying variation %d of %d \r", var + 1, variations );
|
if( !done && verbosity >= 1 ) std::fputs( "\n", stdout );
|
||||||
std::fflush( stdout );
|
|
||||||
}
|
|
||||||
int tmp = var;
|
|
||||||
for( unsigned i = 0; i < block_vector.size(); ++i )
|
|
||||||
{
|
|
||||||
const int infd = infd_vector[tmp % files];
|
|
||||||
tmp /= files;
|
|
||||||
if( !safe_seek( infd, block_vector[i].pos() ) ||
|
|
||||||
!safe_seek( outfd, block_vector[i].pos() ) ||
|
|
||||||
!copy_file( infd, outfd, block_vector[i].size() ) )
|
|
||||||
cleanup_and_fail( output_filename, outfd, 1 );
|
|
||||||
}
|
|
||||||
if( !safe_seek( outfd, mpos ) )
|
|
||||||
cleanup_and_fail( output_filename, outfd, 1 );
|
|
||||||
if( try_decompress_member( outfd, msize ) )
|
|
||||||
{ done = true; break; }
|
|
||||||
if( var > 0 && var % base_variations == 0 )
|
|
||||||
block_vector[0].shift( block_vector[1] );
|
|
||||||
}
|
}
|
||||||
if( verbosity >= 1 ) std::printf( "\n" );
|
if( !done )
|
||||||
|
done = try_merge_member1( mpos, msize, block_vector, color_vector,
|
||||||
|
infd_vector, output_filename, outfd, verbosity );
|
||||||
|
if( verbosity >= 1 ) std::fputs( "\n", stdout );
|
||||||
if( !done )
|
if( !done )
|
||||||
{
|
{
|
||||||
if( verbosity >= 2 )
|
if( verbosity >= 2 )
|
||||||
for( unsigned i = 0; i < block_vector.size(); ++i )
|
for( unsigned i = 0; i < block_vector.size(); ++i )
|
||||||
std::fprintf( stderr, "area %2d from offset %6lld to %6lld\n", i + 1,
|
std::fprintf( stderr, "area %2d from position %6lld to %6lld\n", i + 1,
|
||||||
block_vector[i].pos(), block_vector[i].end() - 1 );
|
block_vector[i].pos(), block_vector[i].end() - 1 );
|
||||||
show_error( "Some error areas overlap. Can't recover input file." );
|
show_error( "Some error areas overlap. Can't recover input file." );
|
||||||
cleanup_and_fail( output_filename, outfd, 2 );
|
cleanup_and_fail( output_filename, outfd, 2 );
|
||||||
|
@ -404,6 +500,6 @@ int merge_files( const std::vector< std::string > & filenames,
|
||||||
cleanup_and_fail( output_filename, -1, 1 );
|
cleanup_and_fail( output_filename, -1, 1 );
|
||||||
}
|
}
|
||||||
if( verbosity >= 1 )
|
if( verbosity >= 1 )
|
||||||
std::printf( "Input files merged successfully.\n" );
|
std::fputs( "Input files merged successfully.\n", stdout );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
12
repair.cc
12
repair.cc
|
@ -71,8 +71,8 @@ int repair_file( const std::string & input_filename,
|
||||||
|
|
||||||
if( verbosity >= 1 ) // damaged member found
|
if( verbosity >= 1 ) // damaged member found
|
||||||
{
|
{
|
||||||
std::printf( "Repairing member %ld (failure pos = %llu)\n",
|
std::printf( "Repairing member %ld of %ld (failure pos = %llu)\n",
|
||||||
i + 1, mpos + failure_pos );
|
i + 1, (long)file_index.members(), mpos + failure_pos );
|
||||||
std::fflush( stdout );
|
std::fflush( stdout );
|
||||||
}
|
}
|
||||||
uint8_t * const mbuffer = read_member( infd, mpos, msize );
|
uint8_t * const mbuffer = read_member( infd, mpos, msize );
|
||||||
|
@ -80,7 +80,7 @@ int repair_file( const std::string & input_filename,
|
||||||
cleanup_and_fail( output_filename, outfd, 1 );
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
long pos = failure_pos;
|
long pos = failure_pos;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
while( pos >= File_header::size && pos > failure_pos - 20000 && !done )
|
while( pos >= File_header::size && pos > failure_pos - 40000 && !done )
|
||||||
{
|
{
|
||||||
const long min_pos = std::max( (long)File_header::size, pos - 1000 );
|
const long min_pos = std::max( (long)File_header::size, pos - 1000 );
|
||||||
const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 );
|
const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 );
|
||||||
|
@ -118,7 +118,7 @@ int repair_file( const std::string & input_filename,
|
||||||
delete master;
|
delete master;
|
||||||
}
|
}
|
||||||
delete[] mbuffer;
|
delete[] mbuffer;
|
||||||
if( verbosity >= 1 ) std::printf( "\n" );
|
if( verbosity >= 1 ) std::fputs( "\n", stdout );
|
||||||
if( !done )
|
if( !done )
|
||||||
{
|
{
|
||||||
show_error( "Can't repair input file. Error is probably larger than 1 byte." );
|
show_error( "Can't repair input file. Error is probably larger than 1 byte." );
|
||||||
|
@ -129,7 +129,7 @@ int repair_file( const std::string & input_filename,
|
||||||
if( outfd < 0 )
|
if( outfd < 0 )
|
||||||
{
|
{
|
||||||
if( verbosity >= 1 )
|
if( verbosity >= 1 )
|
||||||
std::printf( "Input file has no errors. Recovery is not needed.\n" );
|
std::fputs( "Input file has no errors. Recovery is not needed.\n", stdout );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( close( outfd ) != 0 )
|
if( close( outfd ) != 0 )
|
||||||
|
@ -138,6 +138,6 @@ int repair_file( const std::string & input_filename,
|
||||||
cleanup_and_fail( output_filename, -1, 1 );
|
cleanup_and_fail( output_filename, -1, 1 );
|
||||||
}
|
}
|
||||||
if( verbosity >= 1 )
|
if( verbosity >= 1 )
|
||||||
std::printf( "Copy of input file repaired successfully.\n" );
|
std::fputs( "Copy of input file repaired successfully.\n", stdout );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
5
split.cc
5
split.cc
|
@ -43,9 +43,8 @@ void first_filename( const std::string & input_filename,
|
||||||
output_filename = input_filename;
|
output_filename = input_filename;
|
||||||
int b = output_filename.size();
|
int b = output_filename.size();
|
||||||
while( b > 0 && output_filename[b-1] != '/' ) --b;
|
while( b > 0 && output_filename[b-1] != '/' ) --b;
|
||||||
output_filename.insert( b, 1, '1' );
|
output_filename.insert( b, "rec1" );
|
||||||
if( max_digits > 1 ) output_filename.insert( b, max_digits - 1, '0' );
|
if( max_digits > 1 ) output_filename.insert( b + 3, max_digits - 1, '0' );
|
||||||
output_filename.insert( b, "rec" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ fail=0
|
||||||
# fox5_bad3.lz: [100-299] --> zeroed;
|
# fox5_bad3.lz: [100-299] --> zeroed;
|
||||||
# fox5_bad4.lz: [250-349] --> zeroed;
|
# fox5_bad4.lz: [250-349] --> zeroed;
|
||||||
# fox5_bad5.lz: [300-399] --> zeroed;
|
# fox5_bad5.lz: [300-399] --> zeroed;
|
||||||
# test_bad1.lz: byte at offset 67 changed from 0x70 to 0x79
|
# test_bad1.lz: byte at offset 66 changed from 0xA6 to 0x46
|
||||||
# test_bad2.lz: [ 34- 65] --> copy of bytes [ 68- 99]
|
# test_bad2.lz: [ 34- 65] --> copy of bytes [ 68- 99]
|
||||||
# test_bad3.lz: [ 512-1535] --> zeroed; [2560-3583] --> zeroed
|
# test_bad3.lz: [ 512-1535] --> zeroed; [2560-3583] --> zeroed
|
||||||
# test_bad4.lz: [3072-4095] --> random data; [4608-5631] --> zeroed
|
# test_bad4.lz: [3072-4095] --> random data; [4608-5631] --> zeroed
|
||||||
|
@ -180,6 +180,24 @@ cmp "${in_lz}" copy.lz || fail=1
|
||||||
cmp "${in_lz}" copy.lz || fail=1
|
cmp "${in_lz}" copy.lz || fail=1
|
||||||
printf .
|
printf .
|
||||||
|
|
||||||
|
cat "${bad1_lz}" "${in_lz}" "${bad1_lz}" "${bad1_lz}" > bad11.lz || framework_failure
|
||||||
|
cat "${bad1_lz}" "${in_lz}" "${bad2_lz}" "${in_lz}" > bad12.lz || framework_failure
|
||||||
|
cat "${bad2_lz}" "${in_lz}" "${bad2_lz}" "${bad2_lz}" > bad22.lz || framework_failure
|
||||||
|
cat "${in_lz}" "${in_lz}" "${in_lz}" "${in_lz}" > copy4.lz || framework_failure
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad11.lz bad12.lz bad22.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad11.lz bad22.lz bad12.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad12.lz bad11.lz bad22.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad12.lz bad22.lz bad11.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad22.lz bad11.lz bad12.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad22.lz bad12.lz bad11.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
printf .
|
||||||
|
|
||||||
for i in "${bad1_lz}" "${bad2_lz}" ; do
|
for i in "${bad1_lz}" "${bad2_lz}" ; do
|
||||||
for j in "${bad3_lz}" "${bad4_lz}" "${bad5_lz}" ; do
|
for j in "${bad3_lz}" "${bad4_lz}" "${bad5_lz}" ; do
|
||||||
"${LZIPRECOVER}" -mf -o copy.lz "${i}" "${j}" || fail=1
|
"${LZIPRECOVER}" -mf -o copy.lz "${i}" "${j}" || fail=1
|
||||||
|
@ -209,6 +227,24 @@ printf .
|
||||||
cmp "${in_lz}" copy.lz || fail=1
|
cmp "${in_lz}" copy.lz || fail=1
|
||||||
printf .
|
printf .
|
||||||
|
|
||||||
|
cat "${bad3_lz}" "${bad4_lz}" "${bad5_lz}" "${in_lz}" > bad345.lz || framework_failure
|
||||||
|
cat "${bad4_lz}" "${bad5_lz}" "${bad3_lz}" "${in_lz}" > bad453.lz || framework_failure
|
||||||
|
cat "${bad5_lz}" "${bad3_lz}" "${bad4_lz}" "${in_lz}" > bad534.lz || framework_failure
|
||||||
|
cat "${in_lz}" "${in_lz}" "${in_lz}" "${in_lz}" > copy4.lz || framework_failure
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad345.lz bad453.lz bad534.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad345.lz bad534.lz bad453.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad453.lz bad345.lz bad534.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad453.lz bad534.lz bad345.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad534.lz bad345.lz bad453.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
"${LZIPRECOVER}" -mf -o out4.lz bad534.lz bad453.lz bad345.lz || fail=1
|
||||||
|
cmp out4.lz copy4.lz || fail=1
|
||||||
|
printf .
|
||||||
|
|
||||||
rm -f copy.lz
|
rm -f copy.lz
|
||||||
"${LZIPRECOVER}" -R -o copy.lz "${fox5_lz}" || fail=1
|
"${LZIPRECOVER}" -R -o copy.lz "${fox5_lz}" || fail=1
|
||||||
if [ $? = 0 ] && [ ! -e copy.lz ] ; then printf . ; else printf - ; fail=1 ; fi
|
if [ $? = 0 ] && [ ! -e copy.lz ] ; then printf . ; else printf - ; fail=1 ; fi
|
||||||
|
@ -220,6 +256,16 @@ cmp "${fox5_lz}" copy.lz || fail=1
|
||||||
cmp "${in_lz}" copy.lz || fail=1
|
cmp "${in_lz}" copy.lz || fail=1
|
||||||
printf .
|
printf .
|
||||||
|
|
||||||
|
cat "${f5b1_lz}" > copy.tar.lz || framework_failure
|
||||||
|
"${LZIPRECOVER}" -R copy.tar.lz || fail=1
|
||||||
|
if [ $? = 0 ] && [ -e copy_fixed.tar.lz ] ; then printf . ; else printf - ; fail=1 ; fi
|
||||||
|
mv copy.tar.lz copy.lz || framework_failure
|
||||||
|
"${LZIPRECOVER}" -R copy.lz || fail=1
|
||||||
|
if [ $? = 0 ] && [ -e copy_fixed.lz ] ; then printf . ; else printf - ; fail=1 ; fi
|
||||||
|
mv copy.lz copy.tlz || framework_failure
|
||||||
|
"${LZIPRECOVER}" -R copy.tlz || fail=1
|
||||||
|
if [ $? = 0 ] && [ -e copy_fixed.tlz ] ; then printf . ; else printf - ; fail=1 ; fi
|
||||||
|
|
||||||
cat "${in_lz}" "${in_lz}" "${in_lz}" > copy || framework_failure
|
cat "${in_lz}" "${in_lz}" "${in_lz}" > copy || framework_failure
|
||||||
printf "garbage" >> copy || fail=1
|
printf "garbage" >> copy || fail=1
|
||||||
"${LZIPRECOVER}" -s -o copy.lz copy || fail=1
|
"${LZIPRECOVER}" -s -o copy.lz copy || fail=1
|
||||||
|
|
Binary file not shown.
|
@ -33,7 +33,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../arg_parser.h"
|
#include "arg_parser.h"
|
||||||
|
|
||||||
#if CHAR_BIT != 8
|
#if CHAR_BIT != 8
|
||||||
#error "Environments where CHAR_BIT != 8 are not supported."
|
#error "Environments where CHAR_BIT != 8 are not supported."
|
||||||
|
@ -209,18 +209,18 @@ public:
|
||||||
std::fflush( stderr );
|
std::fflush( stderr );
|
||||||
int c = 0;
|
int c = 0;
|
||||||
for( int i = 0; i < 8; ++i ) if( data[i] ) ++c;
|
for( int i = 0; i < 8; ++i ) if( data[i] ) ++c;
|
||||||
if( c == 8 ) std::printf( "Testing full byte.\n" );
|
if( c == 8 ) std::fputs( "Testing full byte.\n", stdout );
|
||||||
else if( c == 0 ) std::printf( "Nothing to test.\n" );
|
else if( c == 0 ) std::fputs( "Nothing to test.\n", stdout );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::printf( "Testing " );
|
std::fputs( "Testing ", stdout );
|
||||||
for( int i = 0; i < 8; ++i )
|
for( int i = 0; i < 8; ++i )
|
||||||
if( data[i] )
|
if( data[i] )
|
||||||
{
|
{
|
||||||
std::printf( "%d", i + 1 );
|
std::printf( "%d", i + 1 );
|
||||||
if( --c ) std::printf( "," );
|
if( --c ) std::fputs( ",", stdout );
|
||||||
}
|
}
|
||||||
std::printf( " bit errors.\n" );
|
std::fputs( " bit errors.\n", stdout );
|
||||||
}
|
}
|
||||||
std::fflush( stdout );
|
std::fflush( stdout );
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ int differing_bits( const uint8_t byte1, const uint8_t byte2 )
|
||||||
|
|
||||||
int main( const int argc, const char * const argv[] )
|
int main( const int argc, const char * const argv[] )
|
||||||
{
|
{
|
||||||
enum { buffer_size = 3 << 20 };
|
enum { buffer_size = 75 << 20 };
|
||||||
Bitset8 bits; // if Bitset8::parse not called test full byte
|
Bitset8 bits; // if Bitset8::parse not called test full byte
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int max_size = buffer_size;
|
int max_size = buffer_size;
|
||||||
|
@ -330,18 +330,21 @@ int main( const int argc, const char * const argv[] )
|
||||||
if( verbosity >= 0 )
|
if( verbosity >= 0 )
|
||||||
std::fprintf( stderr, "byte %d\n", i );
|
std::fprintf( stderr, "byte %d\n", i );
|
||||||
const uint8_t byte = buffer[i];
|
const uint8_t byte = buffer[i];
|
||||||
for( int j = 0; j < 255; ++j )
|
for( int j = 1; j < 256; ++j )
|
||||||
{
|
{
|
||||||
++buffer[i];
|
++buffer[i];
|
||||||
if( bits.includes( differing_bits( byte, buffer[i] ) ) )
|
if( bits.includes( differing_bits( byte, buffer[i] ) ) )
|
||||||
{
|
{
|
||||||
|
if( verbosity >= 2 )
|
||||||
|
std::fprintf( stderr, "0x%02X (0x%02X+0x%02X) ",
|
||||||
|
buffer[i], byte, j );
|
||||||
f = popen( parser.argument( argind ).c_str(), "w" );
|
f = popen( parser.argument( argind ).c_str(), "w" );
|
||||||
if( !f )
|
if( !f )
|
||||||
{ show_error( "Can't open pipe", errno ); return 1; }
|
{ show_error( "Can't open pipe", errno ); return 1; }
|
||||||
std::fwrite( buffer, 1, size, f );
|
std::fwrite( buffer, 1, size, f );
|
||||||
if( pclose( f ) == 0 && verbosity >= 0 )
|
if( pclose( f ) == 0 && verbosity >= 0 )
|
||||||
std::fprintf( stderr, "0x%02X (0x%02X+0x%02X) passed the test\n",
|
std::fprintf( stderr, "0x%02X (0x%02X+0x%02X) passed the test\n",
|
||||||
buffer[i], byte, j + 1 );
|
buffer[i], byte, j );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer[i] = byte;
|
buffer[i] = byte;
|
Loading…
Add table
Reference in a new issue