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 29#include "archive.h" 30#include "archive_entry.h" 31#include "archive_private.h" 32#include "archive_entry_private.h" 33 34/* 35 * sparse handling 36 */ 37 38void 39archive_entry_sparse_clear(struct archive_entry *entry) 40{ 41 struct ae_sparse *sp; 42 43 while (entry->sparse_head != NULL) { 44 sp = entry->sparse_head->next; 45 free(entry->sparse_head); 46 entry->sparse_head = sp; 47 } 48 entry->sparse_tail = NULL; 49} 50 51void 52archive_entry_sparse_add_entry(struct archive_entry *entry, 53 la_int64_t offset, la_int64_t length) 54{ 55 struct ae_sparse *sp; 56 57 if (offset < 0 || length < 0) 58 /* Invalid value */ 59 return; 60 if (offset > INT64_MAX - length || 61 offset + length > archive_entry_size(entry)) 62 /* A value of "length" parameter is too large. */ 63 return; 64 if ((sp = entry->sparse_tail) != NULL) { 65 if (sp->offset + sp->length > offset) 66 /* Invalid value. */ 67 return; 68 if (sp->offset + sp->length == offset) { 69 if (sp->offset + sp->length + length < 0) 70 /* A value of "length" parameter is 71 * too large. */ 72 return; 73 /* Expand existing sparse block size. */ 74 sp->length += length; 75 return; 76 } 77 } 78 79 if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL) 80 /* XXX Error XXX */ 81 return; 82 83 sp->offset = offset; 84 sp->length = length; 85 sp->next = NULL; 86 87 if (entry->sparse_head == NULL) 88 entry->sparse_head = entry->sparse_tail = sp; 89 else { 90 /* Add a new sparse block to the tail of list. */ 91 if (entry->sparse_tail != NULL) 92 entry->sparse_tail->next = sp; 93 entry->sparse_tail = sp; 94 } 95} 96 97 98/* 99 * returns number of the sparse entries 100 */ 101int 102archive_entry_sparse_count(struct archive_entry *entry) 103{ 104 struct ae_sparse *sp; 105 int count = 0; 106 107 for (sp = entry->sparse_head; sp != NULL; sp = sp->next) 108 count++; 109 110 /* 111 * Sanity check if this entry is exactly sparse. 112 * If amount of sparse blocks is just one and it indicates the whole 113 * file data, we should remove it and return zero. 114 */ 115 if (count == 1) { 116 sp = entry->sparse_head; 117 if (sp->offset == 0 && 118 sp->length >= archive_entry_size(entry)) { 119 count = 0; 120 archive_entry_sparse_clear(entry); 121 } 122 } 123 124 return (count); 125} 126 127int 128archive_entry_sparse_reset(struct archive_entry * entry) 129{ 130 entry->sparse_p = entry->sparse_head; 131 132 return archive_entry_sparse_count(entry); 133} 134 135int 136archive_entry_sparse_next(struct archive_entry * entry, 137 la_int64_t *offset, la_int64_t *length) 138{ 139 if (entry->sparse_p) { 140 *offset = entry->sparse_p->offset; 141 *length = entry->sparse_p->length; 142 143 entry->sparse_p = entry->sparse_p->next; 144 145 return (ARCHIVE_OK); 146 } else { 147 *offset = 0; 148 *length = 0; 149 return (ARCHIVE_WARN); 150 } 151} 152 153/* 154 * end of sparse handling 155 */ 156