static bool check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end) { if (!lseek_or_error (file, beg)) return false; while (beg < end) { size_t bytes_read; size_t rdsize = BLOCKSIZE < end - beg ? BLOCKSIZE : end - beg; char diff_buffer[BLOCKSIZE]; bytes_read = safe_read (file->fd, diff_buffer, rdsize); if (bytes_read == SAFE_READ_ERROR) { read_diag_details (file->stat_info->orig_file_name, beg, rdsize); return false; } if (!zero_block_p (diff_buffer, bytes_read)) { char begbuf[INT_BUFSIZE_BOUND (off_t)]; report_difference (file->stat_info, _("File fragment at %s is not a hole"), offtostr (beg, begbuf)); return false; } beg += bytes_read; } return true; }
static bool sparse_dump_region (struct tar_sparse_file *file, size_t i) { union block *blk; off_t bytes_left = file->stat_info->sparse_map[i].numbytes; if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) return false; while (bytes_left > 0) { size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left; size_t bytes_read; blk = find_next_block (); bytes_read = safe_read (file->fd, blk->buffer, bufsize); if (bytes_read == SAFE_READ_ERROR) { read_diag_details (file->stat_info->orig_file_name, (file->stat_info->sparse_map[i].offset + file->stat_info->sparse_map[i].numbytes - bytes_left), bufsize); return false; } memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read); bytes_left -= bytes_read; file->dumped_size += bytes_read; mv_size_left (file->stat_info->archive_file_size - file->dumped_size); set_next_block_after (blk); } return true; }
static bool check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end) { if (!lseek_or_error (file, beg, SEEK_SET)) return false; while (beg < end) { size_t bytes_read; size_t rdsize = end - beg; if (rdsize > BLOCKSIZE) rdsize = BLOCKSIZE; clear_block (diff_buffer); bytes_read = safe_read (file->fd, diff_buffer, rdsize); if (bytes_read == SAFE_READ_ERROR) { read_diag_details (file->stat_info->orig_file_name, beg, rdsize); return false; } if (!zero_block_p (diff_buffer, bytes_read)) { report_difference (file->stat_info, _("File fragment at %lu is not a hole"), beg); return false; } beg += bytes_read; } return true; }
/* Scan the sparse file and create its map */ static bool sparse_scan_file (struct tar_sparse_file *file) { static char buffer[BLOCKSIZE]; size_t count; size_t offset = 0; struct sp_array sp = {0, 0}; if (!lseek_or_error (file, 0, SEEK_SET)) return false; clear_block (buffer); file->stat_info->sparse_map_avail = 0; file->stat_info->archive_file_size = 0; if (!tar_sparse_scan (file, scan_begin, NULL)) return false; while ((count = safe_read (file->fd, buffer, sizeof buffer)) != 0 && count != SAFE_READ_ERROR) { /* Analize the block */ if (zero_block_p (buffer, count)) { if (sp.numbytes) { sparse_add_map (file, &sp); sp.numbytes = 0; if (!tar_sparse_scan (file, scan_block, NULL)) return false; } } else { if (sp.numbytes == 0) sp.offset = offset; sp.numbytes += count; file->stat_info->archive_file_size += count; if (!tar_sparse_scan (file, scan_block, buffer)) return false; } offset += count; clear_block (buffer); } if (sp.numbytes == 0) sp.offset = offset; sparse_add_map (file, &sp); file->stat_info->archive_file_size += count; return tar_sparse_scan (file, scan_end, NULL); }
static bool check_data_region (struct tar_sparse_file *file, size_t i) { size_t size_left; if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) return false; size_left = file->stat_info->sparse_map[i].numbytes; mv_size_left (file->stat_info->archive_file_size - file->dumped_size); while (size_left > 0) { size_t bytes_read; size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left; char diff_buffer[BLOCKSIZE]; union block *blk = find_next_block (); if (!blk) { ERROR ((0, 0, _("Unexpected EOF in archive"))); return false; } set_next_block_after (blk); bytes_read = safe_read (file->fd, diff_buffer, rdsize); if (bytes_read == SAFE_READ_ERROR) { read_diag_details (file->stat_info->orig_file_name, (file->stat_info->sparse_map[i].offset + file->stat_info->sparse_map[i].numbytes - size_left), rdsize); return false; } file->dumped_size += bytes_read; size_left -= bytes_read; mv_size_left (file->stat_info->archive_file_size - file->dumped_size); if (memcmp (blk->buffer, diff_buffer, rdsize)) { report_difference (file->stat_info, _("Contents differ")); return false; } } return true; }
static bool sparse_extract_region (struct tar_sparse_file *file, size_t i) { size_t write_size; if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) return false; write_size = file->stat_info->sparse_map[i].numbytes; if (write_size == 0) { /* Last block of the file is a hole */ if (file->seekable && sys_truncate (file->fd)) truncate_warn (file->stat_info->orig_file_name); } else while (write_size > 0) { size_t count; size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size; union block *blk = find_next_block (); if (!blk) { ERROR ((0, 0, _("Unexpected EOF in archive"))); return false; } set_next_block_after (blk); count = full_write (file->fd, blk->buffer, wrbytes); write_size -= count; file->dumped_size += count; mv_size_left (file->stat_info->archive_file_size - file->dumped_size); file->offset += count; if (count != wrbytes) { write_error_details (file->stat_info->orig_file_name, count, wrbytes); return false; } } return true; }