1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * Copyright (c) 2010-2011 Michihiro NAKAJIMA 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 __FBSDID("$FreeBSD$"); 29 30 #include "archive.h" 31 #include "archive_entry.h" 32 #include "archive_private.h" 33 #include "archive_entry_private.h" 34 35 /* 36 * sparse handling 37 */ 38 39 void 40 archive_entry_sparse_clear(struct archive_entry *entry) 41 { 42 struct ae_sparse *sp; 43 44 while (entry->sparse_head != NULL) { 45 sp = entry->sparse_head->next; 46 free(entry->sparse_head); 47 entry->sparse_head = sp; 48 } 49 entry->sparse_tail = NULL; 50 } 51 52 void 53 archive_entry_sparse_add_entry(struct archive_entry *entry, 54 la_int64_t offset, la_int64_t length) 55 { 56 struct ae_sparse *sp; 57 58 if (offset < 0 || length < 0) 59 /* Invalid value */ 60 return; 61 if (offset > INT64_MAX - length || 62 offset + length > archive_entry_size(entry)) 63 /* A value of "length" parameter is too large. */ 64 return; 65 if ((sp = entry->sparse_tail) != NULL) { 66 if (sp->offset + sp->length > offset) 67 /* Invalid value. */ 68 return; 69 if (sp->offset + sp->length == offset) { 70 if (sp->offset + sp->length + length < 0) 71 /* A value of "length" parameter is 72 * too large. */ 73 return; 74 /* Expand existing sparse block size. */ 75 sp->length += length; 76 return; 77 } 78 } 79 80 if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL) 81 /* XXX Error XXX */ 82 return; 83 84 sp->offset = offset; 85 sp->length = length; 86 sp->next = NULL; 87 88 if (entry->sparse_head == NULL) 89 entry->sparse_head = entry->sparse_tail = sp; 90 else { 91 /* Add a new sparse block to the tail of list. */ 92 if (entry->sparse_tail != NULL) 93 entry->sparse_tail->next = sp; 94 entry->sparse_tail = sp; 95 } 96 } 97 98 99 /* 100 * returns number of the sparse entries 101 */ 102 int 103 archive_entry_sparse_count(struct archive_entry *entry) 104 { 105 struct ae_sparse *sp; 106 int count = 0; 107 108 for (sp = entry->sparse_head; sp != NULL; sp = sp->next) 109 count++; 110 111 /* 112 * Sanity check if this entry is exactly sparse. 113 * If amount of sparse blocks is just one and it indicates the whole 114 * file data, we should remove it and return zero. 115 */ 116 if (count == 1) { 117 sp = entry->sparse_head; 118 if (sp->offset == 0 && 119 sp->length >= archive_entry_size(entry)) { 120 count = 0; 121 archive_entry_sparse_clear(entry); 122 } 123 } 124 125 return (count); 126 } 127 128 int 129 archive_entry_sparse_reset(struct archive_entry * entry) 130 { 131 entry->sparse_p = entry->sparse_head; 132 133 return archive_entry_sparse_count(entry); 134 } 135 136 int 137 archive_entry_sparse_next(struct archive_entry * entry, 138 la_int64_t *offset, la_int64_t *length) 139 { 140 if (entry->sparse_p) { 141 *offset = entry->sparse_p->offset; 142 *length = entry->sparse_p->length; 143 144 entry->sparse_p = entry->sparse_p->next; 145 146 return (ARCHIVE_OK); 147 } else { 148 *offset = 0; 149 *length = 0; 150 return (ARCHIVE_WARN); 151 } 152 } 153 154 /* 155 * end of sparse handling 156 */ 157