1
0
Fork 0

Merging upstream version 1.17~rc1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-21 11:23:37 +01:00
parent 97763bf5de
commit 3574ba518d
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
27 changed files with 624 additions and 240 deletions

155
main.cc
View file

@ -1,5 +1,5 @@
/* 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
it under the terms of the GNU General Public License as published by
@ -55,6 +55,7 @@
#include "arg_parser.h"
#include "lzip.h"
#include "decoder.h"
#include "block.h"
#ifndef O_BINARY
#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_year = "2014";
const char * const program_year = "2015";
const char * invocation_name = 0;
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" },
{ 0, 0 } };
enum Mode { m_none, m_decompress, m_list, m_merge, m_range, m_repair,
m_split, m_test };
enum Mode { m_none, m_debug_delay, m_debug_repair, m_decompress, m_list,
m_merge, m_range_dec, m_repair, m_split, m_test };
std::string output_filename;
int outfd = -1;
@ -92,7 +93,7 @@ bool delete_output_on_interrupt = false;
void show_help()
{
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"
"at all. Losing an entire archive just because of a corrupt byte near the\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"
" -s, --split split multi-member file in single-member files\n"
" -t, --test test compressed file integrity\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
"Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
" -v, --verbose be verbose (a 2nd -v gives more)\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"
"\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"
@ -141,22 +147,109 @@ void show_version()
void show_header( const File_header & header )
{
const char * const prefix[8] =
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
enum { factor = 1024 };
const char * p = "";
const char * np = " ";
unsigned num = header.dictionary_size();
bool exact = ( num % factor == 0 );
if( verbosity >= 3 )
{
const char * const prefix[8] =
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
enum { factor = 1024 };
const char * p = "";
const char * np = " ";
unsigned num = header.dictionary_size();
bool exact = ( num % factor == 0 );
for( int i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i )
{ num /= factor; if( num % factor != 0 ) exact = false;
p = prefix[i]; np = ""; }
std::fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p );
for( int i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i )
{ num /= factor; if( num % factor != 0 ) exact = false;
p = prefix[i]; np = ""; }
std::fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p );
}
}
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 )
{
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; }
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
{ pp(); if( verbosity >= 3 ) show_header( header ); }
{ pp(); show_header( header ); }
LZ_decoder decoder( header, rdec, outfd );
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[] )
{
Block range( 0, 0 );
long long bad_pos = 0;
std::string input_filename;
std::string default_output_filename;
std::string range_string;
std::vector< std::string > filenames;
int infd = -1;
Mode program_mode = m_none;
uint8_t bad_value = 0;
bool force = false;
bool ignore = false;
bool keep_input_files = false;
@ -535,6 +630,8 @@ int main( const int argc, const char * const argv[] )
{ 't', "test", Arg_parser::no },
{ 'v', "verbose", 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 } };
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 'd': set_mode( program_mode, m_decompress ); break;
case 'D': set_mode( program_mode, m_range );
range_string = arg; break;
case 'D': set_mode( program_mode, m_range_dec );
parse_range( arg.c_str(), range ); break;
case 'f': force = true; break;
case 'h': show_help(); return 0;
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 'v': if( verbosity < 4 ) ++verbosity; break;
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." );
}
} // end process options
@ -593,6 +694,12 @@ int main( const int argc, const char * const argv[] )
switch( program_mode )
{
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_list:
if( filenames.size() < 1 )
@ -604,10 +711,10 @@ int main( const int argc, const char * const argv[] )
if( default_output_filename.empty() )
default_output_filename = insert_fixed( filenames[0] );
return merge_files( filenames, default_output_filename, verbosity, force );
case m_range:
case m_range_dec:
one_file( filenames.size() );
return range_decompress( filenames[0], default_output_filename,
range_string, verbosity, force, ignore, to_stdout );
range, verbosity, force, ignore, to_stdout );
case m_repair:
one_file( filenames.size() );
if( default_output_filename.empty() )