1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "archive_platform.h" 27 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $"); 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_ERRNO_H 33 #include <errno.h> 34 #endif 35 #ifdef HAVE_STRING_H 36 #include <string.h> 37 #endif 38 39 #include "archive.h" 40 #include "archive_entry.h" 41 #include "archive_private.h" 42 #include "archive_read_private.h" 43 44 static int copy_data(struct archive *ar, struct archive *aw); 45 static int archive_read_extract_cleanup(struct archive_read *); 46 47 48 /* Retrieve an extract object without initialising the associated 49 * archive_write_disk object. 50 */ 51 struct archive_read_extract * 52 __archive_read_get_extract(struct archive_read *a) 53 { 54 if (a->extract == NULL) { 55 a->extract = (struct archive_read_extract *)calloc(1, sizeof(*a->extract)); 56 if (a->extract == NULL) { 57 archive_set_error(&a->archive, ENOMEM, "Can't extract"); 58 return (NULL); 59 } 60 a->cleanup_archive_extract = archive_read_extract_cleanup; 61 } 62 return (a->extract); 63 } 64 65 /* 66 * Cleanup function for archive_extract. 67 */ 68 static int 69 archive_read_extract_cleanup(struct archive_read *a) 70 { 71 int ret = ARCHIVE_OK; 72 73 if (a->extract->ad != NULL) { 74 ret = archive_write_free(a->extract->ad); 75 } 76 free(a->extract); 77 a->extract = NULL; 78 return (ret); 79 } 80 81 int 82 archive_read_extract2(struct archive *_a, struct archive_entry *entry, 83 struct archive *ad) 84 { 85 struct archive_read *a = (struct archive_read *)_a; 86 int r, r2; 87 88 /* Set up for this particular entry. */ 89 if (a->skip_file_set) 90 archive_write_disk_set_skip_file(ad, 91 a->skip_file_dev, a->skip_file_ino); 92 r = archive_write_header(ad, entry); 93 if (r < ARCHIVE_WARN) 94 r = ARCHIVE_WARN; 95 if (r != ARCHIVE_OK) 96 /* If _write_header failed, copy the error. */ 97 archive_copy_error(&a->archive, ad); 98 else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) 99 /* Otherwise, pour data into the entry. */ 100 r = copy_data(_a, ad); 101 r2 = archive_write_finish_entry(ad); 102 if (r2 < ARCHIVE_WARN) 103 r2 = ARCHIVE_WARN; 104 /* Use the first message. */ 105 if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) 106 archive_copy_error(&a->archive, ad); 107 /* Use the worst error return. */ 108 if (r2 < r) 109 r = r2; 110 return (r); 111 } 112 113 void 114 archive_read_extract_set_progress_callback(struct archive *_a, 115 void (*progress_func)(void *), void *user_data) 116 { 117 struct archive_read *a = (struct archive_read *)_a; 118 struct archive_read_extract *extract = __archive_read_get_extract(a); 119 if (extract != NULL) { 120 extract->extract_progress = progress_func; 121 extract->extract_progress_user_data = user_data; 122 } 123 } 124 125 static int 126 copy_data(struct archive *ar, struct archive *aw) 127 { 128 int64_t offset; 129 const void *buff; 130 struct archive_read_extract *extract; 131 size_t size; 132 int r; 133 134 extract = __archive_read_get_extract((struct archive_read *)ar); 135 if (extract == NULL) 136 return (ARCHIVE_FATAL); 137 for (;;) { 138 r = archive_read_data_block(ar, &buff, &size, &offset); 139 if (r == ARCHIVE_EOF) 140 return (ARCHIVE_OK); 141 if (r != ARCHIVE_OK) 142 return (r); 143 r = (int)archive_write_data_block(aw, buff, size, offset); 144 if (r < ARCHIVE_WARN) 145 r = ARCHIVE_WARN; 146 if (r < ARCHIVE_OK) { 147 archive_set_error(ar, archive_errno(aw), 148 "%s", archive_error_string(aw)); 149 return (r); 150 } 151 if (extract->extract_progress) 152 (extract->extract_progress) 153 (extract->extract_progress_user_data); 154 } 155 } 156