diff options
Diffstat (limited to '')
-rw-r--r-- | main.c | 196 |
1 files changed, 105 insertions, 91 deletions
@@ -1,9 +1,17 @@ /* Pdlzip - LZMA lossless data compressor 2009-08-14 : Igor Pavlov : Public domain - Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. + Copyright (C) 2010-2015 Antonio Diaz Diaz. - This program is free software: you have unlimited permission - to copy, distribute and modify it. + This program is free software. Redistribution and use in source and + binary forms, with or without modification, are permitted provided + that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -49,6 +57,10 @@ #include "LzmaDec.h" #include "LzmaEnc.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #if CHAR_BIT != 8 #error "Environments where CHAR_BIT != 8 are not supported." #endif @@ -56,15 +68,9 @@ const char * const Program_name = "Pdlzip"; const char * const program_name = "pdlzip"; -const char * const program_year = "2013"; +const char * const program_year = "2015"; const char * invocation_name = 0; -#ifdef O_BINARY -const int o_binary = O_BINARY; -#else -const int o_binary = 0; -#endif - struct { const char * from; const char * to; } const known_extensions[] = { { ".lz", "" }, { ".tlz", ".tar" }, @@ -130,39 +136,23 @@ static void show_help( void ) static void show_version( void ) { - printf( "%s %s\n", Program_name, PROGVERSION ); + printf( "%s %s\n", program_name, PROGVERSION ); printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year ); printf( "Public Domain 2009 Igor Pavlov.\n" + "License 2-clause BSD.\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n" ); } -static const char * format_num( unsigned num ) - { - const char * const prefix[8] = - { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; - enum { buf_size = 16, factor = 1024 }; - static char buf[buf_size]; - const char * p = ""; - bool exact = ( num % factor == 0 ); - int i; - - for( i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i ) - { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; } - snprintf( buf, buf_size, "%u %s", num, p ); - return buf; - } - - -static void show_header( const File_header header ) +static void show_header( const unsigned dictionary_size ) { const char * const prefix[8] = { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; enum { factor = 1024 }; const char * p = ""; const char * np = " "; - unsigned num = Fh_get_dictionary_size( header ), i; + unsigned num = dictionary_size, i; bool exact = ( num % factor == 0 ); for( i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i ) @@ -245,8 +235,10 @@ static int extension_index( const char * const name ) for( i = 0; known_extensions[i].from; ++i ) { const char * const ext = known_extensions[i].from; - if( strlen( name ) > strlen( ext ) && - strncmp( name + strlen( name ) - strlen( ext ), ext, strlen( ext ) ) == 0 ) + const unsigned name_len = strlen( name ); + const unsigned ext_len = strlen( ext ); + if( name_len > ext_len && + strncmp( name + name_len - ext_len, ext, ext_len ) == 0 ) return i; } return -1; @@ -266,7 +258,7 @@ static int open_instream( const char * const name, struct stat * const in_statsp } else { - infd = open( name, O_RDONLY | o_binary ); + infd = open( name, O_RDONLY | O_BINARY ); if( infd < 0 ) { if( verbosity >= 0 ) @@ -322,20 +314,21 @@ static void set_c_outname( const char * const name ) static void set_d_outname( const char * const name, const int i ) { + const unsigned name_len = strlen( name ); if( i >= 0 ) { const char * const from = known_extensions[i].from; - if( strlen( name ) > strlen( from ) ) + const unsigned from_len = strlen( from ); + if( name_len > from_len ) { - output_filename = resize_buffer( output_filename, strlen( name ) + + output_filename = resize_buffer( output_filename, name_len + strlen( known_extensions[0].to ) + 1 ); strcpy( output_filename, name ); - strcpy( output_filename + strlen( name ) - strlen( from ), - known_extensions[i].to ); + strcpy( output_filename + name_len - from_len, known_extensions[i].to ); return; } } - output_filename = resize_buffer( output_filename, strlen( name ) + 4 + 1 ); + output_filename = resize_buffer( output_filename, name_len + 4 + 1 ); strcpy( output_filename, name ); strcat( output_filename, ".out" ); if( verbosity >= 1 ) @@ -346,7 +339,7 @@ static void set_d_outname( const char * const name, const int i ) static bool open_outstream( const bool force ) { - int flags = O_CREAT | O_WRONLY | o_binary; + int flags = O_CREAT | O_WRONLY | O_BINARY; if( force ) flags |= O_TRUNC; else flags |= O_EXCL; outfd = open( output_filename, flags, outfd_mode ); @@ -365,7 +358,7 @@ static bool open_outstream( const bool force ) static bool check_tty( const int infd, const enum Mode program_mode ) { - if( program_mode == m_compress && outfd >= 0 && isatty( outfd ) ) + if( program_mode == m_compress && isatty( outfd ) ) { show_error( "I won't write compressed data to a terminal.", 0, true ); return false; @@ -402,10 +395,14 @@ static void close_and_set_permissions( const struct stat * const in_statsp ) bool warning = false; if( in_statsp ) { + const mode_t mode = in_statsp->st_mode; /* fchown will in many cases return with EPERM, which can be safely ignored. */ - if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 && - errno != EPERM ) || - fchmod( outfd, in_statsp->st_mode ) != 0 ) warning = true; + if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 ) + { if( fchmod( outfd, mode ) != 0 ) warning = true; } + else + if( errno != EPERM || + fchmod( outfd, mode & ~( S_ISUID | S_ISGID | S_ISVTX ) ) != 0 ) + warning = true; } if( close( outfd ) != 0 ) cleanup_and_fail( 1 ); outfd = -1; @@ -426,21 +423,21 @@ static int compress( const struct Lzma_options * const encoder_options, const int infd, struct Pretty_print * const pp ) { int retval = 0; - CLzmaEncHandle encoder; + CLzmaEncHandle encoder = 0; File_header header; Fh_set_magic( header ); if( verbosity >= 1 ) Pp_show_msg( pp, 0 ); - if( !Fh_set_dictionary_size( header, encoder_options->dictionary_size ) || - encoder_options->match_len_limit < min_match_len_limit || - encoder_options->match_len_limit > max_match_len ) - internal_error( "invalid argument to encoder" ); + if( Fh_set_dictionary_size( header, encoder_options->dictionary_size ) && + encoder_options->match_len_limit >= min_match_len_limit && + encoder_options->match_len_limit <= max_match_len ) + encoder = LzmaEnc_Init( Fh_get_dictionary_size( header ), + encoder_options->match_len_limit, infd, outfd ); + else internal_error( "invalid argument to encoder." ); - encoder = LzmaEnc_Init( Fh_get_dictionary_size( header ), - encoder_options->match_len_limit, infd, outfd ); if( !encoder ) { - Pp_show_msg( pp, "Not enough memory. Try a smaller dictionary size" ); + Pp_show_msg( pp, "Not enough memory. Try a smaller dictionary size." ); return 1; } @@ -448,7 +445,7 @@ static int compress( const struct Lzma_options * const encoder_options, { show_error( "Can not write output file", errno, false ); retval = 1; } else if( LzmaEnc_Encode( encoder ) != 0 ) - { Pp_show_msg( pp, "Encoder error" ); retval = 1; } + { Pp_show_msg( pp, "Encoder error." ); retval = 1; } LzmaEnc_Free( encoder ); return retval; } @@ -529,8 +526,7 @@ static int lzma_decode( uint64_t unpackSize, CLzmaDec *decoder, const int infd, ( !thereIsSize && status != LZMA_STATUS_FINISHED_WITH_MARK ) ) { show_error( "Data error.", 0, false ); return 2; } if( verbosity >= 2 ) - fprintf( stderr, "lzma-alone, dictionary size %7sB. ", - format_num( decoder->dicBufSize ) ); + { fprintf( stderr, "lzma-alone, " ); show_header( decoder->dicBufSize ); } if( verbosity >= 3 ) fprintf( stderr, "uncompressed size %9llu, compressed size %8llu. ", total_out, total_in ); @@ -652,13 +648,14 @@ static int decompress( const int infd, struct Pretty_print * const pp, for( first_member = true; ; first_member = false ) { int i; + unsigned dictionary_size = 0; File_header header; if( inSize - inPos < lzma_header_size && !read_inbuf( infd, inBuf, &inPos, &inSize ) ) return 1; if( inSize - inPos <= Fh_size ) /* End Of File */ { if( first_member ) - { Pp_show_msg( pp, "File ends unexpectedly at member header" ); + { Pp_show_msg( pp, "File ends unexpectedly at member header." ); retval = 2; } break; } @@ -678,7 +675,7 @@ static int decompress( const int infd, struct Pretty_print * const pp, } if( lzip_mode ) { - Pp_show_msg( pp, "Bad magic number (file not in lzip format)" ); + Pp_show_msg( pp, "Bad magic number (file not in lzip format)." ); retval = 2; break; } } @@ -693,25 +690,24 @@ static int decompress( const int infd, struct Pretty_print * const pp, Fh_version( header ) ); } retval = 2; break; } - if( Fh_get_dictionary_size( header ) < min_dictionary_size || - Fh_get_dictionary_size( header ) > max_dictionary_size ) - { Pp_show_msg( pp, "Invalid dictionary size in member header" ); + dictionary_size = Fh_get_dictionary_size( header ); + if( dictionary_size < min_dictionary_size || + dictionary_size > max_dictionary_size ) + { Pp_show_msg( pp, "Invalid dictionary size in member header." ); retval = 2; break; } raw_props[0] = 93; /* (45 * 2) + (9 * 0) + 3 */ - ds = Fh_get_dictionary_size( header ); + ds = dictionary_size; for( i = 1; i <= 4; ++i ) { raw_props[i] = ds & 0xFF; ds >>= 8; } } if( verbosity >= 2 || ( verbosity == 1 && first_member ) ) - { - Pp_show_msg( pp, 0 ); - if( lzip_mode && verbosity >= 3 ) show_header( header ); - } + { Pp_show_msg( pp, 0 ); + if( lzip_mode && verbosity >= 3 ) show_header( dictionary_size ); } if( !LzmaDec_Init( &decoder, raw_props ) ) { - show_error( "Not enough memory. Find a machine with more memory.", 0, false ); + show_error( "Not enough memory.", 0, false ); cleanup_and_fail( 1 ); } if( lzip_mode ) @@ -746,25 +742,7 @@ static void set_signals( void ) } -void Pp_init( struct Pretty_print * const pp, const char * const filenames[], - const int num_filenames ) - { - unsigned stdin_name_len; - int i; - pp->name = 0; - pp->stdin_name = "(stdin)"; - pp->longest_name = 0; - pp->first_post = false; - stdin_name_len = strlen( pp->stdin_name ); - - for( i = 0; i < num_filenames; ++i ) - { - const char * const s = filenames[i]; - const int len = ( (strcmp( s, "-" ) == 0) ? stdin_name_len : strlen( s ) ); - if( len > pp->longest_name ) pp->longest_name = len; - } - if( pp->longest_name == 0 ) pp->longest_name = stdin_name_len; - } +CRC32 crc32; void Pp_show_msg( struct Pretty_print * const pp, const char * const msg ) @@ -780,8 +758,45 @@ void Pp_show_msg( struct Pretty_print * const pp, const char * const msg ) for( i = 0; i < len; ++i ) fprintf( stderr, " " ); if( !msg ) fflush( stderr ); } - if( msg ) fprintf( stderr, "%s.\n", msg ); + if( msg ) fprintf( stderr, "%s\n", msg ); + } + } + + +/* 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 * const buf, const int size ) + { + int sz = 0; + errno = 0; + while( sz < size ) + { + const int n = read( fd, buf + sz, size - sz ); + if( n > 0 ) sz += n; + else if( n == 0 ) break; /* EOF */ + else if( errno != EINTR ) break; + errno = 0; + } + return sz; + } + + +/* Returns the number of bytes really written. + If (returned value < size), it is always an error. +*/ +int writeblock( const int fd, const uint8_t * const buf, const int size ) + { + int sz = 0; + errno = 0; + while( sz < size ) + { + const int n = write( fd, buf + sz, size - sz ); + if( n > 0 ) sz += n; + else if( n < 0 && errno != EINTR ) break; + errno = 0; } + return sz; } @@ -792,7 +807,7 @@ void show_error( const char * const msg, const int errcode, const bool help ) if( msg && msg[0] ) { fprintf( stderr, "%s: %s", program_name, msg ); - if( errcode > 0 ) fprintf( stderr, ": %s", strerror( errcode ) ); + if( errcode > 0 ) fprintf( stderr, ": %s.", strerror( errcode ) ); fprintf( stderr, "\n" ); } if( help ) @@ -805,7 +820,7 @@ void show_error( const char * const msg, const int errcode, const bool help ) void internal_error( const char * const msg ) { if( verbosity >= 0 ) - fprintf( stderr, "%s: internal error: %s.\n", program_name, msg ); + fprintf( stderr, "%s: internal error: %s\n", program_name, msg ); exit( 3 ); } @@ -879,7 +894,7 @@ int main( const int argc, const char * const argv[] ) CRC32_init(); if( !ap_init( &parser, argc, argv, options, 0 ) ) - { show_error( "Memory exhausted.", 0, false ); return 1; } + { show_error( "Not enough memory.", 0, false ); return 1; } if( ap_error( &parser ) ) /* bad option */ { show_error( ap_error( &parser ), 0, true ); return 1; } @@ -890,8 +905,7 @@ int main( const int argc, const char * const argv[] ) if( !code ) break; /* no more options */ switch( code ) { - case '0': - case '1': case '2': case '3': case '4': + 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; @@ -912,7 +926,7 @@ int main( const int argc, const char * const argv[] ) case 't': program_mode = m_test; break; case 'v': if( verbosity < 4 ) ++verbosity; break; case 'V': show_version(); return 0; - default : internal_error( "uncaught option" ); + default : internal_error( "uncaught option." ); } } /* end process options */ |