summaryrefslogtreecommitdiffstats
path: root/in_place.c
diff options
context:
space:
mode:
Diffstat (limited to 'in_place.c')
-rw-r--r--in_place.c72
1 files changed, 39 insertions, 33 deletions
diff --git a/in_place.c b/in_place.c
index 1ada24e..7f00933 100644
--- a/in_place.c
+++ b/in_place.c
@@ -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;