| 486 |
} |
} |
| 487 |
} |
} |
| 488 |
|
|
|
/* Translate the sparse information on the header, and in any |
|
|
subsequent extended headers, into an array of structures with true |
|
|
numbers, as opposed to character strings. Return nonzero if |
|
|
successful. |
|
|
|
|
|
This function invalidates current_header. */ |
|
|
|
|
|
bool |
|
|
fill_in_sparse_array (void) |
|
|
{ |
|
|
off_t sparse_data_size = current_stat_info.stat.st_size; |
|
|
off_t file_size = OFF_FROM_HEADER (current_header->oldgnu_header.realsize); |
|
|
int sparses; |
|
|
int counter; |
|
|
union block *h = current_header; |
|
|
|
|
|
init_sparsearray (); |
|
|
|
|
|
for (sparses = 0; sparses < SPARSES_IN_OLDGNU_HEADER; sparses++) |
|
|
{ |
|
|
struct sparse const *s = &h->oldgnu_header.sp[sparses]; |
|
|
off_t offset; |
|
|
size_t numbytes; |
|
|
if (s->numbytes[0] == '\0') |
|
|
break; |
|
|
sparsearray[sparses].offset = offset = OFF_FROM_HEADER (s->offset); |
|
|
sparsearray[sparses].numbytes = numbytes = |
|
|
SIZE_FROM_HEADER (s->numbytes); |
|
|
sparse_data_size -= numbytes; |
|
|
if (offset < 0 || file_size < offset + numbytes || sparse_data_size < 0) |
|
|
goto invalid_member; |
|
|
} |
|
|
|
|
|
if (h->oldgnu_header.isextended) |
|
|
do |
|
|
{ |
|
|
h = find_next_block (); |
|
|
if (! h) |
|
|
{ |
|
|
ERROR ((0, 0, _("Unexpected EOF in archive"))); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++) |
|
|
{ |
|
|
struct sparse const *s = &h->sparse_header.sp[counter]; |
|
|
off_t offset; |
|
|
size_t numbytes; |
|
|
if (s->numbytes[0] == '\0') |
|
|
break; |
|
|
|
|
|
if (sparses == sp_array_size) |
|
|
{ |
|
|
sp_array_size *= 2; |
|
|
sparsearray = |
|
|
xrealloc (sparsearray, |
|
|
sp_array_size * sizeof *sparsearray); |
|
|
} |
|
|
|
|
|
sparsearray[sparses].offset = offset = |
|
|
OFF_FROM_HEADER (s->offset); |
|
|
sparsearray[sparses].numbytes = numbytes = |
|
|
SIZE_FROM_HEADER (s->numbytes); |
|
|
sparse_data_size -= numbytes; |
|
|
if (offset < 0 || file_size < offset + numbytes |
|
|
|| sparse_data_size < 0) |
|
|
goto invalid_member; |
|
|
sparses++; |
|
|
} |
|
|
|
|
|
set_next_block_after (h); |
|
|
|
|
|
} while (h->sparse_header.isextended); |
|
|
|
|
|
return 1; |
|
|
|
|
|
invalid_member: |
|
|
ERROR ((0, 0, _("%s: invalid sparse archive member"), |
|
|
current_stat_info.file_name)); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
|
static off_t |
|
|
extract_sparse_file (int fd, char const *name, |
|
|
off_t sizeleft, off_t file_size) |
|
|
{ |
|
|
int sparse_ind = 0; |
|
|
|
|
|
while (sizeleft != 0) |
|
|
{ |
|
|
size_t written; |
|
|
size_t count; |
|
|
union block *data_block = find_next_block (); |
|
|
if (! data_block) |
|
|
{ |
|
|
ERROR ((0, 0, _("Unexpected EOF in archive"))); |
|
|
return sizeleft; |
|
|
} |
|
|
if (lseek (fd, sparsearray[sparse_ind].offset, SEEK_SET) < 0) |
|
|
{ |
|
|
seek_error_details (name, sparsearray[sparse_ind].offset); |
|
|
return sizeleft; |
|
|
} |
|
|
written = sparsearray[sparse_ind++].numbytes; |
|
|
while (written > BLOCKSIZE) |
|
|
{ |
|
|
count = full_write (fd, data_block->buffer, BLOCKSIZE); |
|
|
written -= count; |
|
|
sizeleft -= count; |
|
|
if (count != BLOCKSIZE) |
|
|
{ |
|
|
write_error_details (name, count, BLOCKSIZE); |
|
|
return sizeleft; |
|
|
} |
|
|
set_next_block_after (data_block); |
|
|
data_block = find_next_block (); |
|
|
if (! data_block) |
|
|
{ |
|
|
ERROR ((0, 0, _("Unexpected EOF in archive"))); |
|
|
return sizeleft; |
|
|
} |
|
|
} |
|
|
|
|
|
count = full_write (fd, data_block->buffer, written); |
|
|
sizeleft -= count; |
|
|
|
|
|
if (count != written) |
|
|
{ |
|
|
write_error_details (name, count, written); |
|
|
return sizeleft; |
|
|
} |
|
|
|
|
|
set_next_block_after (data_block); |
|
|
} |
|
|
|
|
|
if (ftruncate (fd, file_size) != 0) |
|
|
truncate_error (name); |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
| 489 |
/* Fix the statuses of all directories whose statuses need fixing, and |
/* Fix the statuses of all directories whose statuses need fixing, and |
| 490 |
which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is |
which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is |
| 491 |
nonzero, do this for all such directories; otherwise, stop at the |
nonzero, do this for all such directories; otherwise, stop at the |
| 570 |
/* Print the block from current_header and current_stat. */ |
/* Print the block from current_header and current_stat. */ |
| 571 |
|
|
| 572 |
if (verbose_option) |
if (verbose_option) |
| 573 |
print_header (-1); |
print_header (¤t_stat_info, -1); |
| 574 |
|
|
| 575 |
file_name = safer_name_suffix (current_stat_info.file_name, 0); |
file_name = safer_name_suffix (current_stat_info.file_name, 0); |
| 576 |
if (strip_path_elements) |
if (strip_path_elements) |
| 604 |
switch (typeflag) |
switch (typeflag) |
| 605 |
{ |
{ |
| 606 |
case GNUTYPE_SPARSE: |
case GNUTYPE_SPARSE: |
|
file_size = OFF_FROM_HEADER (current_header->oldgnu_header.realsize); |
|
|
if (! fill_in_sparse_array ()) |
|
|
return; |
|
| 607 |
/* Fall through. */ |
/* Fall through. */ |
| 608 |
|
|
| 609 |
case AREGTYPE: |
case AREGTYPE: |
| 678 |
extract_file: |
extract_file: |
| 679 |
if (typeflag == GNUTYPE_SPARSE) |
if (typeflag == GNUTYPE_SPARSE) |
| 680 |
{ |
{ |
| 681 |
char *name; |
sparse_extract_file (fd, ¤t_stat_info, &size); |
|
size_t name_length_bis; |
|
|
|
|
|
/* Kludge alert. NAME is assigned to header.name because |
|
|
during the extraction, the space that contains the header |
|
|
will get scribbled on, and the name will get munged, so any |
|
|
error messages that happen to contain the filename will look |
|
|
REAL interesting unless we do this. */ |
|
|
|
|
|
name_length_bis = strlen (file_name) + 1; |
|
|
name = xmalloc (name_length_bis); |
|
|
memcpy (name, file_name, name_length_bis); |
|
|
size = extract_sparse_file (fd, name, |
|
|
current_stat_info.stat.st_size, file_size); |
|
|
free (sparsearray); |
|
| 682 |
} |
} |
| 683 |
else |
else |
| 684 |
for (size = current_stat_info.stat.st_size; size > 0; ) |
for (size = current_stat_info.stat.st_size; size > 0; ) |