1 /*
2 * Copyright 2018 Jonathan Dieter <jdieter@gmail.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #if defined(FREEBSD) || defined(__DragonFly__)
32 #include <sys/endian.h>
33 #elif __APPLE__
34 #include <machine/endian.h>
35 #else
36 #include <endian.h>
37 #endif
38 #include <zck.h>
39
40 #include "zck_private.h"
41
index_read(zckCtx * zck,char * data,size_t size,size_t max_length)42 bool index_read(zckCtx *zck, char *data, size_t size, size_t max_length) {
43 VALIDATE_BOOL(zck);
44 size_t length = 0;
45
46 /* Read and configure hash type */
47 int hash_type = 0;
48 if(!compint_to_int(zck, &hash_type, data + length, &length, max_length)) {
49 set_fatal_error(zck, "Unable to read hash type");
50 return false;
51 }
52 if(!set_chunk_hash_type(zck, hash_type)) {
53 set_fatal_error(zck, "Unable to set chunk hash type");
54 return false;
55 }
56
57 /* Read number of index entries */
58 size_t index_count;
59 if(!compint_to_size(zck, &index_count, data + length, &length,
60 max_length)) {
61 set_fatal_error(zck, "Unable to read index count");
62 return false;
63 }
64 zck->index.count = index_count;
65
66 zckChunk *prev = zck->index.first;
67 size_t idx_loc = 0;
68 int count = 0;
69 while(length < size) {
70 if(length + zck->index.digest_size > max_length) {
71 set_fatal_error(zck, "Read past end of header");
72 return false;
73 }
74
75 zckChunk *tmp = NULL;
76 zckChunk *new = zmalloc(sizeof(zckChunk));
77
78 /* Read index entry digest */
79 new->digest = zmalloc(zck->index.digest_size);
80 memcpy(new->digest, data+length, zck->index.digest_size);
81 new->digest_size = zck->index.digest_size;
82 HASH_FIND(hh, zck->index.ht, new->digest, new->digest_size, tmp);
83 if(!tmp)
84 HASH_ADD_KEYPTR(hh, zck->index.ht, new->digest, new->digest_size,
85 new);
86 length += zck->index.digest_size;
87
88 /* Read and store entry length */
89 size_t chunk_length = 0;
90 if(!compint_to_size(zck, &chunk_length, data+length, &length,
91 max_length)) {
92 set_fatal_error(zck, "Unable to read chunk %i compressed size",
93 count);
94 return false;
95 }
96 new->start = idx_loc;
97 new->comp_length = chunk_length;
98
99 /* Read and store uncompressed entry length */
100 chunk_length = 0;
101 if(!compint_to_size(zck, &chunk_length, data+length, &length,
102 max_length)) {
103 set_fatal_error(zck, "Unable to read chunk %i uncompressed size",
104 count);
105 return false;
106 }
107 new->length = chunk_length;
108 new->zck = zck;
109 new->valid = 0;
110 new->number = count;
111 idx_loc += new->comp_length;
112 count++;
113 zck->index.length = idx_loc;
114
115 if(prev)
116 prev->next = new;
117 else
118 zck->index.first = new;
119 prev = new;
120 }
121 free(zck->index_string);
122 zck->index_string = NULL;
123 return true;
124 }
125
zck_get_chunk_count(zckCtx * zck)126 ssize_t PUBLIC zck_get_chunk_count(zckCtx *zck) {
127 VALIDATE_INT(zck);
128
129 return zck->index.count;
130 }
131
zck_get_chunk(zckCtx * zck,size_t number)132 zckChunk PUBLIC *zck_get_chunk(zckCtx *zck, size_t number) {
133 VALIDATE_PTR(zck);
134
135 for(zckChunk *idx=zck->index.first; idx!=NULL; idx=idx->next) {
136 if(idx->number == number)
137 return idx;
138 }
139 zck_log(ZCK_LOG_WARNING, "Chunk %lu not found", number);
140 return NULL;
141 }
142
zck_get_first_chunk(zckCtx * zck)143 zckChunk PUBLIC *zck_get_first_chunk(zckCtx *zck) {
144 VALIDATE_PTR(zck);
145
146 return zck->index.first;
147 }
148
zck_get_next_chunk(zckChunk * idx)149 zckChunk PUBLIC *zck_get_next_chunk(zckChunk *idx) {
150 if(idx && idx->zck) {
151 VALIDATE_PTR(idx->zck);
152 ALLOCD_PTR(idx->zck, idx);
153 } else {
154 ALLOCD_PTR(NULL, idx);
155 }
156
157 return idx->next;
158 }
159
zck_get_chunk_start(zckChunk * idx)160 ssize_t PUBLIC zck_get_chunk_start(zckChunk *idx) {
161 if(idx && idx->zck) {
162 VALIDATE_INT(idx->zck);
163 ALLOCD_INT(idx->zck, idx);
164 } else {
165 ALLOCD_INT(NULL, idx);
166 }
167
168 if(idx->zck)
169 return idx->start + zck_get_header_length(idx->zck);
170 else
171 return idx->start;
172 }
173
zck_get_chunk_size(zckChunk * idx)174 ssize_t PUBLIC zck_get_chunk_size(zckChunk *idx) {
175 if(idx && idx->zck) {
176 VALIDATE_INT(idx->zck);
177 ALLOCD_INT(idx->zck, idx);
178 } else {
179 ALLOCD_INT(NULL, idx);
180 }
181
182 return idx->length;
183 }
184
zck_get_chunk_comp_size(zckChunk * idx)185 ssize_t PUBLIC zck_get_chunk_comp_size(zckChunk *idx) {
186 if(idx && idx->zck) {
187 VALIDATE_INT(idx->zck);
188 ALLOCD_INT(idx->zck, idx);
189 } else {
190 ALLOCD_INT(NULL, idx);
191 }
192
193 return idx->comp_length;
194 }
195
zck_get_chunk_number(zckChunk * idx)196 ssize_t PUBLIC zck_get_chunk_number(zckChunk *idx) {
197 if(idx && idx->zck) {
198 VALIDATE_INT(idx->zck);
199 ALLOCD_INT(idx->zck, idx);
200 } else {
201 ALLOCD_INT(NULL, idx);
202 }
203
204 return idx->number;
205 }
206
zck_get_chunk_valid(zckChunk * idx)207 int PUBLIC zck_get_chunk_valid(zckChunk *idx) {
208 if(idx && idx->zck) {
209 VALIDATE_INT(idx->zck);
210 ALLOCD_INT(idx->zck, idx);
211 } else {
212 ALLOCD_INT(NULL, idx);
213 }
214
215 return idx->valid;
216 }
217
zck_compare_chunk_digest(zckChunk * a,zckChunk * b)218 bool PUBLIC zck_compare_chunk_digest(zckChunk *a, zckChunk *b) {
219 if(a && a->zck) {
220 VALIDATE_BOOL(a->zck);
221 ALLOCD_BOOL(a->zck, a);
222 } else {
223 ALLOCD_BOOL(NULL, a);
224 }
225 if(b && b->zck) {
226 VALIDATE_BOOL(b->zck);
227 ALLOCD_BOOL(b->zck, b);
228 } else {
229 ALLOCD_BOOL(NULL, b);
230 }
231
232 if(a->digest_size != b->digest_size)
233 return false;
234 if(memcmp(a->digest, b->digest, a->digest_size) != 0)
235 return false;
236 return true;
237 }
238
zck_missing_chunks(zckCtx * zck)239 int PUBLIC zck_missing_chunks(zckCtx *zck) {
240 VALIDATE_READ_INT(zck);
241
242 int missing = 0;
243 for(zckChunk *idx = zck->index.first; idx; idx=idx->next)
244 if(idx->valid == 0)
245 missing++;
246 return missing;
247 }
248
zck_failed_chunks(zckCtx * zck)249 int PUBLIC zck_failed_chunks(zckCtx *zck) {
250 VALIDATE_READ_INT(zck);
251
252 int failed = 0;
253 for(zckChunk *idx = zck->index.first; idx; idx=idx->next)
254 if(idx->valid == -1)
255 failed++;
256 return failed;
257 }
258
zck_reset_failed_chunks(zckCtx * zck)259 void PUBLIC zck_reset_failed_chunks(zckCtx *zck) {
260 if(!zck)
261 return;
262
263 for(zckChunk *idx = zck->index.first; idx; idx=idx->next)
264 if(idx->valid == -1)
265 idx->valid = 0;
266 return;
267 }
268