diff options
Diffstat (limited to 'main.cc')
-rw-r--r-- | main.cc | 118 |
1 files changed, 72 insertions, 46 deletions
@@ -34,20 +34,20 @@ #include <string> #include <vector> #include <fcntl.h> +#include <inttypes.h> #include <pthread.h> -#include <stdint.h> #include <unistd.h> #include <utime.h> #include <sys/stat.h> #include <lzlib.h> -#if CHAR_BIT != 8 -# error "Environments where CHAR_BIT != 8 are not supported." -#endif - #include "arg_parser.h" #include "plzip.h" +#if CHAR_BIT != 8 +#error "Environments where CHAR_BIT != 8 are not supported." +#endif + #ifndef LLONG_MAX #define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL #endif @@ -77,7 +77,7 @@ struct { const char * from; const char * to; } const known_extensions[] = { { ".tlz", ".tar" }, { 0, 0 } }; -struct lzma_options +struct Lzma_options { int dictionary_size; // 4KiB..512MiB int match_len_limit; // 5..273 @@ -87,6 +87,7 @@ enum Mode { m_compress = 0, m_decompress, m_test }; std::string output_filename; int outfd = -1; +mode_t outfd_mode = S_IRUSR | S_IWUSR; bool delete_output_on_interrupt = false; pthread_t main_thread; pid_t main_thread_pid; @@ -99,7 +100,6 @@ void show_help() throw() std::printf( "\nOptions:\n" ); std::printf( " -h, --help display this help and exit\n" ); std::printf( " -V, --version output version information and exit\n" ); -// std::printf( " -b, --member-size=<n> set member size limit in bytes\n" ); std::printf( " -B, --data-size=<n> set input data block size in bytes\n" ); std::printf( " -c, --stdout send output to standard output\n" ); std::printf( " -d, --decompress decompress\n" ); @@ -110,7 +110,6 @@ void show_help() throw() std::printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" ); std::printf( " -q, --quiet suppress all messages\n" ); std::printf( " -s, --dictionary-size=<n> set dictionary size limit in bytes [8MiB]\n" ); -// std::printf( " -S, --volume-size=<n> set volume size limit in bytes\n" ); std::printf( " -t, --test test compressed file integrity\n" ); std::printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" ); std::printf( " -1 .. -9 set compression level [default 6]\n" ); @@ -141,7 +140,31 @@ void show_version() throw() } -long long getnum( const char * ptr, const int bs = 0, +const char * format_num( long long num, long long limit = 9999, + const int set_prefix = 0 ) throw() + { + 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 = false; + static char buf[16]; + + 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 = ""; + limit = std::max( 999LL, std::min( 999999LL, limit ) ); + + for( int i = 0; i < 8 && ( llabs( num ) > limit || + ( llabs( num ) >= factor && num % factor == 0 ) ); ++i ) + { num /= factor; p = prefix[i]; } + snprintf( buf, sizeof buf, "%lld %s", num, p ); + return buf; + } + + +long long getnum( const char * const ptr, const int bs = 0, const long long llimit = LLONG_MIN + 1, const long long ulimit = LLONG_MAX ) throw() { @@ -199,7 +222,7 @@ long long getnum( const char * ptr, const int bs = 0, } -int get_dict_size( const char * arg ) throw() +int get_dict_size( const char * const arg ) throw() { char *tail; int bits = std::strtol( arg, &tail, 0 ); @@ -223,7 +246,7 @@ int extension_index( const std::string & name ) throw() } -int open_instream( const std::string & name, struct stat * in_statsp, +int open_instream( const std::string & name, struct stat * const in_statsp, const Mode program_mode, const int eindex, const bool force, const bool to_stdout ) throw() { @@ -293,13 +316,10 @@ void set_d_outname( const std::string & name, const int i ) throw() bool open_outstream( const bool force ) throw() { - if( force ) - outfd = open( output_filename.c_str(), - O_CREAT | O_TRUNC | O_WRONLY | o_binary, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); - else outfd = open( output_filename.c_str(), - O_CREAT | O_EXCL | O_WRONLY | o_binary, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); + int flags = O_CREAT | O_WRONLY | o_binary; + if( force ) flags |= O_TRUNC; else flags |= O_EXCL; + + outfd = open( output_filename.c_str(), flags, outfd_mode ); if( outfd < 0 ) { if( errno == EEXIST ) outfd = -2; else outfd = -1; @@ -393,11 +413,11 @@ void set_signals( const bool to_file ) throw() { if( to_file ) { - signal( SIGHUP, signal_handler ); - signal( SIGINT, signal_handler ); - signal( SIGTERM, signal_handler ); + std::signal( SIGHUP, signal_handler ); + std::signal( SIGINT, signal_handler ); + std::signal( SIGTERM, signal_handler ); } - signal( SIGUSR1, signal_handler ); + std::signal( SIGUSR1, signal_handler ); } } // end namespace @@ -406,6 +426,12 @@ void set_signals( const bool to_file ) throw() int verbosity = 0; +// This can be called from any thread, main thread or sub-threads alike, since +// they all call common helper functions that call fatal() in case of an error. +// +void fatal() { signal_handler( SIGUSR1 ); } + + void Pretty_print::operator()( const char * const msg ) const throw() { if( verbosity >= 0 ) @@ -423,7 +449,7 @@ void Pretty_print::operator()( const char * const msg ) const throw() } -void show_error( const char * msg, const int errcode, const bool help ) throw() +void show_error( const char * const msg, const int errcode, const bool help ) throw() { if( verbosity >= 0 ) { @@ -439,7 +465,7 @@ void show_error( const char * msg, const int errcode, const bool help ) throw() } -void internal_error( const char * msg ) +void internal_error( const char * const msg ) { std::string s( "internal error: " ); s += msg; show_error( s.c_str() ); @@ -447,16 +473,10 @@ void internal_error( const char * msg ) } -// This can be called from any thread, main thread or sub-threads alike, since -// they all call common helper functions that call fatal() in case of an error. -// -void fatal() { signal_handler( SIGUSR1 ); } - - // Returns the number of bytes really read. // If (returned value < size) and (errno == 0), means EOF was reached. // -int readblock( const int fd, uint8_t * buf, const int size ) throw() +int readblock( const int fd, uint8_t * const buf, const int size ) throw() { int rest = size; errno = 0; @@ -475,7 +495,7 @@ int readblock( const int fd, uint8_t * buf, const int size ) throw() // Returns the number of bytes really written. // If (returned value < size), it is always an error. // -int writeblock( const int fd, const uint8_t * buf, const int size ) throw() +int writeblock( const int fd, const uint8_t * const buf, const int size ) throw() { int rest = size; errno = 0; @@ -490,22 +510,23 @@ int writeblock( const int fd, const uint8_t * buf, const int size ) throw() } -int main( const int argc, const char * argv[] ) +int main( const int argc, const char * const argv[] ) { // Mapping from gzip/bzip2 style 1..9 compression modes // to the corresponding LZMA compression modes. - const lzma_options option_mapping[] = + const Lzma_options option_mapping[] = { + { 1 << 16, 5 }, // -0 { 1 << 20, 10 }, // -1 - { 1 << 20, 12 }, // -2 - { 1 << 20, 17 }, // -3 - { 1 << 21, 26 }, // -4 + { 3 << 19, 12 }, // -2 + { 1 << 21, 17 }, // -3 + { 3 << 20, 26 }, // -4 { 1 << 22, 44 }, // -5 { 1 << 23, 80 }, // -6 { 1 << 24, 108 }, // -7 - { 1 << 24, 163 }, // -8 + { 3 << 23, 163 }, // -8 { 1 << 25, 273 } }; // -9 - lzma_options encoder_options = option_mapping[5]; // default = "-6" + Lzma_options encoder_options = option_mapping[6]; // default = "-6" int data_size = 0; int debug_level = 0; int infd = -1; @@ -533,6 +554,7 @@ int main( const int argc, const char * argv[] ) const Arg_parser::Option options[] = { + { '0', 0, Arg_parser::no }, { '1', "fast", Arg_parser::no }, { '2', 0, Arg_parser::no }, { '3', 0, Arg_parser::no }, @@ -546,6 +568,7 @@ int main( const int argc, const char * argv[] ) { 'B', "data-size", Arg_parser::yes }, { 'c', "stdout", Arg_parser::no }, { 'd', "decompress", Arg_parser::no }, + { 'e', "extreme", Arg_parser::no }, { 'D', "debug", Arg_parser::yes }, { 'f', "force", Arg_parser::no }, { 'h', "help", Arg_parser::no }, @@ -570,20 +593,19 @@ int main( const int argc, const char * argv[] ) { const int code = parser.code( argind ); if( !code ) break; // no more options - const char * arg = parser.argument( argind ).c_str(); + const char * const arg = parser.argument( argind ).c_str(); switch( code ) { - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - encoder_options = option_mapping[code-'1']; break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + encoder_options = option_mapping[code-'0']; break; case 'b': break; case 'B': data_size = getnum( arg, 0, 2 * LZ_min_dictionary_size(), 2 * LZ_max_dictionary_size() ); break; case 'c': to_stdout = true; break; case 'd': program_mode = m_decompress; break; - case 'D': debug_level = getnum( arg, 0, 0, 3 ); - break; + case 'D': debug_level = getnum( arg, 0, 0, 3 ); break; + case 'e': break; case 'f': force = true; break; case 'h': show_help(); return 0; case 'k': keep_input_files = true; break; @@ -605,6 +627,8 @@ int main( const int argc, const char * argv[] ) if( data_size <= 0 ) data_size = 2 * std::max( 65536, encoder_options.dictionary_size ); + else if( data_size < encoder_options.dictionary_size ) + encoder_options.dictionary_size = std::max( data_size, LZ_min_dictionary_size() ); if( num_workers <= 0 ) { @@ -648,6 +672,7 @@ int main( const int argc, const char * argv[] ) if( program_mode == m_compress ) set_c_outname( default_output_filename ); else output_filename = default_output_filename; + outfd_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; if( !open_outstream( force ) ) { if( outfd == -1 && retval < 1 ) retval = 1; @@ -672,6 +697,7 @@ int main( const int argc, const char * argv[] ) if( program_mode == m_compress ) set_c_outname( input_filename ); else set_d_outname( input_filename, eindex ); + outfd_mode = S_IRUSR | S_IWUSR; if( !open_outstream( force ) ) { if( outfd == -1 && retval < 1 ) retval = 1; |