1299425Smm/*- 2299425Smm * Copyright (c) 2003-2007 Tim Kientzle 3299425Smm * All rights reserved. 4299425Smm * 5299425Smm * Redistribution and use in source and binary forms, with or without 6299425Smm * modification, are permitted provided that the following conditions 7299425Smm * are met: 8299425Smm * 1. Redistributions of source code must retain the above copyright 9299425Smm * notice, this list of conditions and the following disclaimer. 10299425Smm * 2. Redistributions in binary form must reproduce the above copyright 11299425Smm * notice, this list of conditions and the following disclaimer in the 12299425Smm * documentation and/or other materials provided with the distribution. 13299425Smm * 14299425Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15299425Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16299425Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17299425Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18299425Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19299425Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20299425Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21299425Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22299425Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23299425Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24299425Smm */ 25299425Smm 26299425Smm#include "archive_platform.h" 27299425Smm__FBSDID("$FreeBSD: releng/11.0/contrib/libarchive/libarchive/archive_read_extract2.c 299529 2016-05-12 10:16:16Z mm $"); 28299425Smm 29299425Smm#ifdef HAVE_SYS_TYPES_H 30299425Smm#include <sys/types.h> 31299425Smm#endif 32299425Smm#ifdef HAVE_ERRNO_H 33299425Smm#include <errno.h> 34299425Smm#endif 35299425Smm#ifdef HAVE_STRING_H 36299425Smm#include <string.h> 37299425Smm#endif 38299425Smm 39299425Smm#include "archive.h" 40299425Smm#include "archive_entry.h" 41299425Smm#include "archive_private.h" 42299425Smm#include "archive_read_private.h" 43299425Smm 44299425Smmstatic int copy_data(struct archive *ar, struct archive *aw); 45299425Smmstatic int archive_read_extract_cleanup(struct archive_read *); 46299425Smm 47299425Smm 48299425Smm/* Retrieve an extract object without initialising the associated 49299425Smm * archive_write_disk object. 50299425Smm */ 51299425Smmstruct archive_read_extract * 52299425Smm__archive_read_get_extract(struct archive_read *a) 53299425Smm{ 54299425Smm if (a->extract == NULL) { 55299425Smm a->extract = (struct archive_read_extract *)malloc(sizeof(*a->extract)); 56299425Smm if (a->extract == NULL) { 57299425Smm archive_set_error(&a->archive, ENOMEM, "Can't extract"); 58299425Smm return (NULL); 59299425Smm } 60299425Smm memset(a->extract, 0, sizeof(*a->extract)); 61299425Smm a->cleanup_archive_extract = archive_read_extract_cleanup; 62299425Smm } 63299425Smm return (a->extract); 64299425Smm} 65299425Smm 66299425Smm/* 67299425Smm * Cleanup function for archive_extract. 68299425Smm */ 69299425Smmstatic int 70299425Smmarchive_read_extract_cleanup(struct archive_read *a) 71299425Smm{ 72299425Smm int ret = ARCHIVE_OK; 73299425Smm 74299425Smm if (a->extract->ad != NULL) { 75299425Smm ret = archive_write_free(a->extract->ad); 76299425Smm } 77299425Smm free(a->extract); 78299425Smm a->extract = NULL; 79299425Smm return (ret); 80299425Smm} 81299425Smm 82299425Smmint 83299425Smmarchive_read_extract2(struct archive *_a, struct archive_entry *entry, 84299425Smm struct archive *ad) 85299425Smm{ 86299425Smm struct archive_read *a = (struct archive_read *)_a; 87299425Smm int r, r2; 88299425Smm 89299425Smm /* Set up for this particular entry. */ 90299425Smm if (a->skip_file_set) 91299425Smm archive_write_disk_set_skip_file(ad, 92299425Smm a->skip_file_dev, a->skip_file_ino); 93299425Smm r = archive_write_header(ad, entry); 94299425Smm if (r < ARCHIVE_WARN) 95299425Smm r = ARCHIVE_WARN; 96299425Smm if (r != ARCHIVE_OK) 97299425Smm /* If _write_header failed, copy the error. */ 98299425Smm archive_copy_error(&a->archive, ad); 99299425Smm else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) 100299425Smm /* Otherwise, pour data into the entry. */ 101299425Smm r = copy_data(_a, ad); 102299425Smm r2 = archive_write_finish_entry(ad); 103299425Smm if (r2 < ARCHIVE_WARN) 104299425Smm r2 = ARCHIVE_WARN; 105299425Smm /* Use the first message. */ 106299425Smm if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) 107299425Smm archive_copy_error(&a->archive, ad); 108299425Smm /* Use the worst error return. */ 109299425Smm if (r2 < r) 110299425Smm r = r2; 111299425Smm return (r); 112299425Smm} 113299425Smm 114299425Smmvoid 115299425Smmarchive_read_extract_set_progress_callback(struct archive *_a, 116299425Smm void (*progress_func)(void *), void *user_data) 117299425Smm{ 118299425Smm struct archive_read *a = (struct archive_read *)_a; 119299425Smm struct archive_read_extract *extract = __archive_read_get_extract(a); 120299425Smm if (extract != NULL) { 121299425Smm extract->extract_progress = progress_func; 122299425Smm extract->extract_progress_user_data = user_data; 123299425Smm } 124299425Smm} 125299425Smm 126299425Smmstatic int 127299425Smmcopy_data(struct archive *ar, struct archive *aw) 128299425Smm{ 129299425Smm int64_t offset; 130299425Smm const void *buff; 131299425Smm struct archive_read_extract *extract; 132299425Smm size_t size; 133299425Smm int r; 134299425Smm 135299425Smm extract = __archive_read_get_extract((struct archive_read *)ar); 136299425Smm if (extract == NULL) 137299425Smm return (ARCHIVE_FATAL); 138299425Smm for (;;) { 139299425Smm r = archive_read_data_block(ar, &buff, &size, &offset); 140299425Smm if (r == ARCHIVE_EOF) 141299425Smm return (ARCHIVE_OK); 142299425Smm if (r != ARCHIVE_OK) 143299425Smm return (r); 144299425Smm r = (int)archive_write_data_block(aw, buff, size, offset); 145299425Smm if (r < ARCHIVE_WARN) 146299425Smm r = ARCHIVE_WARN; 147299425Smm if (r < ARCHIVE_OK) { 148299425Smm archive_set_error(ar, archive_errno(aw), 149299425Smm "%s", archive_error_string(aw)); 150299425Smm return (r); 151299425Smm } 152299425Smm if (extract->extract_progress) 153299425Smm (extract->extract_progress) 154299425Smm (extract->extract_progress_user_data); 155299425Smm } 156299425Smm} 157