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