diff options
Diffstat (limited to 'main.cc')
-rw-r--r-- | main.cc | 218 |
1 files changed, 103 insertions, 115 deletions
@@ -1,5 +1,5 @@ /* Lziprecover - Data recovery tool for lzipped files - Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz. + Copyright (C) 2009, 2010, 2011, 2012, 2013 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,6 +38,7 @@ #include <utime.h> #include <sys/stat.h> #if defined(__MSVCRT__) +#include <io.h> #define fchmod(x,y) 0 #define fchown(x,y,z) 0 #define SIGHUP SIGTERM @@ -47,6 +48,9 @@ #define S_IROTH 0 #define S_IWOTH 0 #endif +#if defined(__OS2__) +#include <io.h> +#endif #include "arg_parser.h" #include "lzip.h" @@ -61,7 +65,7 @@ namespace { const char * const Program_name = "Lziprecover"; const char * const program_name = "lziprecover"; -const char * const program_year = "2012"; +const char * const program_year = "2013"; const char * invocation_name = 0; #ifdef O_BINARY @@ -80,6 +84,7 @@ enum Mode { m_none, m_decompress, m_generate, m_list, m_merge, m_range, std::string output_filename; int outfd = -1; +int verbosity = 0; const mode_t usr_rw = S_IRUSR | S_IWUSR; const mode_t all_rw = usr_rw | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; mode_t outfd_mode = usr_rw; @@ -125,10 +130,30 @@ void show_version() "There is NO WARRANTY, to the extent permitted by law.\n" ); } +} // end namespace + +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 ); + + 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, "version %d, dictionary size %s%4u %sB. ", + header.version(), np, num, p ); + } + +namespace { -void one_file( const int argind, const int arguments ) +void one_file( const int files ) { - if( argind + 1 != arguments ) + if( files != 1 ) { show_error( "You must specify exactly 1 file.", 0, true ); std::exit( 1 ); @@ -159,6 +184,40 @@ int extension_index( const std::string & name ) return -1; } +} // end namespace + +int open_instream( const std::string & name, struct stat * const in_statsp, + const bool to_stdout, const bool reg_only ) + { + int infd = open( name.c_str(), O_RDONLY | o_binary ); + if( infd < 0 ) + { + if( verbosity >= 0 ) + std::fprintf( stderr, "%s: Can't open input file '%s': %s.\n", + program_name, name.c_str(), std::strerror( errno ) ); + } + else + { + const int i = fstat( infd, in_statsp ); + const mode_t mode = in_statsp->st_mode; + const bool can_read = ( i == 0 && !reg_only && + ( S_ISBLK( mode ) || S_ISCHR( mode ) || + S_ISFIFO( mode ) || S_ISSOCK( mode ) ) ); + if( i != 0 || ( !S_ISREG( mode ) && ( !to_stdout || !can_read ) ) ) + { + if( verbosity >= 0 ) + std::fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n", + program_name, name.c_str(), + ( can_read && !to_stdout ) ? + " and '--stdout' was not specified" : "" ); + close( infd ); + infd = -1; + } + } + return infd; + } + +namespace { void set_d_outname( const std::string & name, const int i ) { @@ -300,16 +359,17 @@ void show_trailing_garbage( const uint8_t * const data, const int size, int decompress( const int infd, const Pretty_print & pp, const bool testing ) { + const char * const ok_msg = ( testing ? "ok\n" : "done\n" ); int retval = 0; try { + unsigned long long partial_file_pos = 0; Range_decoder rdec( infd ); - long long partial_file_pos = 0; - for( bool first_member = true; ; first_member = false, pp.reset() ) + for( bool first_member = true; ; first_member = false ) { File_header header; rdec.reset_member_position(); - const int size = rdec.read( header.data, File_header::size ); + const int size = rdec.read_data( header.data, File_header::size ); if( rdec.finished() ) // End Of File { if( first_member ) @@ -339,13 +399,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 >= 2 ) - std::fprintf( stderr, "version %d, dictionary size %7sB. ", - header.version(), - format_num( header.dictionary_size(), 9999, -1 ) ); - } + { pp(); if( verbosity >= 2 ) show_header( header ); } LZ_decoder decoder( header, rdec, outfd ); const int result = decoder.decode_member( pp ); @@ -356,17 +410,15 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing ) { pp(); if( result == 2 ) - std::fprintf( stderr, "File ends unexpectedly at pos %lld\n", + std::fprintf( stderr, "File ends unexpectedly at pos %llu\n", partial_file_pos ); else - std::fprintf( stderr, "Decoder error at pos %lld\n", + std::fprintf( stderr, "Decoder error at pos %llu\n", partial_file_pos ); } retval = 2; break; } - if( verbosity >= 2 ) - { if( testing ) std::fprintf( stderr, "ok\n" ); - else std::fprintf( stderr, "done\n" ); } + if( verbosity >= 2 ) { std::fprintf( stderr, ok_msg ); pp.reset(); } } } catch( std::bad_alloc ) @@ -375,9 +427,7 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing ) retval = 1; } catch( Error e ) { pp(); show_error( e.msg, errno ); retval = 1; } - if( verbosity == 1 && retval == 0 ) - { if( testing ) std::fprintf( stderr, "ok\n" ); - else std::fprintf( stderr, "done\n" ); } + if( verbosity == 1 && retval == 0 ) std::fprintf( stderr, ok_msg ); return retval; } @@ -399,65 +449,6 @@ void set_signals() } // end namespace -int verbosity = 0; - - -const char * format_num( long long num, 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 int 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 && ( llabs( num ) > limit || - ( exact && llabs( num ) >= factor ) ); ++i ) - { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; } - snprintf( buf, sizeof buf, "%lld %s", num, p ); - return buf; - } - - -int open_instream( const std::string & name, struct stat * const in_statsp, - const bool to_stdout, const bool reg_only ) - { - int infd = open( name.c_str(), O_RDONLY | o_binary ); - if( infd < 0 ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "%s: Can't open input file '%s': %s.\n", - program_name, name.c_str(), std::strerror( errno ) ); - } - else - { - const int i = fstat( infd, in_statsp ); - const mode_t & mode = in_statsp->st_mode; - const bool can_read = ( i == 0 && !reg_only && - ( S_ISBLK( mode ) || S_ISCHR( mode ) || - S_ISFIFO( mode ) || S_ISSOCK( mode ) ) ); - if( i != 0 || ( !S_ISREG( mode ) && ( !to_stdout || !can_read ) ) ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n", - program_name, name.c_str(), - ( can_read && !to_stdout ) ? - " and '--stdout' was not specified" : "" ); - close( infd ); - infd = -1; - } - } - return infd; - } - - int open_outstream_rw( const std::string & output_filename, const bool force ) { @@ -490,7 +481,7 @@ void show_error( const char * const msg, const int errcode, const bool help ) std::fprintf( stderr, ": %s", std::strerror( errcode ) ); std::fprintf( stderr, "\n" ); } - if( help && invocation_name && invocation_name[0] ) + if( help ) std::fprintf( stderr, "Try '%s --help' for more information.\n", invocation_name ); } @@ -507,15 +498,15 @@ void internal_error( const char * const msg ) int main( const int argc, const char * const argv[] ) { + 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; bool force = false; bool keep_input_files = false; bool to_stdout = false; - std::string input_filename; - std::string default_output_filename; - std::string range_string; - std::vector< std::string > filenames; invocation_name = argv[0]; const Arg_parser::Option options[] = @@ -546,7 +537,7 @@ int main( const int argc, const char * const argv[] ) { const int code = parser.code( argind ); if( !code ) break; // no more options - const std::string & arg = parser.argument( argind ).c_str(); + const std::string & arg = parser.argument( argind ); switch( code ) { case 'c': to_stdout = true; break; @@ -570,8 +561,8 @@ int main( const int argc, const char * const argv[] ) } // end process options #if defined(__MSVCRT__) || defined(__OS2__) - _fsetmode( stdin, "b" ); - _fsetmode( stdout, "b" ); + setmode( STDIN_FILENO, O_BINARY ); + setmode( STDOUT_FILENO, O_BINARY ); #endif if( program_mode == m_none ) @@ -580,6 +571,13 @@ int main( const int argc, const char * const argv[] ) return 1; } + bool filenames_given = false; + for( ; argind < parser.arguments(); ++argind ) + { + filenames.push_back( parser.argument( argind ) ); + if( filenames.back() != "-" ) filenames_given = true; + } + switch( program_mode ) { case m_generate: @@ -588,29 +586,27 @@ int main( const int argc, const char * const argv[] ) case m_none: internal_error( "invalid operation" ); break; case m_decompress: break; case m_list: - one_file( argind, parser.arguments() ); - return list_file( parser.argument( argind ) ); + if( filenames.size() < 1 ) + { show_error( "You must specify at least 1 file.", 0, true ); return 1; } + return list_files( filenames, verbosity ); case m_merge: - for( ; argind < parser.arguments(); ++argind ) - filenames.push_back( parser.argument( argind ) ); if( filenames.size() < 2 ) { show_error( "You must specify at least 2 files.", 0, true ); return 1; } if( !default_output_filename.size() ) default_output_filename = insert_fixed( filenames[0] ); - return merge_files( filenames, default_output_filename, force ); + return merge_files( filenames, default_output_filename, verbosity, force ); case m_range: - one_file( argind, parser.arguments() ); - return range_decompress( parser.argument( argind ), - default_output_filename, range_string, - to_stdout, force ); + one_file( filenames.size() ); + return range_decompress( filenames[0], default_output_filename, + range_string, verbosity, force, to_stdout ); case m_repair: - one_file( argind, parser.arguments() ); + one_file( filenames.size() ); if( !default_output_filename.size() ) - default_output_filename = insert_fixed( parser.argument( argind ) ); - return repair_file( parser.argument( argind ), default_output_filename, force ); + default_output_filename = insert_fixed( filenames[0] ); + return repair_file( filenames[0], default_output_filename, verbosity, force ); case m_split: - one_file( argind, parser.arguments() ); - return split_file( parser.argument( argind ), default_output_filename, force ); + one_file( filenames.size() ); + return split_file( filenames[0], default_output_filename, verbosity, force ); case m_test: break; } @@ -619,13 +615,6 @@ int main( const int argc, const char * const argv[] ) else if( program_mode != m_decompress ) internal_error( "invalid decompressor operation" ); - bool filenames_given = false; - for( ; argind < parser.arguments(); ++argind ) - { - if( parser.argument( argind ) != "-" ) filenames_given = true; - filenames.push_back( parser.argument( argind ) ); - } - if( filenames.empty() ) filenames.push_back("-"); if( !to_stdout && program_mode != m_test && ( filenames_given || default_output_filename.size() ) ) @@ -634,7 +623,7 @@ int main( const int argc, const char * const argv[] ) Pretty_print pp( filenames, verbosity ); int retval = 0; - for( unsigned int i = 0; i < filenames.size(); ++i ) + for( unsigned i = 0; i < filenames.size(); ++i ) { struct stat in_stats; output_filename.clear(); @@ -653,7 +642,7 @@ int main( const int argc, const char * const argv[] ) outfd_mode = all_rw; if( !open_outstream( force ) ) { - if( outfd == -1 && retval < 1 ) retval = 1; + if( retval < 1 ) retval = 1; close( infd ); infd = -1; continue; } @@ -663,7 +652,6 @@ int main( const int argc, const char * const argv[] ) else { input_filename = filenames[i]; - const int eindex = extension_index( input_filename ); infd = open_instream( input_filename, &in_stats, to_stdout ); if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; } if( program_mode != m_test ) @@ -671,11 +659,11 @@ int main( const int argc, const char * const argv[] ) if( to_stdout ) outfd = STDOUT_FILENO; else { - set_d_outname( input_filename, eindex ); + set_d_outname( input_filename, extension_index( input_filename ) ); outfd_mode = usr_rw; if( !open_outstream( force ) ) { - if( outfd == -1 && retval < 1 ) retval = 1; + if( retval < 1 ) retval = 1; close( infd ); infd = -1; continue; } |