This commit is contained in:
John Cupitt 2009-03-20 15:23:41 +00:00
parent d2a0d4468f
commit 74b0bf80ad
6 changed files with 41 additions and 54 deletions

View File

@ -360,10 +360,11 @@ typedef struct im__IMAGE {
GSList *preclosefns; /* list of pre-close callbacks */ GSList *preclosefns; /* list of pre-close callbacks */
GSList *invalidatefns; /* list of invalidate callbacks */ GSList *invalidatefns; /* list of invalidate callbacks */
/* Set this to indicate a truncated file. We've been able to read the /* Record the file length here. We use this to stop ourselves mapping
* header, but don't try reading outside the file size. * things beyond the end of the file in the case that the file has
* been truncated.
*/ */
int nodata; size_t file_length;
} IMAGE; } IMAGE;
/* Only define if IM_ENABLE_DEPRECATED is set. /* Only define if IM_ENABLE_DEPRECATED is set.

View File

@ -83,7 +83,6 @@ IMAGE *
im_binfile( const char *name, int xs, int ys, int bands, int offset ) im_binfile( const char *name, int xs, int ys, int bands, int offset )
{ {
IMAGE *im; IMAGE *im;
gint64 length;
gint64 psize; gint64 psize;
/* Check parameters. /* Check parameters.
@ -112,14 +111,14 @@ im_binfile( const char *name, int xs, int ys, int bands, int offset )
/* Read the file length and check against what we think /* Read the file length and check against what we think
* the size should be. * the size should be.
*/ */
if( (length = im_file_length( im->fd )) == -1 ) { if( (im->file_length = im_file_length( im->fd )) == -1 ) {
im_close( im ); im_close( im );
return( NULL ); return( NULL );
} }
/* Very common, so special message. /* Very common, so special message.
*/ */
if( psize > length ) { if( psize > im->file_length ) {
im_error( "im_binfile", _( "unable to open %s: " im_error( "im_binfile", _( "unable to open %s: "
"file has been truncated" ), im->filename ); "file has been truncated" ), im->filename );
im_close( im ); im_close( im );
@ -129,7 +128,7 @@ im_binfile( const char *name, int xs, int ys, int bands, int offset )
/* Just wierd. Only print a warning for this, since we should /* Just wierd. Only print a warning for this, since we should
* still be able to process it without coredumps. * still be able to process it without coredumps.
*/ */
if( psize < length ) if( psize < im->file_length )
im_warn( "im_binfile", _( "%s is longer than expected" ), im_warn( "im_binfile", _( "%s is longer than expected" ),
im->filename ); im->filename );

View File

@ -32,7 +32,7 @@
* 9/8/08 * 9/8/08
* - lock global image list (thanks lee) * - lock global image list (thanks lee)
* 19/3/09 * 19/3/09
* - add nodata * - add file_length
*/ */
/* /*
@ -170,7 +170,7 @@ im_init( const char *filename )
im->preclosefns = NULL; im->preclosefns = NULL;
im->invalidatefns = NULL; im->invalidatefns = NULL;
im->nodata = 0; im->file_length = 0;
if( !(im->filename = im_strdup( NULL, filename )) ) { if( !(im->filename = im_strdup( NULL, filename )) ) {
im_close( im ); im_close( im );

View File

@ -210,7 +210,6 @@ im__munmap( void *start, size_t length )
int int
im_mapfile( IMAGE *im ) im_mapfile( IMAGE *im )
{ {
gint64 length;
struct stat st; struct stat st;
mode_t m; mode_t m;
@ -219,15 +218,14 @@ im_mapfile( IMAGE *im )
/* Check the size of the file; if it is less than 64 bytes, then flag /* Check the size of the file; if it is less than 64 bytes, then flag
* an error. * an error.
*/ */
if( (length = im_file_length( im->fd )) == -1 ) g_assert( im->file_length > 0 );
return( -1 );
if( fstat( im->fd, &st ) == -1 ) { if( fstat( im->fd, &st ) == -1 ) {
im_error( "im_mapfile", im_error( "im_mapfile",
"%s", _( "unable to get file status" ) ); "%s", _( "unable to get file status" ) );
return( -1 ); return( -1 );
} }
m = (mode_t) st.st_mode; m = (mode_t) st.st_mode;
if( length < 64 ) { if( im->file_length < 64 ) {
im_error( "im_mapfile", im_error( "im_mapfile",
"%s", _( "file is less than 64 bytes" ) ); "%s", _( "file is less than 64 bytes" ) );
return( -1 ); return( -1 );
@ -238,13 +236,10 @@ im_mapfile( IMAGE *im )
return( -1 ); return( -1 );
} }
if( !(im->baseaddr = im__mmap( im->fd, 0, length, 0 )) ) if( !(im->baseaddr = im__mmap( im->fd, 0, im->file_length, 0 )) )
return( -1 ); return( -1 );
/* im__mmap() will fail for >2GB, so this is safe even for large im->length = im->file_length;
* files.
*/
im->length = length;
return( 0 ); return( 0 );
} }
@ -254,7 +249,6 @@ im_mapfile( IMAGE *im )
int int
im_mapfilerw( IMAGE *im ) im_mapfilerw( IMAGE *im )
{ {
gint64 length;
struct stat st; struct stat st;
mode_t m; mode_t m;
@ -263,27 +257,23 @@ im_mapfilerw( IMAGE *im )
/* Check the size of the file if it is less than 64 bytes return /* Check the size of the file if it is less than 64 bytes return
* make also sure that it is a regular file * make also sure that it is a regular file
*/ */
if( (length = im_file_length( im->fd )) == -1 ) g_assert( im->file_length > 0 );
return( -1 );
if( fstat( im->fd, &st ) == -1 ) { if( fstat( im->fd, &st ) == -1 ) {
im_error( "im_mapfilerw", im_error( "im_mapfilerw",
"%s", _( "unable to get file status" ) ); "%s", _( "unable to get file status" ) );
return( -1 ); return( -1 );
} }
m = (mode_t) st.st_mode; m = (mode_t) st.st_mode;
if( length < 64 || !S_ISREG( m ) ) { if( im->file_length < 64 || !S_ISREG( m ) ) {
im_error( "im_mapfile", im_error( "im_mapfile",
"%s", _( "unable to read data" ) ); "%s", _( "unable to read data" ) );
return( -1 ); return( -1 );
} }
if( !(im->baseaddr = im__mmap( im->fd, 1, length, 0 )) ) if( !(im->baseaddr = im__mmap( im->fd, 1, im->file_length, 0 )) )
return( -1 ); return( -1 );
/* im__mmap() will fail for >2GB, so this is safe even for large im->length = im->file_length;
* files.
*/
im->length = length;
return( 0 ); return( 0 );
} }

View File

@ -325,14 +325,12 @@ read_chunk( int fd, gint64 offset, size_t length )
int int
im__has_extension_block( IMAGE *im ) im__has_extension_block( IMAGE *im )
{ {
gint64 length;
gint64 psize; gint64 psize;
psize = im__image_pixel_length( im ); psize = im__image_pixel_length( im );
if( (length = im_file_length( im->fd )) == -1 ) g_assert( im->file_length > 0 );
return( 0 );
return( length - psize > 0 ); return( im->file_length - psize > 0 );
} }
/* Read everything after the pixels into memory. /* Read everything after the pixels into memory.
@ -340,29 +338,27 @@ im__has_extension_block( IMAGE *im )
void * void *
im__read_extension_block( IMAGE *im, int *size ) im__read_extension_block( IMAGE *im, int *size )
{ {
gint64 length;
gint64 psize; gint64 psize;
void *buf; void *buf;
psize = im__image_pixel_length( im ); psize = im__image_pixel_length( im );
if( (length = im_file_length( im->fd )) == -1 ) g_assert( im->file_length > 0 );
return( NULL ); if( im->file_length - psize > 10 * 1024 * 1024 ) {
if( length - psize > 10 * 1024 * 1024 ) {
im_error( "im_readhist", im_error( "im_readhist",
"%s", _( "more than a 10 megabytes of XML? " "%s", _( "more than a 10 megabytes of XML? "
"sufferin' succotash!" ) ); "sufferin' succotash!" ) );
return( NULL ); return( NULL );
} }
if( length - psize == 0 ) if( im->file_length - psize == 0 )
return( NULL ); return( NULL );
if( !(buf = read_chunk( im->fd, psize, length - psize )) ) if( !(buf = read_chunk( im->fd, psize, im->file_length - psize )) )
return( NULL ); return( NULL );
if( size ) if( size )
*size = length - psize; *size = im->file_length - psize;
#ifdef DEBUG #ifdef DEBUG
printf( "im__read_extension_block: read %d bytes from %s\n", printf( "im__read_extension_block: read %d bytes from %s\n",
(int) (length - psize), im->filename ); (int) (im->file_length - psize), im->filename );
printf( "data: \"%s\"\n", (char *) buf ); printf( "data: \"%s\"\n", (char *) buf );
#endif /*DEBUG*/ #endif /*DEBUG*/
@ -896,7 +892,6 @@ im__read_header( IMAGE *image )
*/ */
unsigned char header[IM_SIZEOF_HEADER]; unsigned char header[IM_SIZEOF_HEADER];
gint64 length;
gint64 psize; gint64 psize;
image->dtype = IM_OPENIN; image->dtype = IM_OPENIN;
@ -913,13 +908,11 @@ im__read_header( IMAGE *image )
/* Predict and check the file size. /* Predict and check the file size.
*/ */
psize = im__image_pixel_length( image ); psize = im__image_pixel_length( image );
if( (length = im_file_length( image->fd )) == -1 ) if( (image->file_length = im_file_length( image->fd )) == -1 )
return( -1 ); return( -1 );
if( psize > length ) { if( psize > image->file_length )
im_warn( "im_openin", _( "unable to read data for \"%s\", %s" ), im_warn( "im_openin", _( "unable to read data for \"%s\", %s" ),
image->filename, _( "file has been truncated" ) ); image->filename, _( "file has been truncated" ) );
image->nodata = 1;
}
/* Set demand style. Allow the most permissive sort. /* Set demand style. Allow the most permissive sort.
*/ */
@ -960,9 +953,13 @@ im_openin( IMAGE *image )
if( im__read_header( image ) ) if( im__read_header( image ) )
return( -1 ); return( -1 );
/* Make sure we can map the whole thing without running over the VM
* limit or running out of file.
*/
size = (gint64) IM_IMAGE_SIZEOF_LINE( image ) * image->Ysize + size = (gint64) IM_IMAGE_SIZEOF_LINE( image ) * image->Ysize +
image->sizeof_header; image->sizeof_header;
if( size < im__mmap_limit && !image->nodata ) { if( size < im__mmap_limit &&
image->file_length >= size ) {
if( im_mapfile( image ) ) if( im_mapfile( image ) )
return( -1 ); return( -1 );
image->data = image->baseaddr + image->sizeof_header; image->data = image->baseaddr + image->sizeof_header;

View File

@ -219,15 +219,6 @@ im_window_set( im_window_t *window, int top, int height )
gint64 start, end, pagestart; gint64 start, end, pagestart;
size_t length, pagelength; size_t length, pagelength;
/* Make sure this image has data.
*/
if( window->im->nodata ) {
im_error( "im_window_set",
_( "unable to read data for \"%s\", %s" ),
window->im->filename, _( "file has been truncated" ) );
return( -1 );
}
/* Calculate start and length for our window. /* Calculate start and length for our window.
*/ */
start = window->im->sizeof_header + start = window->im->sizeof_header +
@ -238,6 +229,15 @@ im_window_set( im_window_t *window, int top, int height )
end = start + length; end = start + length;
pagelength = end - pagestart; pagelength = end - pagestart;
/* Make sure we have enough file.
*/
if( end > window->im->file_length ) {
im_error( "im_window_set",
_( "unable to read data for \"%s\", %s" ),
window->im->filename, _( "file has been truncated" ) );
return( -1 );
}
if( !(baseaddr = im__mmap( window->im->fd, 0, pagelength, pagestart )) ) if( !(baseaddr = im__mmap( window->im->fd, 0, pagelength, pagestart )) )
return( -1 ); return( -1 );