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 = 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