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; ) |