bool sparse_diff_file (int fd, struct tar_stat_info *st) { bool rc = true; struct tar_sparse_file file; size_t i; off_t offset = 0; if (!tar_sparse_init (&file)) return dump_status_not_implemented; file.stat_info = st; file.fd = fd; file.seekable = true; /* File *must* be seekable for compare to work */ rc = tar_sparse_decode_header (&file); mv_begin_read (st); for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++) { rc = check_sparse_region (&file, offset, file.stat_info->sparse_map[i].offset) && check_data_region (&file, i); offset = file.stat_info->sparse_map[i].offset + file.stat_info->sparse_map[i].numbytes; } if (!rc) skip_file (file.stat_info->archive_file_size - file.dumped_size); mv_end (); tar_sparse_done (&file); return rc; }
static void get_gnu_dumpdir (struct tar_stat_info *stat_info) { size_t size; size_t copied; union block *data_block; char *to; char *archive_dir; size = stat_info->stat.st_size; archive_dir = xmalloc (size); to = archive_dir; set_next_block_after (current_header); mv_begin_read (stat_info); for (; size > 0; size -= copied) { mv_size_left (size); data_block = find_next_block (); if (!data_block) ERROR ((1, 0, _("Unexpected EOF in archive"))); copied = available_space_after (data_block); if (copied > size) copied = size; memcpy (to, data_block->buffer, copied); to += copied; set_next_block_after ((union block *) (data_block->buffer + copied - 1)); } mv_end (); stat_info->dumpdir = archive_dir; stat_info->skipped = true; /* For skip_member() and friends to work correctly */ }