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
archive_entry_sparse_clear(struct archive_entry * entry)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
archive_entry_sparse_add_entry(struct archive_entry * entry,la_int64_t offset,la_int64_t length)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
archive_entry_sparse_count(struct archive_entry * entry)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
archive_entry_sparse_reset(struct archive_entry * entry)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
archive_entry_sparse_next(struct archive_entry * entry,la_int64_t * offset,la_int64_t * length)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