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: stable/10/contrib/libarchive/libarchive/archive_read_extract2.c 311042 2017-01-02 01:43:11Z 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) { 55311042Smm a->extract = (struct archive_read_extract *)calloc(1, sizeof(*a->extract)); 56299425Smm if (a->extract == NULL) { 57299425Smm archive_set_error(&a->archive, ENOMEM, "Can't extract"); 58299425Smm return (NULL); 59299425Smm } 60299425Smm a->cleanup_archive_extract = archive_read_extract_cleanup; 61299425Smm } 62299425Smm return (a->extract); 63299425Smm} 64299425Smm 65299425Smm/* 66299425Smm * Cleanup function for archive_extract. 67299425Smm */ 68299425Smmstatic int 69299425Smmarchive_read_extract_cleanup(struct archive_read *a) 70299425Smm{ 71299425Smm int ret = ARCHIVE_OK; 72299425Smm 73299425Smm if (a->extract->ad != NULL) { 74299425Smm ret = archive_write_free(a->extract->ad); 75299425Smm } 76299425Smm free(a->extract); 77299425Smm a->extract = NULL; 78299425Smm return (ret); 79299425Smm} 80299425Smm 81299425Smmint 82299425Smmarchive_read_extract2(struct archive *_a, struct archive_entry *entry, 83299425Smm struct archive *ad) 84299425Smm{ 85299425Smm struct archive_read *a = (struct archive_read *)_a; 86299425Smm int r, r2; 87299425Smm 88299425Smm /* Set up for this particular entry. */ 89299425Smm if (a->skip_file_set) 90299425Smm archive_write_disk_set_skip_file(ad, 91299425Smm a->skip_file_dev, a->skip_file_ino); 92299425Smm r = archive_write_header(ad, entry); 93299425Smm if (r < ARCHIVE_WARN) 94299425Smm r = ARCHIVE_WARN; 95299425Smm if (r != ARCHIVE_OK) 96299425Smm /* If _write_header failed, copy the error. */ 97299425Smm archive_copy_error(&a->archive, ad); 98299425Smm else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) 99299425Smm /* Otherwise, pour data into the entry. */ 100299425Smm r = copy_data(_a, ad); 101299425Smm r2 = archive_write_finish_entry(ad); 102299425Smm if (r2 < ARCHIVE_WARN) 103299425Smm r2 = ARCHIVE_WARN; 104299425Smm /* Use the first message. */ 105299425Smm if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) 106299425Smm archive_copy_error(&a->archive, ad); 107299425Smm /* Use the worst error return. */ 108299425Smm if (r2 < r) 109299425Smm r = r2; 110299425Smm return (r); 111299425Smm} 112299425Smm 113299425Smmvoid 114299425Smmarchive_read_extract_set_progress_callback(struct archive *_a, 115299425Smm void (*progress_func)(void *), void *user_data) 116299425Smm{ 117299425Smm struct archive_read *a = (struct archive_read *)_a; 118299425Smm struct archive_read_extract *extract = __archive_read_get_extract(a); 119299425Smm if (extract != NULL) { 120299425Smm extract->extract_progress = progress_func; 121299425Smm extract->extract_progress_user_data = user_data; 122299425Smm } 123299425Smm} 124299425Smm 125299425Smmstatic int 126299425Smmcopy_data(struct archive *ar, struct archive *aw) 127299425Smm{ 128299425Smm int64_t offset; 129299425Smm const void *buff; 130299425Smm struct archive_read_extract *extract; 131299425Smm size_t size; 132299425Smm int r; 133299425Smm 134299425Smm extract = __archive_read_get_extract((struct archive_read *)ar); 135299425Smm if (extract == NULL) 136299425Smm return (ARCHIVE_FATAL); 137299425Smm for (;;) { 138299425Smm r = archive_read_data_block(ar, &buff, &size, &offset); 139299425Smm if (r == ARCHIVE_EOF) 140299425Smm return (ARCHIVE_OK); 141299425Smm if (r != ARCHIVE_OK) 142299425Smm return (r); 143299425Smm r = (int)archive_write_data_block(aw, buff, size, offset); 144299425Smm if (r < ARCHIVE_WARN) 145299425Smm r = ARCHIVE_WARN; 146299425Smm if (r < ARCHIVE_OK) { 147299425Smm archive_set_error(ar, archive_errno(aw), 148299425Smm "%s", archive_error_string(aw)); 149299425Smm return (r); 150299425Smm } 151299425Smm if (extract->extract_progress) 152299425Smm (extract->extract_progress) 153299425Smm (extract->extract_progress_user_data); 154299425Smm } 155299425Smm} 156