Merging upstream version 1.21.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
4b818dc40b
commit
29d9f35b61
42 changed files with 2853 additions and 1586 deletions
275
main.cc
275
main.cc
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for the lzip format
|
||||
Copyright (C) 2009-2018 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009-2019 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
|
||||
|
@ -38,25 +38,29 @@
|
|||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(__MSVCRT__)
|
||||
#if defined(__MSVCRT__) || defined(__OS2__) || defined(__DJGPP__)
|
||||
#include <io.h>
|
||||
#if defined(__MSVCRT__)
|
||||
#define fchmod(x,y) 0
|
||||
#define fchown(x,y,z) 0
|
||||
#define SIGHUP SIGTERM
|
||||
#define S_ISSOCK(x) 0
|
||||
#ifndef S_IRGRP
|
||||
#define S_IRGRP 0
|
||||
#define S_IWGRP 0
|
||||
#define S_IROTH 0
|
||||
#define S_IWOTH 0
|
||||
#endif
|
||||
#if defined(__OS2__)
|
||||
#include <io.h>
|
||||
#endif
|
||||
#if defined(__DJGPP__)
|
||||
#define S_ISSOCK(x) 0
|
||||
#define S_ISVTX 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "arg_parser.h"
|
||||
#include "lzip.h"
|
||||
#include "decoder.h"
|
||||
#include "block.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
|
@ -67,12 +71,11 @@
|
|||
#endif
|
||||
|
||||
int verbosity = 0;
|
||||
std::string output_filename; // global vars for output file
|
||||
int outfd = -1;
|
||||
std::string output_filename; // global vars for output file
|
||||
int outfd = -1; // see 'delete_output_on_interrupt' below
|
||||
|
||||
namespace {
|
||||
|
||||
const char * const Program_name = "Lziprecover";
|
||||
const char * const program_name = "lziprecover";
|
||||
const char * invocation_name = 0;
|
||||
|
||||
|
@ -82,53 +85,58 @@ const struct { const char * from; const char * to; } known_extensions[] = {
|
|||
{ 0, 0 } };
|
||||
|
||||
enum Mode { m_none, m_alone_to_lz, m_debug_decompress, m_debug_delay,
|
||||
m_debug_repair, m_decompress, m_dump_tdata, m_list, m_merge,
|
||||
m_range_dec, m_remove_tdata, m_repair, m_show_packets, m_split,
|
||||
m_strip_tdata, m_test };
|
||||
m_debug_repair, m_decompress, m_dump, m_list, m_merge,
|
||||
m_range_dec, m_remove, m_repair, m_show_packets, m_split,
|
||||
m_strip, m_test };
|
||||
|
||||
/* Variable used in signal handler context.
|
||||
It is not declared volatile because the handler never returns. */
|
||||
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( "\nLziprecover can repair perfectly most files with small errors (up to one\n"
|
||||
std::printf( "Lziprecover is a data recovery tool and decompressor for files in the lzip\n"
|
||||
"compressed data format (.lz). Lziprecover is able to repair slightly damaged\n"
|
||||
"files, produce a correct file by merging the good parts of two or more\n"
|
||||
"damaged copies, extract data from damaged files, decompress files and test\n"
|
||||
"integrity of files.\n"
|
||||
"\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"
|
||||
"\nLziprecover 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"
|
||||
"\nLziprecover provides random access to the data in multimember files; it\n"
|
||||
"only decompresses the members containing the desired data.\n"
|
||||
"\nLziprecover facilitates the management of metadata stored as trailing\n"
|
||||
"data in lzip files.\n"
|
||||
"\nLziprecover can remove the damaged members from multimember files, for\n"
|
||||
"example multimember tar.lz archives.\n"
|
||||
"\nLziprecover provides random access to the data in multimember files; it only\n"
|
||||
"decompresses the members containing the desired data.\n"
|
||||
"\nLziprecover facilitates the management of metadata stored as trailing data\n"
|
||||
"in lzip files.\n"
|
||||
"\nLziprecover is not a replacement for regular backups, but a last line of\n"
|
||||
"defense for the case where the backups are also damaged.\n"
|
||||
"\nUsage: %s [options] [files]\n", invocation_name );
|
||||
std::printf( "\nOptions:\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
" -a, --trailing-error exit with error status if trailing data\n"
|
||||
" -A, --alone-to-lz convert lzma-alone files to lzip format\n"
|
||||
" -c, --stdout write to standard output, keep input files\n"
|
||||
" -d, --decompress decompress\n"
|
||||
" -D, --range-decompress=<range> decompress a range of bytes (N-M) to stdout\n"
|
||||
" -f, --force overwrite existing output files\n"
|
||||
" -i, --ignore-errors make '--range-decompress' ignore data errors\n"
|
||||
" -k, --keep keep (don't delete) input files\n"
|
||||
" -l, --list print (un)compressed file sizes\n"
|
||||
" -m, --merge correct errors in file using several copies\n"
|
||||
" -o, --output=<file> place the output into <file>\n"
|
||||
" -q, --quiet suppress all messages\n"
|
||||
" -R, --repair try to repair a small error in file\n"
|
||||
" -s, --split split multimember file in single-member files\n"
|
||||
" -t, --test test compressed file integrity\n"
|
||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||
" --loose-trailing allow trailing data seeming corrupt header\n"
|
||||
" --dump-tdata dump trailing data to standard output\n"
|
||||
" --remove-tdata remove trailing data from files in place\n"
|
||||
" --strip-tdata copy files to stdout without trailing data\n" );
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
" -a, --trailing-error exit with error status if trailing data\n"
|
||||
" -A, --alone-to-lz convert lzma-alone files to lzip format\n"
|
||||
" -c, --stdout write to standard output, keep input files\n"
|
||||
" -d, --decompress decompress\n"
|
||||
" -D, --range-decompress=<n-m> decompress a range of bytes to stdout\n"
|
||||
" -f, --force overwrite existing output files\n"
|
||||
" -i, --ignore-errors all errors in -D, format errors in -l, --dump\n"
|
||||
" -k, --keep keep (don't delete) input files\n"
|
||||
" -l, --list print (un)compressed file sizes\n"
|
||||
" -m, --merge correct errors in file using several copies\n"
|
||||
" -o, --output=<file> place the output into <file>\n"
|
||||
" -q, --quiet suppress all messages\n"
|
||||
" -R, --repair try to repair a small error in file\n"
|
||||
" -s, --split split multimember file in single-member files\n"
|
||||
" -t, --test test compressed file integrity\n"
|
||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||
" --loose-trailing allow trailing data seeming corrupt header\n"
|
||||
" --dump=<list>:d:t dump members listed/damaged, tdata to stdout\n"
|
||||
" --remove=<list>:d:t remove members, tdata from files in place\n"
|
||||
" --strip=<list>:d:t copy files to stdout stripping members given\n" );
|
||||
if( verbosity >= 1 )
|
||||
{
|
||||
std::printf( " -W, --debug-decompress=<pos>,<val> set pos to val and decompress to stdout\n"
|
||||
|
@ -202,6 +210,46 @@ void show_header( const unsigned dictionary_size )
|
|||
#include "main_common.cc"
|
||||
|
||||
|
||||
// Colon-separated list of "damaged", "tdata", [r][^]<list> (1 1,3-5,8)
|
||||
void Member_list::parse( const char * p )
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
const char * tp = p; // points to terminator; ':' or null
|
||||
while( *tp && *tp != ':' ) ++tp;
|
||||
const unsigned len = tp - p;
|
||||
if( std::isalpha( (const unsigned char)*p ) )
|
||||
{
|
||||
if( len <= 7 && std::strncmp( "damaged", p, len ) == 0 )
|
||||
{ damaged = true; goto next; }
|
||||
if( len <= 5 && std::strncmp( "tdata", p, len ) == 0 )
|
||||
{ tdata = true; goto next; }
|
||||
}
|
||||
{
|
||||
const bool reverse = ( *p == 'r' );
|
||||
if( reverse ) ++p;
|
||||
if( *p == '^' ) { ++p; if( reverse ) rin = false; else in = false; }
|
||||
std::vector< Block > * rvp = reverse ? &rrange_vector : &range_vector;
|
||||
while( std::isdigit( (const unsigned char)*p ) )
|
||||
{
|
||||
const char * tail;
|
||||
const int pos = getnum( p, 0, 1, INT_MAX, &tail ) - 1;
|
||||
if( rvp->size() && pos < rvp->back().end() ) break;
|
||||
const int size = (*tail == '-') ?
|
||||
getnum( tail + 1, 0, pos + 1, INT_MAX, &tail ) - pos : 1;
|
||||
rvp->push_back( Block( pos, size ) );
|
||||
if( tail == tp ) goto next;
|
||||
if( *tail == ',' ) p = tail + 1; else break;
|
||||
}
|
||||
}
|
||||
show_error( "Invalid list of members." );
|
||||
std::exit( 1 );
|
||||
next:
|
||||
if( *(p = tp) != 0 ) ++p; else return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// Recognized formats: <begin> <begin>-<end> <begin>,<size> ,<size>
|
||||
|
@ -215,11 +263,11 @@ void parse_range( const char * const ptr, Block & range )
|
|||
{
|
||||
range.pos( value );
|
||||
if( tail[0] == 0 ) { range.size( INT64_MAX - value ); return; }
|
||||
const bool issize = ( tail[0] == ',' );
|
||||
const bool is_size = ( tail[0] == ',' );
|
||||
value = getnum( tail + 1, 0, 1, INT64_MAX ); // size
|
||||
if( issize || value > range.pos() )
|
||||
if( is_size || value > range.pos() )
|
||||
{
|
||||
if( !issize ) value -= range.pos();
|
||||
if( !is_size ) value -= range.pos();
|
||||
if( INT64_MAX - range.pos() >= value ) { range.size( value ); return; }
|
||||
}
|
||||
}
|
||||
|
@ -343,23 +391,23 @@ int open_instream( const char * const name, struct stat * const in_statsp,
|
|||
int open_truncable_stream( const char * const name,
|
||||
struct stat * const in_statsp )
|
||||
{
|
||||
int infd = open( name, O_RDWR | O_BINARY );
|
||||
if( infd < 0 )
|
||||
int fd = open( name, O_RDWR | O_BINARY );
|
||||
if( fd < 0 )
|
||||
show_file_error( name, "Can't open input file", errno );
|
||||
else
|
||||
{
|
||||
const int i = fstat( infd, in_statsp );
|
||||
const int i = fstat( fd, in_statsp );
|
||||
const mode_t mode = in_statsp->st_mode;
|
||||
if( i != 0 || !S_ISREG( mode ) )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: File '%s' is not a regular file.\n",
|
||||
program_name, name );
|
||||
close( infd );
|
||||
infd = -1;
|
||||
close( fd );
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
return infd;
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
|
@ -421,8 +469,17 @@ bool check_tty( const char * const input_filename, const int infd,
|
|||
}
|
||||
|
||||
|
||||
void set_signals( void (*action)(int) )
|
||||
{
|
||||
std::signal( SIGHUP, action );
|
||||
std::signal( SIGINT, action );
|
||||
std::signal( SIGTERM, action );
|
||||
}
|
||||
|
||||
|
||||
void cleanup_and_fail( const int retval )
|
||||
{
|
||||
set_signals( SIG_IGN ); // ignore signals
|
||||
if( delete_output_on_interrupt )
|
||||
{
|
||||
delete_output_on_interrupt = false;
|
||||
|
@ -438,6 +495,13 @@ void cleanup_and_fail( const int retval )
|
|||
|
||||
namespace {
|
||||
|
||||
extern "C" void signal_handler( int )
|
||||
{
|
||||
show_error( "Control-C or similar caught, quitting." );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
|
||||
|
||||
// Set permissions, owner and times.
|
||||
void close_and_set_permissions( const struct stat * const in_statsp )
|
||||
{
|
||||
|
@ -517,9 +581,9 @@ int decompress( const unsigned long long cfile_size, const int infd,
|
|||
Range_decoder rdec( infd );
|
||||
for( bool first_member = true; ; first_member = false )
|
||||
{
|
||||
File_header header;
|
||||
Lzip_header header;
|
||||
rdec.reset_member_position();
|
||||
const int size = rdec.read_data( header.data, File_header::size );
|
||||
const int size = rdec.read_data( header.data, Lzip_header::size );
|
||||
if( rdec.finished() ) // End Of File
|
||||
{
|
||||
if( first_member )
|
||||
|
@ -573,30 +637,16 @@ int decompress( const unsigned long long cfile_size, const int infd,
|
|||
{ std::fputs( testing ? "ok\n" : "done\n", stderr ); pp.reset(); }
|
||||
}
|
||||
}
|
||||
catch( std::bad_alloc ) { pp( "Not enough memory." ); retval = 1; }
|
||||
catch( Error e ) { pp(); show_error( e.msg, errno ); retval = 1; }
|
||||
catch( std::bad_alloc & ) { pp( "Not enough memory." ); retval = 1; }
|
||||
catch( Error & e ) { pp(); show_error( e.msg, errno ); retval = 1; }
|
||||
if( verbosity == 1 && retval == 0 )
|
||||
std::fputs( testing ? "ok\n" : "done\n", stderr );
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void signal_handler( int )
|
||||
{
|
||||
show_error( "Control-C or similar caught, quitting." );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
|
||||
|
||||
void set_signals()
|
||||
{
|
||||
std::signal( SIGHUP, signal_handler );
|
||||
std::signal( SIGINT, signal_handler );
|
||||
std::signal( SIGTERM, signal_handler );
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
void set_signal_handler() { set_signals( signal_handler ); }
|
||||
|
||||
int close_outstream( const struct stat * const in_statsp )
|
||||
{
|
||||
|
@ -625,23 +675,15 @@ std::string insert_fixed( std::string name )
|
|||
void show_file_error( const char * const filename, const char * const msg,
|
||||
const int errcode )
|
||||
{
|
||||
if( verbosity < 0 ) return;
|
||||
std::fprintf( stderr, "%s: %s: %s", program_name, filename, msg );
|
||||
if( errcode > 0 ) std::fprintf( stderr, ": %s", std::strerror( errcode ) );
|
||||
std::fputc( '\n', stderr );
|
||||
}
|
||||
|
||||
|
||||
void show_error2( const char * const msg1, const char * const name,
|
||||
const char * const msg2 )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: %s '%s' %s\n", program_name, msg1, name, msg2 );
|
||||
std::fprintf( stderr, "%s: %s: %s%s%s\n", program_name, filename, msg,
|
||||
( errcode > 0 ) ? ": " : "",
|
||||
( errcode > 0 ) ? std::strerror( errcode ) : "" );
|
||||
}
|
||||
|
||||
|
||||
void show_error4( const char * const msg1, const char * const name1,
|
||||
const char * const name2, const char * const msg2 )
|
||||
void show_2file_error( const char * const msg1, const char * const name1,
|
||||
const char * const name2, const char * const msg2 )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: %s '%s' and '%s' %s\n",
|
||||
|
@ -684,6 +726,7 @@ int main( const int argc, const char * const argv[] )
|
|||
{
|
||||
Block range( 0, 0 );
|
||||
Bad_byte bad_byte;
|
||||
Member_list member_list;
|
||||
std::string default_output_filename;
|
||||
std::vector< std::string > filenames;
|
||||
Mode program_mode = m_none;
|
||||
|
@ -695,7 +738,7 @@ int main( const int argc, const char * const argv[] )
|
|||
bool to_stdout = false;
|
||||
invocation_name = argv[0];
|
||||
|
||||
enum { opt_dtd = 256, opt_lt, opt_rtd, opt_std };
|
||||
enum { opt_du = 256, opt_dtd, opt_lt, opt_re, opt_rtd, opt_st, opt_std };
|
||||
const Arg_parser::Option options[] =
|
||||
{
|
||||
{ 'a', "trailing-error", Arg_parser::no },
|
||||
|
@ -721,9 +764,12 @@ int main( const int argc, const char * const argv[] )
|
|||
{ 'X', "show-packets", Arg_parser::maybe },
|
||||
{ 'Y', "debug-delay", Arg_parser::yes },
|
||||
{ 'Z', "debug-repair", Arg_parser::yes },
|
||||
{ opt_du, "dump", Arg_parser::yes },
|
||||
{ opt_dtd, "dump-tdata", Arg_parser::no },
|
||||
{ opt_lt, "loose-trailing", Arg_parser::no },
|
||||
{ opt_re, "remove", Arg_parser::yes },
|
||||
{ opt_rtd, "remove-tdata", Arg_parser::no },
|
||||
{ opt_st, "strip", Arg_parser::yes },
|
||||
{ opt_std, "strip-tdata", Arg_parser::no },
|
||||
{ 0 , 0, Arg_parser::no } };
|
||||
|
||||
|
@ -768,15 +814,24 @@ int main( const int argc, const char * const argv[] )
|
|||
parse_range( arg, range ); break;
|
||||
case 'Z': set_mode( program_mode, m_debug_repair );
|
||||
parse_pos_value( arg, bad_byte ); break;
|
||||
case opt_dtd: set_mode( program_mode, m_dump_tdata ); break;
|
||||
case opt_du: set_mode( program_mode, m_dump );
|
||||
member_list.parse( arg ); break;
|
||||
case opt_dtd: set_mode( program_mode, m_dump );
|
||||
member_list.parse( "tdata" ); break;
|
||||
case opt_lt: loose_trailing = true; break;
|
||||
case opt_rtd: set_mode( program_mode, m_remove_tdata ); break;
|
||||
case opt_std: set_mode( program_mode, m_strip_tdata ); break;
|
||||
case opt_re: set_mode( program_mode, m_remove );
|
||||
member_list.parse( arg ); break;
|
||||
case opt_rtd: set_mode( program_mode, m_remove );
|
||||
member_list.parse( "tdata" ); break;
|
||||
case opt_st: set_mode( program_mode, m_strip );
|
||||
member_list.parse( arg ); break;
|
||||
case opt_std: set_mode( program_mode, m_strip );
|
||||
member_list.parse( "tdata" ); break;
|
||||
default : internal_error( "uncaught option." );
|
||||
}
|
||||
} // end process options
|
||||
|
||||
#if defined(__MSVCRT__) || defined(__OS2__)
|
||||
#if defined(__MSVCRT__) || defined(__OS2__) || defined(__DJGPP__)
|
||||
setmode( STDIN_FILENO, O_BINARY );
|
||||
setmode( STDOUT_FILENO, O_BINARY );
|
||||
#endif
|
||||
|
@ -794,6 +849,7 @@ int main( const int argc, const char * const argv[] )
|
|||
if( filenames.back() != "-" ) filenames_given = true;
|
||||
}
|
||||
|
||||
const char terminator = isatty( STDOUT_FILENO ) ? '\r' : '\n';
|
||||
try {
|
||||
switch( program_mode )
|
||||
{
|
||||
|
@ -804,56 +860,54 @@ int main( const int argc, const char * const argv[] )
|
|||
return debug_decompress( filenames[0], bad_byte, false );
|
||||
case m_debug_delay:
|
||||
one_file( filenames.size() );
|
||||
return debug_delay( filenames[0], range );
|
||||
return debug_delay( filenames[0], range, terminator );
|
||||
case m_debug_repair:
|
||||
one_file( filenames.size() );
|
||||
return debug_repair( filenames[0], bad_byte );
|
||||
return debug_repair( filenames[0], bad_byte, terminator );
|
||||
case m_decompress: break;
|
||||
case m_dump_tdata:
|
||||
case m_strip_tdata:
|
||||
case m_dump:
|
||||
case m_strip:
|
||||
if( filenames.size() < 1 )
|
||||
{ show_error( "You must specify at least 1 file.", 0, true ); return 1; }
|
||||
if( default_output_filename.size() ) set_signals();
|
||||
return dump_tdata( filenames, default_output_filename, force,
|
||||
program_mode == m_strip_tdata, loose_trailing );
|
||||
return dump_members( filenames, default_output_filename, member_list,
|
||||
force, ignore_errors, ignore_trailing,
|
||||
loose_trailing, program_mode == m_strip );
|
||||
case m_list: break;
|
||||
case m_merge:
|
||||
if( filenames.size() < 2 )
|
||||
{ show_error( "You must specify at least 2 files.", 0, true ); return 1; }
|
||||
set_signals();
|
||||
return merge_files( filenames, default_output_filename, force );
|
||||
return merge_files( filenames, default_output_filename, force, terminator );
|
||||
case m_range_dec:
|
||||
one_file( filenames.size() );
|
||||
set_signals();
|
||||
return range_decompress( filenames[0], default_output_filename, range,
|
||||
force, ignore_errors, ignore_trailing,
|
||||
loose_trailing, to_stdout );
|
||||
case m_remove_tdata:
|
||||
case m_remove:
|
||||
if( filenames.size() < 1 )
|
||||
{ show_error( "You must specify at least 1 file.", 0, true ); return 1; }
|
||||
return remove_tdata( filenames, loose_trailing );
|
||||
return remove_members( filenames, member_list, ignore_errors,
|
||||
ignore_trailing, loose_trailing );
|
||||
case m_repair:
|
||||
one_file( filenames.size() );
|
||||
set_signals();
|
||||
return repair_file( filenames[0], default_output_filename, force );
|
||||
return repair_file( filenames[0], default_output_filename, force, terminator );
|
||||
case m_show_packets:
|
||||
one_file( filenames.size() );
|
||||
return debug_decompress( filenames[0], bad_byte, true );
|
||||
case m_split:
|
||||
one_file( filenames.size() );
|
||||
set_signals();
|
||||
return split_file( filenames[0], default_output_filename, force );
|
||||
case m_test: break;
|
||||
}
|
||||
}
|
||||
catch( std::bad_alloc )
|
||||
catch( std::bad_alloc & )
|
||||
{ show_error( "Not enough memory." ); cleanup_and_fail( 1 ); }
|
||||
catch( Error e ) { show_error( e.msg, errno ); cleanup_and_fail( 1 ); }
|
||||
catch( Error & e ) { show_error( e.msg, errno ); cleanup_and_fail( 1 ); }
|
||||
|
||||
if( filenames.empty() ) filenames.push_back("-");
|
||||
|
||||
if( program_mode == m_list )
|
||||
return list_files( filenames, ignore_trailing, loose_trailing );
|
||||
return list_files( filenames, ignore_errors, ignore_trailing,
|
||||
loose_trailing );
|
||||
|
||||
if( program_mode == m_test )
|
||||
outfd = -1;
|
||||
|
@ -862,7 +916,7 @@ int main( const int argc, const char * const argv[] )
|
|||
|
||||
if( !to_stdout && program_mode != m_test &&
|
||||
( filenames_given || default_output_filename.size() ) )
|
||||
set_signals();
|
||||
set_signals( signal_handler );
|
||||
|
||||
Pretty_print pp( filenames );
|
||||
|
||||
|
@ -941,6 +995,12 @@ int main( const int argc, const char * const argv[] )
|
|||
else
|
||||
tmp = decompress( cfile_size, infd, pp, ignore_trailing,
|
||||
loose_trailing, program_mode == m_test );
|
||||
if( close( infd ) != 0 )
|
||||
{
|
||||
show_error( input_filename.size() ? "Error closing input file" :
|
||||
"Error closing stdin", errno );
|
||||
if( tmp < 1 ) tmp = 1;
|
||||
}
|
||||
if( tmp > retval ) retval = tmp;
|
||||
if( tmp )
|
||||
{ if( program_mode != m_test ) cleanup_and_fail( retval );
|
||||
|
@ -950,7 +1010,6 @@ int main( const int argc, const char * const argv[] )
|
|||
close_and_set_permissions( in_statsp );
|
||||
if( input_filename.size() )
|
||||
{
|
||||
close( infd );
|
||||
if( !keep_input_files && !to_stdout && program_mode != m_test )
|
||||
std::remove( input_filename.c_str() );
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue