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 
38 void
archive_entry_sparse_clear(struct archive_entry * entry)39 archive_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 
51 void
archive_entry_sparse_add_entry(struct archive_entry * entry,la_int64_t offset,la_int64_t length)52 archive_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  */
101 int
archive_entry_sparse_count(struct archive_entry * entry)102 archive_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 
127 int
archive_entry_sparse_reset(struct archive_entry * entry)128 archive_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 
135 int
archive_entry_sparse_next(struct archive_entry * entry,la_int64_t * offset,la_int64_t * length)136 archive_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