diff options
Diffstat (limited to 'in_place.c')
-rw-r--r-- | in_place.c | 72 |
1 files changed, 39 insertions, 33 deletions
@@ -1,18 +1,18 @@ -/* Xlunzip - Test tool for the lzip_decompress linux module - Copyright (C) 2016-2020 Antonio Diaz Diaz. +/* Xlunzip - Test tool for the lzip_decompress linux module + Copyright (C) 2016-2020 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 - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. + 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 + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define _FILE_OFFSET_BITS 64 @@ -58,8 +58,7 @@ static uint8_t * read_file( const int infd, long * const buffer_sizep, { long buffer_size = 1 << 20; uint8_t * buffer = (uint8_t *)malloc( buffer_size ); - if( !buffer ) - { show_file_error( filename, "Not enough memory.", 0 ); return 0; } + if( !buffer ) { show_file_error( filename, mem_msg, 0 ); return 0; } long file_size = readblock( infd, buffer, buffer_size ); while( file_size >= buffer_size && !errno ) @@ -70,8 +69,7 @@ static uint8_t * read_file( const int infd, long * const buffer_sizep, buffer_size = ( buffer_size <= LONG_MAX / 2 ) ? 2 * buffer_size : LONG_MAX; uint8_t * const tmp = (uint8_t *)realloc( buffer, buffer_size ); if( !tmp ) - { show_file_error( filename, "Not enough memory.", 0 ); free( buffer ); - return 0; } + { show_file_error( filename, mem_msg, 0 ); free( buffer ); return 0; } buffer = tmp; file_size += readblock( infd, buffer + file_size, buffer_size - file_size ); } @@ -88,6 +86,7 @@ struct File_sizes { unsigned long long csize; unsigned long long dsize; + long members; long trailing; }; @@ -102,7 +101,8 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes, if( !Lh_verify_version( *header ) ) return "Version of lzip member format not supported."; - file_sizes->csize = file_sizes->dsize = file_sizes->trailing = 0; + file_sizes->csize = file_sizes->dsize = 0; + file_sizes->members = file_sizes->trailing = 0; unsigned long pos = file_size; /* always points to a header or to EOF */ while( pos >= min_member_size ) { @@ -137,6 +137,7 @@ static const char * set_file_sizes( struct File_sizes * const file_sizes, pos -= member_size; file_sizes->csize += member_size; file_sizes->dsize += Lt_get_data_size( *trailer ); + ++file_sizes->members; } if( pos != 0 || file_sizes->csize == 0 ) return "Can't get file sizes."; if( file_sizes->csize + file_sizes->trailing != (unsigned long)file_size ) @@ -154,13 +155,15 @@ static void error(char *x) { show_file_error( global_name, x, 0 ); } /* * Load the compressed file at the end of the buffer used to hold the * decompressed data. Verify that the in-place decompression does not - * overwrite the compressed data. + * overwrite the compressed data. The buffer must be large enough to contain + * after the decompressed data extra space for a marker, a trailer, the + * maximum possible data expansion, and (if multimember) N-1 empty members. * - * |----- compressed data ------| - * V V - * |---------------|-------------------|--------| - * ^ ^ - * |------- decompressed data ---------| + * |------ compressed data ------| + * V V + * |----------------|-------------------|---------| + * ^ ^ extra + * |-------- decompressed data ---------| */ int decompress_in_place( const int infd, struct Pretty_print * const pp, @@ -175,19 +178,22 @@ int decompress_in_place( const int infd, struct Pretty_print * const pp, const long csize = file_sizes.csize; const long dsize = file_sizes.dsize; - /* const long trailing = file_sizes.trailing; */ - /* ( (csize-36+63) >> 6 ) + 36 never failed with single member */ - const long rextra = ( csize >> 5 ) + 72; - if( buffer_size < dsize + rextra ) /* avoid realloc if big enough */ +/* const long extra_bytes = ( dsize >> 8 ) + 65536; wrong linux formula */ + const long extra_bytes = ( csize >> 6 ) + file_sizes.members * 36; + const long long target_buffer_size = max( dsize, csize ) + extra_bytes; + if( target_buffer_size > LONG_MAX ) + { show_file_error( pp->name, "Buffer is larger than LONG_MAX.", 0 ); + return 1; } + if( buffer_size < target_buffer_size ) /* avoid realloc if big enough */ { - buffer_size = dsize + rextra; - buffer = (uint8_t *)realloc( buffer, buffer_size ); - if( !buffer ) - { show_file_error( pp->name, "Not enough memory.", 0 ); return 1; } + buffer = (uint8_t *)realloc( buffer, target_buffer_size ); + if( !buffer ) { show_file_error( pp->name, mem_msg, 0 ); return 1; } } - else buffer_size = max( dsize + rextra, csize ); - const long cbegin = buffer_size - csize; + buffer_size = target_buffer_size; + const long cbegin = buffer_size - csize; /* overwrite trailing data */ if( cbegin > 0 ) memmove( buffer + cbegin, buffer, csize ); +/*fprintf( stderr, "buffer_size = %ld, cbegin = %ld, extra_bytes = %ld\n", + buffer_size, cbegin, extra_bytes );*/ long in_pos, out_pos; int retval; |