/* Functions for dealing with sparse files
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Free Software
- Foundation, Inc.
+ Copyright 2003-2007, 2010, 2013 Free Software Foundation, Inc.
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
Public License for more details.
You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <system.h>
#include <inttostr.h>
/* Old GNU Format. The sparse file information is stored in the
oldgnu_header in the following manner:
- The header is marked with type 'S'. Its `size' field contains
+ The header is marked with type 'S'. Its 'size' field contains
the cumulative size of all non-empty blocks of the file. The
- actual file size is stored in `realsize' member of oldgnu_header.
+ actual file size is stored in 'realsize' member of oldgnu_header.
- The map of the file is stored in a list of `struct sparse'.
+ The map of the file is stored in a list of 'struct sparse'.
Each struct contains offset to the block of data and its
size (both as octal numbers). The first file header contains
at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
- contains more structs, then the field `isextended' of the main
- header is set to 1 (binary) and the `struct sparse_header'
+ contains more structs, then the field 'isextended' of the main
+ header is set to 1 (binary) and the 'struct sparse_header'
header follows, containing at most 21 following structs
- (SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
+ (SPARSES_IN_SPARSE_HEADER). If more structs follow, 'isextended'
field of the extended header is set and next next extension header
follows, etc... */
return add_finish;
sp.offset = OFF_FROM_HEADER (s->offset);
sp.numbytes = OFF_FROM_HEADER (s->numbytes);
- if (sp.offset < 0
- || sp.offset + sp.numbytes < 0
+ if (sp.offset < 0 || sp.numbytes < 0
+ || INT_ADD_OVERFLOW (sp.offset, sp.numbytes)
|| file->stat_info->stat.st_size < sp.offset + sp.numbytes
|| file->stat_info->archive_file_size < 0)
return add_fail;
{
/* NOTE! st_size was initialized from the header
which actually contains archived size. The following fixes it */
+ off_t realsize = OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
- file->stat_info->stat.st_size =
- OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
- return true;
+ file->stat_info->stat.st_size = max (0, realsize);
+ return 0 <= realsize;
}
/* Convert old GNU format sparse data to internal representation */
{
/* NOTE! st_size was initialized from the header
which actually contains archived size. The following fixes it */
+ off_t realsize = OFF_FROM_HEADER (current_header->star_in_header.realsize);
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
- file->stat_info->stat.st_size =
- OFF_FROM_HEADER (current_header->star_in_header.realsize);
- return true;
+ file->stat_info->stat.st_size = max (0, realsize);
+ return 0 <= realsize;
}
/* Convert STAR format sparse data to internal representation */
if (!ISDIGIT (*arg))
return false;
+ errno = 0;
u = strtoumax (arg, &arg_lim, 10);
if (! (u <= maxval && errno != ERANGE) || *arg_lim)