Merging upstream version 1.17~rc1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
97763bf5de
commit
3574ba518d
27 changed files with 624 additions and 240 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,7 +1,14 @@
|
||||||
|
2015-01-21 Antonio Diaz Diaz <antonio@gnu.org>
|
||||||
|
|
||||||
|
* Version 1.17-rc1 released.
|
||||||
|
* repair.cc: Repair time has been reduced by 15%.
|
||||||
|
* Added new option '-y, --debug-delay'.
|
||||||
|
* Added new option '-z, --debug-repair'.
|
||||||
|
|
||||||
2014-10-16 Antonio Diaz Diaz <antonio@gnu.org>
|
2014-10-16 Antonio Diaz Diaz <antonio@gnu.org>
|
||||||
|
|
||||||
* Version 1.17-pre1 released.
|
* Version 1.17-pre1 released.
|
||||||
* merge.cc: New block selection algorithm makes merge much faster.
|
* New block selection algorithm makes merge up to 100 times faster.
|
||||||
* Makefile.in: Added new targets 'install*-compress'.
|
* Makefile.in: Added new targets 'install*-compress'.
|
||||||
* testsuite/unzcrash.cc: Moved to top directory.
|
* testsuite/unzcrash.cc: Moved to top directory.
|
||||||
* Added chapter 'File names' to the manual.
|
* Added chapter 'File names' to the manual.
|
||||||
|
@ -9,7 +16,7 @@
|
||||||
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.
|
||||||
* New class LZ_mtester makes repair much faster.
|
* New class LZ_mtester makes repair up to 10 times faster.
|
||||||
* main.cc (close_and_set_permissions): Behave like 'cp -p'.
|
* main.cc (close_and_set_permissions): Behave like 'cp -p'.
|
||||||
* lziprecover.texinfo: Renamed to lziprecover.texi.
|
* lziprecover.texinfo: Renamed to lziprecover.texi.
|
||||||
* License changed to GPL version 2 or later.
|
* License changed to GPL version 2 or later.
|
||||||
|
@ -99,7 +106,7 @@
|
||||||
* testsuite/unzcrash.cc: Test all 1-byte errors.
|
* testsuite/unzcrash.cc: Test all 1-byte errors.
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This file is a collection of facts, and thus it is not copyrightable,
|
This file is a collection of facts, and thus it is not copyrightable,
|
||||||
but just in case, you have unlimited permission to copy, distribute and
|
but just in case, you have unlimited permission to copy, distribute and
|
||||||
|
|
2
INSTALL
2
INSTALL
|
@ -62,7 +62,7 @@ After running 'configure', you can run 'make' and 'make install' as
|
||||||
explained above.
|
explained above.
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This file is free documentation: you have unlimited permission to copy,
|
This file is free documentation: you have unlimited permission to copy,
|
||||||
distribute and modify it.
|
distribute and modify it.
|
||||||
|
|
17
Makefile.in
17
Makefile.in
|
@ -6,8 +6,8 @@ INSTALL_DATA = $(INSTALL) -m 644
|
||||||
INSTALL_DIR = $(INSTALL) -d -m 755
|
INSTALL_DIR = $(INSTALL) -d -m 755
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
objs = arg_parser.o file_index.o merge.o mtester.o range_dec.o repair.o \
|
objs = arg_parser.o block.o file_index.o merge.o mtester.o range_dec.o \
|
||||||
split.o decoder.o main.o
|
repair.o split.o decoder.o main.o
|
||||||
unzobjs = arg_parser.o unzcrash.o
|
unzobjs = arg_parser.o unzcrash.o
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,14 +36,15 @@ unzcrash.o : unzcrash.cc
|
||||||
|
|
||||||
$(objs) : Makefile
|
$(objs) : Makefile
|
||||||
arg_parser.o : arg_parser.h
|
arg_parser.o : arg_parser.h
|
||||||
|
block.o : block.h
|
||||||
decoder.o : lzip.h decoder.h
|
decoder.o : lzip.h decoder.h
|
||||||
file_index.o : lzip.h file_index.h
|
file_index.o : lzip.h block.h file_index.h
|
||||||
main.o : arg_parser.h lzip.h decoder.h
|
main.o : arg_parser.h lzip.h decoder.h block.h
|
||||||
merge.o : lzip.h decoder.h file_index.h
|
merge.o : lzip.h decoder.h block.h file_index.h
|
||||||
mtester.o : lzip.h mtester.h
|
mtester.o : lzip.h mtester.h
|
||||||
range_dec.o : lzip.h decoder.h file_index.h
|
range_dec.o : lzip.h decoder.h block.h file_index.h
|
||||||
repair.o : lzip.h file_index.h mtester.h
|
repair.o : lzip.h mtester.h block.h file_index.h
|
||||||
split.o : lzip.h
|
split.o : lzip.h block.h file_index.h
|
||||||
unzcrash.o : arg_parser.h Makefile
|
unzcrash.o : arg_parser.h Makefile
|
||||||
|
|
||||||
|
|
||||||
|
|
8
NEWS
8
NEWS
|
@ -6,6 +6,14 @@ magnitude faster depending on number of files and number of errors.
|
||||||
Please, report as a bug any files correctly merged by lziprecover 1.16
|
Please, report as a bug any files correctly merged by lziprecover 1.16
|
||||||
that this version can't merge.
|
that this version can't merge.
|
||||||
|
|
||||||
|
Repair time has been reduced by 15%.
|
||||||
|
|
||||||
|
The new option "-y, --debug-delay", which finds the max error detection
|
||||||
|
delay in a given range of positions, has been added.
|
||||||
|
|
||||||
|
The new option "-z, --debug-repair", which test repairs a one-byte error
|
||||||
|
at a given position, has been added.
|
||||||
|
|
||||||
The targets "install-compress", "install-strip-compress",
|
The targets "install-compress", "install-strip-compress",
|
||||||
"install-info-compress" and "install-man-compress" have been added to
|
"install-info-compress" and "install-man-compress" have been added to
|
||||||
the Makefile.
|
the Makefile.
|
||||||
|
|
2
README
2
README
|
@ -75,7 +75,7 @@ unzcrash.c from Julian Seward's bzip2. Type 'make unzcrash' in the
|
||||||
lziprecover source directory to build it. Then try 'unzcrash --help'.
|
lziprecover source directory to build it. Then try 'unzcrash --help'.
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This file is free documentation: you have unlimited permission to copy,
|
This file is free documentation: you have unlimited permission to copy,
|
||||||
distribute and modify it.
|
distribute and modify it.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||||
Copyright (C) 2006-2014 Antonio Diaz Diaz.
|
Copyright (C) 2006-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This library is free software: you can redistribute it and/or modify
|
This library 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
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||||
Copyright (C) 2006-2014 Antonio Diaz Diaz.
|
Copyright (C) 2006-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This library is free software: you can redistribute it and/or modify
|
This library 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
|
||||||
|
|
33
block.cc
Normal file
33
block.cc
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "block.h"
|
||||||
|
|
||||||
|
|
||||||
|
Block Block::split( const long long pos )
|
||||||
|
{
|
||||||
|
if( pos > pos_ && pos < end() )
|
||||||
|
{
|
||||||
|
const Block b( pos_, pos - pos_ );
|
||||||
|
pos_ = pos; size_ -= b.size_;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
return Block( 0, 0 );
|
||||||
|
}
|
62
block.h
Normal file
62
block.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INT64_MAX
|
||||||
|
#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class Block
|
||||||
|
{
|
||||||
|
long long pos_, size_; // pos + size <= INT64_MAX
|
||||||
|
|
||||||
|
public:
|
||||||
|
Block( const long long p, const long long s ) : pos_( p ), size_( s ) {}
|
||||||
|
|
||||||
|
long long pos() const { return pos_; }
|
||||||
|
long long size() const { return size_; }
|
||||||
|
long long end() const { return pos_ + size_; }
|
||||||
|
|
||||||
|
void pos( const long long p ) { pos_ = p; }
|
||||||
|
void size( const long long s ) { size_ = s; }
|
||||||
|
|
||||||
|
bool operator==( const Block & b ) const
|
||||||
|
{ return pos_ == b.pos_ && size_ == b.size_; }
|
||||||
|
bool operator!=( const Block & b ) const
|
||||||
|
{ return pos_ != b.pos_ || size_ != b.size_; }
|
||||||
|
|
||||||
|
bool operator<( const Block & b ) const { return pos_ < b.pos_; }
|
||||||
|
|
||||||
|
bool includes( const long long pos ) const
|
||||||
|
{ return ( pos_ <= pos && end() > pos ); }
|
||||||
|
bool overlaps( const Block & b ) const
|
||||||
|
{ return ( pos_ < b.end() && b.pos_ < end() ); }
|
||||||
|
|
||||||
|
void shift( Block & b ) { ++size_; ++b.pos_; --b.size_; }
|
||||||
|
Block split( const long long pos );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// defined in range_dec.cc
|
||||||
|
int range_decompress( const std::string & input_filename,
|
||||||
|
const std::string & output_filename,
|
||||||
|
Block range, const int verbosity, const bool force,
|
||||||
|
const bool ignore, const bool to_stdout );
|
||||||
|
|
||||||
|
// defined in repair.cc
|
||||||
|
int debug_delay( const std::string & input_filename, Block range,
|
||||||
|
const int verbosity );
|
6
configure
vendored
6
configure
vendored
|
@ -1,12 +1,12 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# configure script for Lziprecover - Data recovery tool for the lzip format
|
# configure script for Lziprecover - Data recovery tool for the lzip format
|
||||||
# Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
# Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
#
|
#
|
||||||
# This configure script is free software: you have unlimited permission
|
# This configure script is free software: you have unlimited permission
|
||||||
# to copy, distribute and modify it.
|
# to copy, distribute and modify it.
|
||||||
|
|
||||||
pkgname=lziprecover
|
pkgname=lziprecover
|
||||||
pkgversion=1.17-pre1
|
pkgversion=1.17-rc1
|
||||||
progname=lziprecover
|
progname=lziprecover
|
||||||
srctrigger=doc/${pkgname}.texi
|
srctrigger=doc/${pkgname}.texi
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ echo "LDFLAGS = ${LDFLAGS}"
|
||||||
rm -f Makefile
|
rm -f Makefile
|
||||||
cat > Makefile << EOF
|
cat > Makefile << EOF
|
||||||
# Makefile for Lziprecover - Data recovery tool for the lzip format
|
# Makefile for Lziprecover - Data recovery tool for the lzip format
|
||||||
# Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
# Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
# This file was generated automatically by configure. Do not edit.
|
# This file was generated automatically by configure. Do not edit.
|
||||||
#
|
#
|
||||||
# This Makefile is free software: you have unlimited permission
|
# This Makefile is free software: you have unlimited permission
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
|
|
@ -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" "October 2014" "lziprecover 1.17-pre1" "User Commands"
|
.TH LZIPRECOVER "1" "January 2015" "lziprecover 1.17-rc1" "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,7 @@ 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.
|
||||||
|
.PP
|
||||||
Lziprecover can repair perfectly most files with small errors (up to one
|
Lziprecover can repair perfectly most files with small errors (up to one
|
||||||
single\-byte error per member), without the need of any extra redundance
|
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
|
at all. Losing an entire archive just because of a corrupt byte near the
|
||||||
|
@ -76,7 +77,7 @@ Report bugs to lzip\-bug@nongnu.org
|
||||||
.br
|
.br
|
||||||
Lziprecover home page: http://www.nongnu.org/lzip/lziprecover.html
|
Lziprecover home page: http://www.nongnu.org/lzip/lziprecover.html
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2014 Antonio Diaz Diaz.
|
Copyright \(co 2015 Antonio Diaz Diaz.
|
||||||
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
|
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
|
||||||
.br
|
.br
|
||||||
This is free software: you are free to change and redistribute it.
|
This is free software: you are free to change and redistribute it.
|
||||||
|
|
|
@ -12,12 +12,13 @@ File: lziprecover.info, Node: Top, Next: Introduction, Up: (dir)
|
||||||
Lziprecover Manual
|
Lziprecover Manual
|
||||||
******************
|
******************
|
||||||
|
|
||||||
This manual is for Lziprecover (version 1.17-pre1, 16 October 2014).
|
This manual is for Lziprecover (version 1.17-rc1, 21 January 2015).
|
||||||
|
|
||||||
* Menu:
|
* Menu:
|
||||||
|
|
||||||
* Introduction:: Purpose and features of lziprecover
|
* Introduction:: Purpose and features of lziprecover
|
||||||
* Invoking lziprecover:: Command line interface
|
* Invoking lziprecover:: Command line interface
|
||||||
|
* Data safety:: Protecting data from accidental loss
|
||||||
* 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 names:: Names of the files produced by lziprecover
|
||||||
|
@ -28,7 +29,7 @@ This manual is for Lziprecover (version 1.17-pre1, 16 October 2014).
|
||||||
* Concept index:: Index of concepts
|
* Concept index:: Index of concepts
|
||||||
|
|
||||||
|
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This manual is free documentation: you have unlimited permission to
|
This manual is free documentation: you have unlimited permission to
|
||||||
copy, distribute and modify it.
|
copy, distribute and modify it.
|
||||||
|
@ -104,7 +105,7 @@ like lzip or lunzip.
|
||||||
line of defense for the case where the backups are also damaged.
|
line of defense for the case where the backups are also damaged.
|
||||||
|
|
||||||
|
|
||||||
File: lziprecover.info, Node: Invoking lziprecover, Next: Repairing files, Prev: Introduction, Up: Top
|
File: lziprecover.info, Node: Invoking lziprecover, Next: Data safety, Prev: Introduction, Up: Top
|
||||||
|
|
||||||
2 Invoking lziprecover
|
2 Invoking lziprecover
|
||||||
**********************
|
**********************
|
||||||
|
@ -252,20 +253,66 @@ invalid input file, 3 for an internal consistency error (eg, bug) which
|
||||||
caused lziprecover to panic.
|
caused lziprecover to panic.
|
||||||
|
|
||||||
|
|
||||||
File: lziprecover.info, Node: Repairing files, Next: Merging files, Prev: Invoking lziprecover, Up: Top
|
File: lziprecover.info, Node: Data safety, Next: Repairing files, Prev: Invoking lziprecover, Up: Top
|
||||||
|
|
||||||
3 Repairing files
|
3 Protecting data from accidental loss
|
||||||
|
**************************************
|
||||||
|
|
||||||
|
There are 3 main types of data corruption that may cause data loss:
|
||||||
|
single-byte errors, multi-byte errors (generally affecting a whole
|
||||||
|
sector in a block device), and total device failure.
|
||||||
|
|
||||||
|
Lziprecover protects natively against single-byte errors (*note
|
||||||
|
Repairing files::), as long as file integrity is checked frequently
|
||||||
|
enough that a second single-byte error does not develop in the same
|
||||||
|
member before the first one is repaired.
|
||||||
|
|
||||||
|
Lziprecover also protects against multi-byte errors (*note Merging
|
||||||
|
files::), if at least one backup copy of the file is made.
|
||||||
|
|
||||||
|
The only remedy for total device failure is storing backup copies in
|
||||||
|
separate media.
|
||||||
|
|
||||||
|
How does lzip compare with gzip and bzip2 with respect to data
|
||||||
|
safety? Lets suppose that you made a backup copy of your valuable
|
||||||
|
scientific data, compressed it, and stored two copies on separate
|
||||||
|
media. Years later you notice that both copies are corrupt.
|
||||||
|
|
||||||
|
If you compressed with gzip and both copies suffer any damage in the
|
||||||
|
data stream, even if it is just one altered bit, the original data can't
|
||||||
|
be recovered.
|
||||||
|
|
||||||
|
If you used bzip2, and if the file is large enough to contain more
|
||||||
|
than one compressed data block (usually larger than 900 kB), and if no
|
||||||
|
block is damaged in both files, then the data can be manually recovered
|
||||||
|
by splitting the files with bzip2recover, verifying every block and then
|
||||||
|
copying the right blocks in the right order in another file.
|
||||||
|
|
||||||
|
But if you used lzip, the data can be automatically recovered as
|
||||||
|
long as no byte is damaged in both files.
|
||||||
|
|
||||||
|
Note that each error in a bzip2 file makes a whole block unusable,
|
||||||
|
but each error in a lzip file only affects the damaged bytes, making it
|
||||||
|
possible to recover a file with thousands of errors.
|
||||||
|
|
||||||
|
|
||||||
|
File: lziprecover.info, Node: Repairing files, Next: Merging files, Prev: Data safety, Up: Top
|
||||||
|
|
||||||
|
4 Repairing files
|
||||||
*****************
|
*****************
|
||||||
|
|
||||||
Lziprecover can repair perfectly most files with small errors (up to one
|
Lziprecover can repair perfectly most files with small errors (up to one
|
||||||
single-byte error per member), without the need of any extra redundance
|
single-byte error per member), without the need of any extra redundance
|
||||||
at all. If the reparation is successful, the repaired file will be
|
at all. If the reparation is successful, the repaired file will be
|
||||||
identical bit for bit to the original.
|
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
|
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
|
(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
|
trailer (last 8 bytes of each member). If the error is in the header it
|
||||||
to bit-flip, one of the most common forms of data corruption.
|
can be easily repaired with a text editor like GNU Moe (*note File
|
||||||
|
format::). If the error is in the member size, it is enough to ignore
|
||||||
|
the message about 'bad member size' when decompressing.
|
||||||
|
|
||||||
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
|
||||||
|
@ -289,7 +336,7 @@ lziprecover repairs more efficiently the worst errors.
|
||||||
|
|
||||||
File: lziprecover.info, Node: Merging files, Next: File names, Prev: Repairing files, Up: Top
|
File: lziprecover.info, Node: Merging files, Next: File names, Prev: Repairing files, Up: Top
|
||||||
|
|
||||||
4 Merging files
|
5 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
|
||||||
|
@ -330,7 +377,7 @@ errors are randomly located inside each copy).
|
||||||
|
|
||||||
File: lziprecover.info, Node: File names, Next: File format, Prev: Merging files, Up: Top
|
File: lziprecover.info, Node: File names, Next: File format, Prev: Merging files, Up: Top
|
||||||
|
|
||||||
5 Names of the files produced by lziprecover
|
6 Names of the files produced by lziprecover
|
||||||
********************************************
|
********************************************
|
||||||
|
|
||||||
The name of the fixed file produced by '--merge' and '--repair' is made
|
The name of the fixed file produced by '--merge' and '--repair' is made
|
||||||
|
@ -341,7 +388,7 @@ original file name ends with one of the extensions '.tar.lz', '.lz' or
|
||||||
|
|
||||||
File: lziprecover.info, Node: File format, Next: Examples, Prev: File names, Up: Top
|
File: lziprecover.info, Node: File format, Next: Examples, Prev: File names, Up: Top
|
||||||
|
|
||||||
6 File format
|
7 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
|
||||||
|
@ -414,7 +461,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
|
||||||
|
|
||||||
7 A small tutorial with examples
|
8 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
|
||||||
|
@ -485,7 +532,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
|
||||||
|
|
||||||
8 Testing the robustness of decompressors
|
9 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
|
||||||
|
@ -562,8 +609,8 @@ 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
|
||||||
|
|
||||||
9 Reporting bugs
|
10 Reporting bugs
|
||||||
****************
|
*****************
|
||||||
|
|
||||||
There are probably bugs in lziprecover. There are certainly errors and
|
There are probably bugs in lziprecover. There are certainly errors and
|
||||||
omissions in this manual. If you report them, they will get fixed. If
|
omissions in this manual. If you report them, they will get fixed. If
|
||||||
|
@ -584,6 +631,7 @@ Concept index
|
||||||
* Menu:
|
* Menu:
|
||||||
|
|
||||||
* bugs: Problems. (line 6)
|
* bugs: Problems. (line 6)
|
||||||
|
* data safety: Data safety. (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)
|
* file names: File names. (line 6)
|
||||||
|
@ -598,17 +646,18 @@ Concept index
|
||||||
|
|
||||||
Tag Table:
|
Tag Table:
|
||||||
Node: Top231
|
Node: Top231
|
||||||
Node: Introduction1153
|
Node: Introduction1216
|
||||||
Node: Invoking lziprecover4249
|
Node: Invoking lziprecover4312
|
||||||
Node: Repairing files9686
|
Node: Data safety9745
|
||||||
Node: Merging files11371
|
Node: Repairing files11661
|
||||||
Node: File names13212
|
Node: Merging files13563
|
||||||
Node: File format13676
|
Node: File names15404
|
||||||
Node: Examples16183
|
Node: File format15868
|
||||||
Ref: ddrescue-example17384
|
Node: Examples18375
|
||||||
Node: Unzcrash18493
|
Ref: ddrescue-example19576
|
||||||
Node: Problems21047
|
Node: Unzcrash20685
|
||||||
Node: Concept index21597
|
Node: Problems23239
|
||||||
|
Node: Concept index23791
|
||||||
|
|
||||||
End Tag Table
|
End Tag Table
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
@finalout
|
@finalout
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@set UPDATED 16 October 2014
|
@set UPDATED 21 January 2015
|
||||||
@set VERSION 1.17-pre1
|
@set VERSION 1.17-rc1
|
||||||
|
|
||||||
@dircategory Data Compression
|
@dircategory Data Compression
|
||||||
@direntry
|
@direntry
|
||||||
|
@ -37,6 +37,7 @@ This manual is for Lziprecover (version @value{VERSION}, @value{UPDATED}).
|
||||||
@menu
|
@menu
|
||||||
* Introduction:: Purpose and features of lziprecover
|
* Introduction:: Purpose and features of lziprecover
|
||||||
* Invoking lziprecover:: Command line interface
|
* Invoking lziprecover:: Command line interface
|
||||||
|
* Data safety:: Protecting data from accidental loss
|
||||||
* 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 names:: Names of the files produced by lziprecover
|
||||||
|
@ -48,7 +49,7 @@ This manual is for Lziprecover (version @value{VERSION}, @value{UPDATED}).
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@sp 1
|
@sp 1
|
||||||
Copyright @copyright{} 2009-2014 Antonio Diaz Diaz.
|
Copyright @copyright{} 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This manual is free documentation: you have unlimited permission
|
This manual is free documentation: you have unlimited permission
|
||||||
to copy, distribute and modify it.
|
to copy, distribute and modify it.
|
||||||
|
@ -281,6 +282,48 @@ invalid input file, 3 for an internal consistency error (eg, bug) which
|
||||||
caused lziprecover to panic.
|
caused lziprecover to panic.
|
||||||
|
|
||||||
|
|
||||||
|
@node Data safety
|
||||||
|
@chapter Protecting data from accidental loss
|
||||||
|
@cindex data safety
|
||||||
|
|
||||||
|
There are 3 main types of data corruption that may cause data loss:
|
||||||
|
single-byte errors, multi-byte errors (generally affecting a whole
|
||||||
|
sector in a block device), and total device failure.
|
||||||
|
|
||||||
|
Lziprecover protects natively against single-byte errors
|
||||||
|
(@pxref{Repairing files}), as long as file integrity is checked
|
||||||
|
frequently enough that a second single-byte error does not develop in
|
||||||
|
the same member before the first one is repaired.
|
||||||
|
|
||||||
|
Lziprecover also protects against multi-byte errors (@pxref{Merging
|
||||||
|
files}), if at least one backup copy of the file is made.
|
||||||
|
|
||||||
|
The only remedy for total device failure is storing backup copies in
|
||||||
|
separate media.
|
||||||
|
|
||||||
|
How does lzip compare with gzip and bzip2 with respect to data safety?
|
||||||
|
Lets suppose that you made a backup copy of your valuable scientific
|
||||||
|
data, compressed it, and stored two copies on separate media. Years
|
||||||
|
later you notice that both copies are corrupt.
|
||||||
|
|
||||||
|
If you compressed with gzip and both copies suffer any damage in the
|
||||||
|
data stream, even if it is just one altered bit, the original data can't
|
||||||
|
be recovered.
|
||||||
|
|
||||||
|
If you used bzip2, and if the file is large enough to contain more than
|
||||||
|
one compressed data block (usually larger than 900 kB), and if no block
|
||||||
|
is damaged in both files, then the data can be manually recovered by
|
||||||
|
splitting the files with bzip2recover, verifying every block and then
|
||||||
|
copying the right blocks in the right order in another file.
|
||||||
|
|
||||||
|
But if you used lzip, the data can be automatically recovered as long as
|
||||||
|
no byte is damaged in both files.
|
||||||
|
|
||||||
|
Note that each error in a bzip2 file makes a whole block unusable, but
|
||||||
|
each error in a lzip file only affects the damaged bytes, making it
|
||||||
|
possible to recover a file with thousands of errors.
|
||||||
|
|
||||||
|
|
||||||
@node Repairing files
|
@node Repairing files
|
||||||
@chapter Repairing files
|
@chapter Repairing files
|
||||||
@cindex repairing files
|
@cindex repairing files
|
||||||
|
@ -288,12 +331,15 @@ caused lziprecover to panic.
|
||||||
Lziprecover can repair perfectly most files with small errors (up to one
|
Lziprecover can repair perfectly most files with small errors (up to one
|
||||||
single-byte error per member), without the need of any extra redundance
|
single-byte error per member), without the need of any extra redundance
|
||||||
at all. If the reparation is successful, the repaired file will be
|
at all. If the reparation is successful, the repaired file will be
|
||||||
identical bit for bit to the original.
|
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
|
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
|
(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
|
trailer (last 8 bytes of each member). If the error is in the header it
|
||||||
to bit-flip, one of the most common forms of data corruption.
|
can be easily repaired with a text editor like GNU Moe (@pxref{File
|
||||||
|
format}). If the error is in the member size, it is enough to ignore the
|
||||||
|
message about @samp{bad member size} when decompressing.
|
||||||
|
|
||||||
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
|
||||||
|
@ -641,7 +687,7 @@ for all eternity, if not longer.
|
||||||
|
|
||||||
If you find a bug in lziprecover, please send electronic mail to
|
If you find a bug in lziprecover, please send electronic mail to
|
||||||
@email{lzip-bug@@nongnu.org}. Include the version number, which you can
|
@email{lzip-bug@@nongnu.org}. Include the version number, which you can
|
||||||
find by running @w{@samp{lziprecover --version}}.
|
find by running @w{@code{lziprecover --version}}.
|
||||||
|
|
||||||
|
|
||||||
@node Concept index
|
@node Concept index
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "lzip.h"
|
#include "lzip.h"
|
||||||
|
#include "block.h"
|
||||||
#include "file_index.h"
|
#include "file_index.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,18 +38,6 @@ int seek_read( const int fd, uint8_t * const buf, const int size,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Block Block::split( const long long pos )
|
|
||||||
{
|
|
||||||
if( pos > pos_ && pos < end() )
|
|
||||||
{
|
|
||||||
const Block b( pos_, pos - pos_ );
|
|
||||||
pos_ = pos; size_ -= b.size_;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
return Block( 0, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void File_index::set_errno_error( const char * const msg )
|
void File_index::set_errno_error( const char * const msg )
|
||||||
{
|
{
|
||||||
error_ = msg; error_ += std::strerror( errno ); error_ += '.';
|
error_ = msg; error_ += std::strerror( errno ); error_ += '.';
|
||||||
|
|
35
file_index.h
35
file_index.h
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
@ -15,39 +15,6 @@
|
||||||
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 INT64_MAX
|
|
||||||
#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class Block
|
|
||||||
{
|
|
||||||
long long pos_, size_; // pos + size <= INT64_MAX
|
|
||||||
|
|
||||||
public:
|
|
||||||
Block( const long long p, const long long s ) : pos_( p ), size_( s ) {}
|
|
||||||
|
|
||||||
long long pos() const { return pos_; }
|
|
||||||
long long size() const { return size_; }
|
|
||||||
long long end() const { return pos_ + size_; }
|
|
||||||
|
|
||||||
void pos( const long long p ) { pos_ = p; }
|
|
||||||
void size( const long long s ) { size_ = s; }
|
|
||||||
|
|
||||||
bool operator==( const Block & b ) const
|
|
||||||
{ return pos_ == b.pos_ && size_ == b.size_; }
|
|
||||||
bool operator!=( const Block & b ) const
|
|
||||||
{ return pos_ != b.pos_ || size_ != b.size_; }
|
|
||||||
|
|
||||||
bool operator<( const Block & b ) const { return pos_ < b.pos_; }
|
|
||||||
|
|
||||||
bool overlaps( const Block & b ) const
|
|
||||||
{ return ( pos_ < b.end() && b.pos_ < end() ); }
|
|
||||||
void shift( Block & b ) { ++size_; ++b.pos_; --b.size_; }
|
|
||||||
Block split( const long long pos );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class File_index
|
class File_index
|
||||||
{
|
{
|
||||||
struct Member
|
struct Member
|
||||||
|
|
11
lzip.h
11
lzip.h
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
@ -309,18 +309,19 @@ int merge_files( const std::vector< std::string > & filenames,
|
||||||
const bool force );
|
const bool force );
|
||||||
|
|
||||||
// defined in range_dec.cc
|
// defined in range_dec.cc
|
||||||
|
const char * format_num( unsigned long long num,
|
||||||
|
unsigned long long limit = -1ULL,
|
||||||
|
const int set_prefix = 0 );
|
||||||
bool safe_seek( const int fd, const long long pos );
|
bool safe_seek( const int fd, const long long pos );
|
||||||
int list_files( const std::vector< std::string > & filenames,
|
int list_files( const std::vector< std::string > & filenames,
|
||||||
const int verbosity );
|
const int verbosity );
|
||||||
int range_decompress( const std::string & input_filename,
|
|
||||||
const std::string & default_output_filename,
|
|
||||||
const std::string & range_string, const int verbosity,
|
|
||||||
const bool force, const bool ignore, const bool to_stdout );
|
|
||||||
|
|
||||||
// defined in repair.cc
|
// defined in repair.cc
|
||||||
int repair_file( const std::string & input_filename,
|
int repair_file( const std::string & input_filename,
|
||||||
const std::string & output_filename, const int verbosity,
|
const std::string & output_filename, const int verbosity,
|
||||||
const bool force );
|
const bool force );
|
||||||
|
int debug_repair( const std::string & input_filename, const long long bad_pos,
|
||||||
|
const int verbosity, const uint8_t bad_value );
|
||||||
|
|
||||||
// defined in split.cc
|
// defined in split.cc
|
||||||
int split_file( const std::string & input_filename,
|
int split_file( const std::string & input_filename,
|
||||||
|
|
133
main.cc
133
main.cc
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
#include "arg_parser.h"
|
#include "arg_parser.h"
|
||||||
#include "lzip.h"
|
#include "lzip.h"
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
|
#include "block.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
|
@ -69,7 +70,7 @@ namespace {
|
||||||
|
|
||||||
const char * const Program_name = "Lziprecover";
|
const char * const Program_name = "Lziprecover";
|
||||||
const char * const program_name = "lziprecover";
|
const char * const program_name = "lziprecover";
|
||||||
const char * const program_year = "2014";
|
const char * const program_year = "2015";
|
||||||
const char * invocation_name = 0;
|
const char * invocation_name = 0;
|
||||||
|
|
||||||
struct { const char * from; const char * to; } const known_extensions[] = {
|
struct { const char * from; const char * to; } const known_extensions[] = {
|
||||||
|
@ -77,8 +78,8 @@ struct { const char * from; const char * to; } const known_extensions[] = {
|
||||||
{ ".tlz", ".tar" },
|
{ ".tlz", ".tar" },
|
||||||
{ 0, 0 } };
|
{ 0, 0 } };
|
||||||
|
|
||||||
enum Mode { m_none, m_decompress, m_list, m_merge, m_range, m_repair,
|
enum Mode { m_none, m_debug_delay, m_debug_repair, m_decompress, m_list,
|
||||||
m_split, m_test };
|
m_merge, m_range_dec, m_repair, m_split, m_test };
|
||||||
|
|
||||||
std::string output_filename;
|
std::string output_filename;
|
||||||
int outfd = -1;
|
int outfd = -1;
|
||||||
|
@ -92,7 +93,7 @@ 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( "Lziprecover can repair perfectly most files with small errors (up to one\n"
|
std::printf( "\nLziprecover 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"
|
"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"
|
"at all. Losing an entire archive just because of a corrupt byte near the\n"
|
||||||
"beginning is a thing of the past.\n"
|
"beginning is a thing of the past.\n"
|
||||||
|
@ -116,8 +117,13 @@ void show_help()
|
||||||
" -R, --repair try to repair a small error in file\n"
|
" -R, --repair try to repair a small error in file\n"
|
||||||
" -s, --split split multi-member file in single-member files\n"
|
" -s, --split split multi-member file in single-member files\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" );
|
||||||
"Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
|
if( verbosity >= 1 )
|
||||||
|
{
|
||||||
|
std::printf( " -y, --debug-delay=<range> find max error detection delay in <range>\n"
|
||||||
|
" -z, --debug-repair=<pos>,<val> test repair one-byte error at <pos>\n" );
|
||||||
|
}
|
||||||
|
std::printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
|
||||||
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
|
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
|
||||||
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
|
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
|
||||||
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
|
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
|
||||||
|
@ -140,6 +146,8 @@ void show_version()
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
||||||
void show_header( const File_header & header )
|
void show_header( const File_header & header )
|
||||||
|
{
|
||||||
|
if( verbosity >= 3 )
|
||||||
{
|
{
|
||||||
const char * const prefix[8] =
|
const char * const prefix[8] =
|
||||||
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
|
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
|
||||||
|
@ -154,9 +162,94 @@ void show_header( const File_header & header )
|
||||||
p = prefix[i]; np = ""; }
|
p = prefix[i]; np = ""; }
|
||||||
std::fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p );
|
std::fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Returns the number of chars read, or 0 if error.
|
||||||
|
//
|
||||||
|
int parse_long_long( const char * const ptr, long long & value )
|
||||||
|
{
|
||||||
|
char * tail;
|
||||||
|
errno = 0;
|
||||||
|
value = strtoll( ptr, &tail, 0 );
|
||||||
|
if( tail == ptr || errno || value < 0 ) return 0;
|
||||||
|
int c = tail - ptr;
|
||||||
|
|
||||||
|
if( ptr[c] )
|
||||||
|
{
|
||||||
|
const int factor = ( ptr[c+1] == 'i' ) ? 1024 : 1000;
|
||||||
|
int exponent = 0;
|
||||||
|
switch( ptr[c] )
|
||||||
|
{
|
||||||
|
case 'Y': exponent = 8; break;
|
||||||
|
case 'Z': exponent = 7; break;
|
||||||
|
case 'E': exponent = 6; break;
|
||||||
|
case 'P': exponent = 5; break;
|
||||||
|
case 'T': exponent = 4; break;
|
||||||
|
case 'G': exponent = 3; break;
|
||||||
|
case 'M': exponent = 2; break;
|
||||||
|
case 'K': if( factor == 1024 ) exponent = 1; else return 0; break;
|
||||||
|
case 'k': if( factor == 1000 ) exponent = 1; else return 0; break;
|
||||||
|
}
|
||||||
|
if( exponent > 0 )
|
||||||
|
{
|
||||||
|
++c;
|
||||||
|
if( ptr[c] == 'i' ) { ++c; if( value ) format_num( 0, 0, -1 ); }
|
||||||
|
if( ptr[c] == 'B' ) ++c;
|
||||||
|
for( int i = 0; i < exponent; ++i )
|
||||||
|
{
|
||||||
|
if( INT64_MAX / factor >= value ) value *= factor;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Recognized formats: <begin> <begin>-<end> <begin>,<size>
|
||||||
|
//
|
||||||
|
void parse_range( const char * const ptr, Block & range )
|
||||||
|
{
|
||||||
|
long long value = 0;
|
||||||
|
int c = parse_long_long( ptr, value ); // pos
|
||||||
|
if( c && value >= 0 && value < INT64_MAX &&
|
||||||
|
( ptr[c] == 0 || ptr[c] == ',' || ptr[c] == '-' ) )
|
||||||
|
{
|
||||||
|
range.pos( value );
|
||||||
|
if( ptr[c] == 0 ) { range.size( INT64_MAX - value ); return; }
|
||||||
|
const bool issize = ( ptr[c] == ',' );
|
||||||
|
c = parse_long_long( ptr + c + 1, value ); // size
|
||||||
|
if( c && value > 0 && ( issize || value > range.pos() ) )
|
||||||
|
{
|
||||||
|
if( !issize ) value -= range.pos();
|
||||||
|
if( INT64_MAX - range.pos() >= value ) { range.size( value ); return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_error( "Bad decompression range.", 0, true );
|
||||||
|
std::exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Recognized format: <pos>,<value>
|
||||||
|
//
|
||||||
|
void parse_pos_value( const char * const ptr, long long & pos, uint8_t & value )
|
||||||
|
{
|
||||||
|
long long val = 0;
|
||||||
|
int c = parse_long_long( ptr, val ); // pos
|
||||||
|
if( c && val >= 0 && val < INT64_MAX && ptr[c] == ',' )
|
||||||
|
{
|
||||||
|
pos = val;
|
||||||
|
c = parse_long_long( ptr + c + 1, val ); // value
|
||||||
|
if( c && val >= 0 && val < 256 )
|
||||||
|
{ value = val; return; }
|
||||||
|
}
|
||||||
|
show_error( "Bad file position or byte value.", 0, true );
|
||||||
|
std::exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void one_file( const int files )
|
void one_file( const int files )
|
||||||
{
|
{
|
||||||
if( files != 1 )
|
if( files != 1 )
|
||||||
|
@ -400,7 +493,7 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing )
|
||||||
{ pp( "Invalid dictionary size in member header." ); retval = 2; break; }
|
{ pp( "Invalid dictionary size in member header." ); retval = 2; break; }
|
||||||
|
|
||||||
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
|
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
|
||||||
{ pp(); if( verbosity >= 3 ) show_header( header ); }
|
{ pp(); show_header( header ); }
|
||||||
|
|
||||||
LZ_decoder decoder( header, rdec, outfd );
|
LZ_decoder decoder( header, rdec, outfd );
|
||||||
const int result = decoder.decode_member( pp );
|
const int result = decoder.decode_member( pp );
|
||||||
|
@ -504,12 +597,14 @@ void internal_error( const char * const msg )
|
||||||
|
|
||||||
int main( const int argc, const char * const argv[] )
|
int main( const int argc, const char * const argv[] )
|
||||||
{
|
{
|
||||||
|
Block range( 0, 0 );
|
||||||
|
long long bad_pos = 0;
|
||||||
std::string input_filename;
|
std::string input_filename;
|
||||||
std::string default_output_filename;
|
std::string default_output_filename;
|
||||||
std::string range_string;
|
|
||||||
std::vector< std::string > filenames;
|
std::vector< std::string > filenames;
|
||||||
int infd = -1;
|
int infd = -1;
|
||||||
Mode program_mode = m_none;
|
Mode program_mode = m_none;
|
||||||
|
uint8_t bad_value = 0;
|
||||||
bool force = false;
|
bool force = false;
|
||||||
bool ignore = false;
|
bool ignore = false;
|
||||||
bool keep_input_files = false;
|
bool keep_input_files = false;
|
||||||
|
@ -535,6 +630,8 @@ int main( const int argc, const char * const argv[] )
|
||||||
{ 't', "test", Arg_parser::no },
|
{ 't', "test", Arg_parser::no },
|
||||||
{ 'v', "verbose", Arg_parser::no },
|
{ 'v', "verbose", Arg_parser::no },
|
||||||
{ 'V', "version", Arg_parser::no },
|
{ 'V', "version", Arg_parser::no },
|
||||||
|
{ 'y', "debug-delay", Arg_parser::yes },
|
||||||
|
{ 'z', "debug-repair", Arg_parser::yes },
|
||||||
{ 0 , 0, Arg_parser::no } };
|
{ 0 , 0, Arg_parser::no } };
|
||||||
|
|
||||||
const Arg_parser parser( argc, argv, options );
|
const Arg_parser parser( argc, argv, options );
|
||||||
|
@ -551,8 +648,8 @@ int main( const int argc, const char * const argv[] )
|
||||||
{
|
{
|
||||||
case 'c': to_stdout = true; break;
|
case 'c': to_stdout = true; break;
|
||||||
case 'd': set_mode( program_mode, m_decompress ); break;
|
case 'd': set_mode( program_mode, m_decompress ); break;
|
||||||
case 'D': set_mode( program_mode, m_range );
|
case 'D': set_mode( program_mode, m_range_dec );
|
||||||
range_string = arg; break;
|
parse_range( arg.c_str(), range ); break;
|
||||||
case 'f': force = true; break;
|
case 'f': force = true; break;
|
||||||
case 'h': show_help(); return 0;
|
case 'h': show_help(); return 0;
|
||||||
case 'i': ignore = true; break;
|
case 'i': ignore = true; break;
|
||||||
|
@ -567,6 +664,10 @@ int main( const int argc, const char * const argv[] )
|
||||||
case 't': set_mode( program_mode, m_test ); break;
|
case 't': set_mode( program_mode, m_test ); break;
|
||||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||||
case 'V': show_version(); return 0;
|
case 'V': show_version(); return 0;
|
||||||
|
case 'y': set_mode( program_mode, m_debug_delay );
|
||||||
|
parse_range( arg.c_str(), range ); break;
|
||||||
|
case 'z': set_mode( program_mode, m_debug_repair );
|
||||||
|
parse_pos_value( arg.c_str(), bad_pos, bad_value ); break;
|
||||||
default : internal_error( "uncaught option." );
|
default : internal_error( "uncaught option." );
|
||||||
}
|
}
|
||||||
} // end process options
|
} // end process options
|
||||||
|
@ -593,6 +694,12 @@ int main( const int argc, const char * const argv[] )
|
||||||
switch( program_mode )
|
switch( program_mode )
|
||||||
{
|
{
|
||||||
case m_none: internal_error( "invalid operation." ); break;
|
case m_none: internal_error( "invalid operation." ); break;
|
||||||
|
case m_debug_delay:
|
||||||
|
one_file( filenames.size() );
|
||||||
|
return debug_delay( filenames[0], range, verbosity );
|
||||||
|
case m_debug_repair:
|
||||||
|
one_file( filenames.size() );
|
||||||
|
return debug_repair( filenames[0], bad_pos, verbosity, bad_value );
|
||||||
case m_decompress: break;
|
case m_decompress: break;
|
||||||
case m_list:
|
case m_list:
|
||||||
if( filenames.size() < 1 )
|
if( filenames.size() < 1 )
|
||||||
|
@ -604,10 +711,10 @@ int main( const int argc, const char * const argv[] )
|
||||||
if( default_output_filename.empty() )
|
if( default_output_filename.empty() )
|
||||||
default_output_filename = insert_fixed( filenames[0] );
|
default_output_filename = insert_fixed( filenames[0] );
|
||||||
return merge_files( filenames, default_output_filename, verbosity, force );
|
return merge_files( filenames, default_output_filename, verbosity, force );
|
||||||
case m_range:
|
case m_range_dec:
|
||||||
one_file( filenames.size() );
|
one_file( filenames.size() );
|
||||||
return range_decompress( filenames[0], default_output_filename,
|
return range_decompress( filenames[0], default_output_filename,
|
||||||
range_string, verbosity, force, ignore, to_stdout );
|
range, verbosity, force, ignore, to_stdout );
|
||||||
case m_repair:
|
case m_repair:
|
||||||
one_file( filenames.size() );
|
one_file( filenames.size() );
|
||||||
if( default_output_filename.empty() )
|
if( default_output_filename.empty() )
|
||||||
|
|
5
merge.cc
5
merge.cc
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "lzip.h"
|
#include "lzip.h"
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
|
#include "block.h"
|
||||||
#include "file_index.h"
|
#include "file_index.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -255,6 +256,7 @@ int open_input_files( const std::vector< std::string > & filenames,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// merge block by block
|
||||||
bool try_merge_member( const long long mpos, const long long msize,
|
bool try_merge_member( const long long mpos, const long long msize,
|
||||||
const std::vector< Block > & block_vector,
|
const std::vector< Block > & block_vector,
|
||||||
const std::vector< int > & color_vector,
|
const std::vector< int > & color_vector,
|
||||||
|
@ -318,6 +320,7 @@ bool try_merge_member( const long long mpos, const long long msize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// merge a single block split at every possible position
|
||||||
bool try_merge_member1( const long long mpos, const long long msize,
|
bool try_merge_member1( const long long mpos, const long long msize,
|
||||||
const std::vector< Block > & block_vector,
|
const std::vector< Block > & block_vector,
|
||||||
const std::vector< int > & color_vector,
|
const std::vector< int > & color_vector,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
|
125
range_dec.cc
125
range_dec.cc
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,101 +30,12 @@
|
||||||
|
|
||||||
#include "lzip.h"
|
#include "lzip.h"
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
|
#include "block.h"
|
||||||
#include "file_index.h"
|
#include "file_index.h"
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char * format_num( unsigned long long num,
|
|
||||||
unsigned long long limit = -1ULL,
|
|
||||||
const int set_prefix = 0 )
|
|
||||||
{
|
|
||||||
const char * const si_prefix[8] =
|
|
||||||
{ "k", "M", "G", "T", "P", "E", "Z", "Y" };
|
|
||||||
const char * const binary_prefix[8] =
|
|
||||||
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
|
|
||||||
static bool si = true;
|
|
||||||
static char buf[32];
|
|
||||||
|
|
||||||
if( set_prefix ) si = ( set_prefix > 0 );
|
|
||||||
const unsigned factor = ( si ? 1000 : 1024 );
|
|
||||||
const char * const * prefix = ( si ? si_prefix : binary_prefix );
|
|
||||||
const char * p = "";
|
|
||||||
bool exact = ( num % factor == 0 );
|
|
||||||
|
|
||||||
for( int i = 0; i < 8 && ( num > limit || ( exact && num >= factor ) ); ++i )
|
|
||||||
{ num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; }
|
|
||||||
snprintf( buf, sizeof buf, "%llu %s", num, p );
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the number of chars read, or 0 if error.
|
|
||||||
//
|
|
||||||
int parse_long_long( const char * const ptr, long long & value )
|
|
||||||
{
|
|
||||||
char * tail;
|
|
||||||
errno = 0;
|
|
||||||
value = strtoll( ptr, &tail, 0 );
|
|
||||||
if( tail == ptr || errno || value < 0 ) return 0;
|
|
||||||
int c = tail - ptr;
|
|
||||||
|
|
||||||
if( ptr[c] )
|
|
||||||
{
|
|
||||||
const int factor = ( ptr[c+1] == 'i' ) ? 1024 : 1000;
|
|
||||||
int exponent = 0;
|
|
||||||
switch( ptr[c] )
|
|
||||||
{
|
|
||||||
case 'Y': exponent = 8; break;
|
|
||||||
case 'Z': exponent = 7; break;
|
|
||||||
case 'E': exponent = 6; break;
|
|
||||||
case 'P': exponent = 5; break;
|
|
||||||
case 'T': exponent = 4; break;
|
|
||||||
case 'G': exponent = 3; break;
|
|
||||||
case 'M': exponent = 2; break;
|
|
||||||
case 'K': if( factor == 1024 ) exponent = 1; else return 0; break;
|
|
||||||
case 'k': if( factor == 1000 ) exponent = 1; else return 0; break;
|
|
||||||
}
|
|
||||||
if( exponent > 0 )
|
|
||||||
{
|
|
||||||
++c;
|
|
||||||
if( ptr[c] == 'i' ) { ++c; if( value ) format_num( 0, 0, -1 ); }
|
|
||||||
if( ptr[c] == 'B' ) ++c;
|
|
||||||
for( int i = 0; i < exponent; ++i )
|
|
||||||
{
|
|
||||||
if( INT64_MAX / factor >= value ) value *= factor;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Recognized formats: <begin> <begin>-<end> <begin>,<size>
|
|
||||||
//
|
|
||||||
void parse_range( const char * const ptr, Block & range )
|
|
||||||
{
|
|
||||||
long long value = 0;
|
|
||||||
int c = parse_long_long( ptr, value ); // pos
|
|
||||||
if( c && value >= 0 && value < INT64_MAX &&
|
|
||||||
( ptr[c] == 0 || ptr[c] == ',' || ptr[c] == '-' ) )
|
|
||||||
{
|
|
||||||
range.pos( value );
|
|
||||||
if( ptr[c] == 0 ) { range.size( INT64_MAX - value ); return; }
|
|
||||||
const bool issize = ( ptr[c] == ',' );
|
|
||||||
c = parse_long_long( ptr + c + 1, value ); // size
|
|
||||||
if( c && value > 0 && ( issize || value > range.pos() ) )
|
|
||||||
{
|
|
||||||
if( !issize ) value -= range.pos();
|
|
||||||
if( INT64_MAX - range.pos() >= value ) { range.size( value ); return; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
show_error( "Bad decompression range.", 0, true );
|
|
||||||
std::exit( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int decompress_member( const int infd, const int outfd,
|
int decompress_member( const int infd, const int outfd,
|
||||||
const Pretty_print & pp,
|
const Pretty_print & pp,
|
||||||
const unsigned long long mpos,
|
const unsigned long long mpos,
|
||||||
|
@ -221,6 +132,30 @@ int list_file( const char * const input_filename, const Pretty_print & pp )
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
||||||
|
|
||||||
|
const char * format_num( unsigned long long num,
|
||||||
|
unsigned long long limit,
|
||||||
|
const int set_prefix )
|
||||||
|
{
|
||||||
|
const char * const si_prefix[8] =
|
||||||
|
{ "k", "M", "G", "T", "P", "E", "Z", "Y" };
|
||||||
|
const char * const binary_prefix[8] =
|
||||||
|
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
|
||||||
|
static bool si = true;
|
||||||
|
static char buf[32];
|
||||||
|
|
||||||
|
if( set_prefix ) si = ( set_prefix > 0 );
|
||||||
|
const unsigned factor = ( si ? 1000 : 1024 );
|
||||||
|
const char * const * prefix = ( si ? si_prefix : binary_prefix );
|
||||||
|
const char * p = "";
|
||||||
|
bool exact = ( num % factor == 0 );
|
||||||
|
|
||||||
|
for( int i = 0; i < 8 && ( num > limit || ( exact && num >= factor ) ); ++i )
|
||||||
|
{ num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; }
|
||||||
|
snprintf( buf, sizeof buf, "%llu %s", num, p );
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool safe_seek( const int fd, const long long pos )
|
bool safe_seek( const int fd, const long long pos )
|
||||||
{
|
{
|
||||||
if( lseek( fd, pos, SEEK_SET ) == pos ) return true;
|
if( lseek( fd, pos, SEEK_SET ) == pos ) return true;
|
||||||
|
@ -245,11 +180,9 @@ int list_files( const std::vector< std::string > & filenames,
|
||||||
|
|
||||||
int range_decompress( const std::string & input_filename,
|
int range_decompress( const std::string & input_filename,
|
||||||
const std::string & output_filename,
|
const std::string & output_filename,
|
||||||
const std::string & range_string, const int verbosity,
|
Block range, const int verbosity, const bool force,
|
||||||
const bool force, const bool ignore, const bool to_stdout )
|
const bool ignore, const bool to_stdout )
|
||||||
{
|
{
|
||||||
Block range( 0, 0 );
|
|
||||||
parse_range( range_string.c_str(), range );
|
|
||||||
struct stat in_stats;
|
struct stat in_stats;
|
||||||
const int infd = open_instream( input_filename.c_str(), &in_stats, true, true );
|
const int infd = open_instream( input_filename.c_str(), &in_stats, true, true );
|
||||||
if( infd < 0 ) return 1;
|
if( infd < 0 ) return 1;
|
||||||
|
@ -262,7 +195,7 @@ int range_decompress( const std::string & input_filename,
|
||||||
if( range.end() > file_index.data_end() )
|
if( range.end() > file_index.data_end() )
|
||||||
range.size( std::max( 0LL, file_index.data_end() - range.pos() ) );
|
range.size( std::max( 0LL, file_index.data_end() - range.pos() ) );
|
||||||
if( range.size() <= 0 )
|
if( range.size() <= 0 )
|
||||||
{ if( verbosity >= 1 ) pp( "Nothing to do." ); return 0; }
|
{ if( verbosity >= 0 ) pp( "Nothing to do." ); return 0; }
|
||||||
|
|
||||||
if( verbosity >= 1 )
|
if( verbosity >= 1 )
|
||||||
{
|
{
|
||||||
|
|
186
repair.cc
186
repair.cc
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
@ -29,10 +29,13 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "lzip.h"
|
#include "lzip.h"
|
||||||
#include "file_index.h"
|
|
||||||
#include "mtester.h"
|
#include "mtester.h"
|
||||||
|
#include "block.h"
|
||||||
|
#include "file_index.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
int seek_write( const int fd, const uint8_t * const buf, const int size,
|
int seek_write( const int fd, const uint8_t * const buf, const int size,
|
||||||
const long long pos )
|
const long long pos )
|
||||||
{
|
{
|
||||||
|
@ -41,6 +44,8 @@ int seek_write( const int fd, const uint8_t * const buf, const int size,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // end namespace
|
||||||
|
|
||||||
|
|
||||||
int repair_file( const std::string & input_filename,
|
int repair_file( const std::string & input_filename,
|
||||||
const std::string & output_filename, const int verbosity,
|
const std::string & output_filename, const int verbosity,
|
||||||
|
@ -80,13 +85,13 @@ 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 - 40000 && !done )
|
while( pos >= File_header::size && pos > failure_pos - 50000 && !done )
|
||||||
{
|
{
|
||||||
const long min_pos = std::max( (long)File_header::size, pos - 1000 );
|
const long min_pos = std::max( (long)File_header::size, pos - 100 );
|
||||||
const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 );
|
const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 );
|
||||||
if( !master )
|
if( !master )
|
||||||
cleanup_and_fail( output_filename, outfd, 1 );
|
cleanup_and_fail( output_filename, outfd, 1 );
|
||||||
for( ; pos >= min_pos && !done ; --pos )
|
for( ; pos >= min_pos && !done; --pos )
|
||||||
{
|
{
|
||||||
if( verbosity >= 1 )
|
if( verbosity >= 1 )
|
||||||
{
|
{
|
||||||
|
@ -141,3 +146,174 @@ int repair_file( const std::string & input_filename,
|
||||||
std::fputs( "Copy of input file repaired successfully.\n", stdout );
|
std::fputs( "Copy of input file repaired successfully.\n", stdout );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int debug_delay( const std::string & input_filename, Block range,
|
||||||
|
const int verbosity )
|
||||||
|
{
|
||||||
|
struct stat in_stats;
|
||||||
|
const int infd = open_instream( input_filename.c_str(), &in_stats, true, true );
|
||||||
|
if( infd < 0 ) return 1;
|
||||||
|
|
||||||
|
Pretty_print pp( input_filename, verbosity );
|
||||||
|
const File_index file_index( infd );
|
||||||
|
if( file_index.retval() != 0 )
|
||||||
|
{ pp( file_index.error().c_str() ); return file_index.retval(); }
|
||||||
|
|
||||||
|
if( range.end() > file_index.file_end() )
|
||||||
|
range.size( std::max( 0LL, file_index.file_end() - range.pos() ) );
|
||||||
|
if( range.size() <= 0 )
|
||||||
|
{ if( verbosity >= 0 ) pp( "Nothing to do." ); return 0; }
|
||||||
|
|
||||||
|
for( long i = 0; i < file_index.members(); ++i )
|
||||||
|
{
|
||||||
|
const Block & mb = file_index.mblock( i );
|
||||||
|
if( !range.overlaps( mb ) ) continue;
|
||||||
|
const long long mpos = file_index.mblock( i ).pos();
|
||||||
|
const long long msize = file_index.mblock( i ).size();
|
||||||
|
if( verbosity >= 1 ) // damaged member found
|
||||||
|
{
|
||||||
|
std::printf( "Finding max delay in member %ld of %ld (member pos = %llu)\n",
|
||||||
|
i + 1, (long)file_index.members(), mpos );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
uint8_t * const mbuffer = read_member( infd, mpos, msize );
|
||||||
|
if( !mbuffer )
|
||||||
|
{ show_error( "Can't read member." ); return 1; }
|
||||||
|
long pos = std::max( range.pos() - mpos, File_header::size + 1LL );
|
||||||
|
const long end = std::min( range.end() - mpos, msize );
|
||||||
|
long max_delay = 0;
|
||||||
|
while( pos < end )
|
||||||
|
{
|
||||||
|
const LZ_mtester * master = prepare_master( mbuffer, msize, pos - 16 );
|
||||||
|
if( !master )
|
||||||
|
{ show_error( "Can't prepare master." ); return 1; }
|
||||||
|
const long partial_end = std::min( pos + 100, end );
|
||||||
|
for( ; pos < partial_end; ++pos )
|
||||||
|
{
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
{
|
||||||
|
std::printf( "Delays in position %llu \r", mpos + pos );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
int value = -1;
|
||||||
|
for( int j = 0; j < 256; ++j )
|
||||||
|
{
|
||||||
|
++mbuffer[pos];
|
||||||
|
if( j == 255 ) break;
|
||||||
|
long failure_pos;
|
||||||
|
if( test_member_rest( *master, &failure_pos ) ) continue;
|
||||||
|
const long delay = failure_pos - pos;
|
||||||
|
if( delay > max_delay ) { max_delay = delay; value = mbuffer[pos]; }
|
||||||
|
}
|
||||||
|
if( value >= 0 && verbosity >= 0 )
|
||||||
|
{
|
||||||
|
std::printf( "New max delay %lu at position %llu (0x%02X)\n",
|
||||||
|
max_delay, mpos + pos, value );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
if( pos + max_delay >= msize ) { pos = end; break; }
|
||||||
|
}
|
||||||
|
delete master;
|
||||||
|
}
|
||||||
|
delete[] mbuffer;
|
||||||
|
if( verbosity >= 1 ) std::fputs( "\n", stdout );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( verbosity >= 1 ) std::fputs( "Done.\n", stdout );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int debug_repair( const std::string & input_filename, const long long bad_pos,
|
||||||
|
const int verbosity, const uint8_t bad_value )
|
||||||
|
{
|
||||||
|
struct stat in_stats;
|
||||||
|
const int infd = open_instream( input_filename.c_str(), &in_stats, true, true );
|
||||||
|
if( infd < 0 ) return 1;
|
||||||
|
|
||||||
|
Pretty_print pp( input_filename, verbosity );
|
||||||
|
const File_index file_index( infd );
|
||||||
|
if( file_index.retval() != 0 )
|
||||||
|
{ pp( file_index.error().c_str() ); return file_index.retval(); }
|
||||||
|
|
||||||
|
long idx = 0;
|
||||||
|
for( ; idx < file_index.members(); ++idx )
|
||||||
|
if( file_index.mblock( idx ).includes( bad_pos ) ) break;
|
||||||
|
if( idx >= file_index.members() )
|
||||||
|
{ if( verbosity >= 0 ) pp( "Nothing to do." ); return 0; }
|
||||||
|
|
||||||
|
const long long mpos = file_index.mblock( idx ).pos();
|
||||||
|
const long long msize = file_index.mblock( idx ).size();
|
||||||
|
{
|
||||||
|
long long failure_pos = 0;
|
||||||
|
if( !safe_seek( infd, mpos ) )
|
||||||
|
{ show_error( "Can't seek to member." ); return 1; }
|
||||||
|
if( !try_decompress_member( infd, msize, &failure_pos ) )
|
||||||
|
{
|
||||||
|
if( verbosity >= 0 )
|
||||||
|
std::printf( "Member %ld of %ld already damaged (failure pos = %llu)\n",
|
||||||
|
idx + 1, (long)file_index.members(), mpos + failure_pos );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t * const mbuffer = read_member( infd, mpos, msize );
|
||||||
|
if( !mbuffer )
|
||||||
|
{ show_error( "Can't read member." ); return 1; }
|
||||||
|
const uint8_t good_value = mbuffer[bad_pos];
|
||||||
|
mbuffer[bad_pos] = bad_value;
|
||||||
|
long failure_pos = 0;
|
||||||
|
{
|
||||||
|
const LZ_mtester * master = prepare_master( mbuffer, msize, 0 );
|
||||||
|
if( !master )
|
||||||
|
{ show_error( "Can't prepare master." ); return 1; }
|
||||||
|
if( test_member_rest( *master, &failure_pos ) )
|
||||||
|
{
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
std::fputs( "Member decompressed with no errors.\n", stdout );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
{
|
||||||
|
std::printf( "Test repairing member %ld of %ld\n"
|
||||||
|
" (damage pos = %llu (0x%02X->0x%02X), failure pos = %llu)\n",
|
||||||
|
idx + 1, (long)file_index.members(), mpos + bad_pos,
|
||||||
|
good_value, bad_value, mpos + failure_pos );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long pos = failure_pos;
|
||||||
|
bool done = false;
|
||||||
|
while( pos >= File_header::size && pos > failure_pos - 50000 && !done )
|
||||||
|
{
|
||||||
|
const long min_pos = std::max( (long)File_header::size, pos - 100 );
|
||||||
|
const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 );
|
||||||
|
if( !master )
|
||||||
|
{ show_error( "Can't prepare master." ); return 1; }
|
||||||
|
for( ; pos >= min_pos && !done; --pos )
|
||||||
|
{
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
{
|
||||||
|
std::printf( "Trying position %llu \r", mpos + pos );
|
||||||
|
std::fflush( stdout );
|
||||||
|
}
|
||||||
|
for( int j = 0; j < 256; ++j )
|
||||||
|
{
|
||||||
|
++mbuffer[pos];
|
||||||
|
if( j == 255 ) break;
|
||||||
|
if( test_member_rest( *master ) ) { done = true; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete master;
|
||||||
|
}
|
||||||
|
delete[] mbuffer;
|
||||||
|
if( verbosity >= 1 ) std::fputs( "\n", stdout );
|
||||||
|
if( !done )
|
||||||
|
{
|
||||||
|
show_error( "Can't repair input file. There is a bug somewhere." );
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if( verbosity >= 1 )
|
||||||
|
std::fputs( "Member repaired successfully.\n", stdout );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
5
split.cc
5
split.cc
|
@ -1,5 +1,5 @@
|
||||||
/* Lziprecover - Data recovery tool for the lzip format
|
/* Lziprecover - Data recovery tool for the lzip format
|
||||||
Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
Copyright (C) 2009-2015 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
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "lzip.h"
|
#include "lzip.h"
|
||||||
|
#include "block.h"
|
||||||
#include "file_index.h"
|
#include "file_index.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ bool verify_header( const File_header & header, const Pretty_print & pp )
|
||||||
|
|
||||||
|
|
||||||
// Search forward from 'pos' for "LZIP" (Boyer-Moore algorithm)
|
// Search forward from 'pos' for "LZIP" (Boyer-Moore algorithm)
|
||||||
// Return pos of found string or 'pos+size' if not found.
|
// Returns pos of found string or 'pos+size' if not found.
|
||||||
//
|
//
|
||||||
int find_magic( const uint8_t * const buffer, const int pos, const int size )
|
int find_magic( const uint8_t * const buffer, const int pos, const int size )
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# check script for Lziprecover - Data recovery tool for the lzip format
|
# check script for Lziprecover - Data recovery tool for the lzip format
|
||||||
# Copyright (C) 2009-2014 Antonio Diaz Diaz.
|
# Copyright (C) 2009-2015 Antonio Diaz Diaz.
|
||||||
#
|
#
|
||||||
# This script is free software: you have unlimited permission
|
# This script is free software: you have unlimited permission
|
||||||
# to copy, distribute and modify it.
|
# to copy, distribute and modify it.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* Unzcrash - Tests robustness of decompressors to corrupted data.
|
/* Unzcrash - Tests robustness of decompressors to corrupted data.
|
||||||
Inspired by unzcrash.c from Julian Seward's bzip2.
|
Inspired by unzcrash.c from Julian Seward's bzip2.
|
||||||
Copyright (C) 2008-2014 Antonio Diaz Diaz.
|
Copyright (C) 2008-2015 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
|
||||||
|
@ -44,7 +44,7 @@ namespace {
|
||||||
|
|
||||||
const char * const Program_name = "Unzcrash";
|
const char * const Program_name = "Unzcrash";
|
||||||
const char * const program_name = "unzcrash";
|
const char * const program_name = "unzcrash";
|
||||||
const char * const program_year = "2014";
|
const char * const program_year = "2015";
|
||||||
const char * invocation_name = 0;
|
const char * invocation_name = 0;
|
||||||
|
|
||||||
int verbosity = 0;
|
int verbosity = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue