1 /*
2 zip_open.c -- open zip archive by name
3 Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner
4
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
16 distribution.
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
19 written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35 #include <sys/stat.h>
36 #include <limits.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "zipint.h"
42
43 typedef enum {
44 EXISTS_ERROR = -1,
45 EXISTS_NOT = 0,
46 EXISTS_EMPTY,
47 EXISTS_NONEMPTY,
48 } exists_t;
49 static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);
50 static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);
51 static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);
52 static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error);
53 static int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *);
54 static unsigned char *_zip_memmem(const unsigned char *, size_t, const unsigned char *, size_t);
55 static zip_cdir_t *_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error);
56 static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
57 static zip_cdir_t *_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
58
59
60 ZIP_EXTERN zip_t *
zip_open(const char * fn,int _flags,int * zep)61 zip_open(const char *fn, int _flags, int *zep)
62 {
63 zip_t *za;
64 zip_source_t *src;
65 struct zip_error error;
66
67 zip_error_init(&error);
68 if ((src = zip_source_file_create(fn, 0, -1, &error)) == NULL) {
69 _zip_set_open_error(zep, &error, 0);
70 zip_error_fini(&error);
71 return NULL;
72 }
73
74 if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {
75 zip_source_free(src);
76 _zip_set_open_error(zep, &error, 0);
77 zip_error_fini(&error);
78 return NULL;
79 }
80
81 zip_error_fini(&error);
82 return za;
83 }
84
85
86 ZIP_EXTERN zip_t *
zip_open_from_source(zip_source_t * src,int _flags,zip_error_t * error)87 zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error)
88 {
89 static zip_int64_t needed_support_read = -1;
90 static zip_int64_t needed_support_write = -1;
91
92 unsigned int flags;
93 zip_int64_t supported;
94 exists_t exists;
95
96 if (_flags < 0 || src == NULL) {
97 zip_error_set(error, ZIP_ER_INVAL, 0);
98 return NULL;
99 }
100 flags = (unsigned int)_flags;
101
102 supported = zip_source_supports(src);
103 if (needed_support_read == -1) {
104 needed_support_read = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_STAT, -1);
105 needed_support_write = zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1);
106 }
107 if ((supported & needed_support_read) != needed_support_read) {
108 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
109 return NULL;
110 }
111 if ((supported & needed_support_write) != needed_support_write) {
112 flags |= ZIP_RDONLY;
113 }
114
115 if ((flags & (ZIP_RDONLY|ZIP_TRUNCATE)) == (ZIP_RDONLY|ZIP_TRUNCATE)) {
116 zip_error_set(error, ZIP_ER_RDONLY, 0);
117 return NULL;
118 }
119
120 exists = _zip_file_exists(src, error);
121 switch (exists) {
122 case EXISTS_ERROR:
123 return NULL;
124
125 case EXISTS_NOT:
126 if ((flags & ZIP_CREATE) == 0) {
127 zip_error_set(error, ZIP_ER_NOENT, 0);
128 return NULL;
129 }
130 return _zip_allocate_new(src, flags, error);
131
132 default: {
133 zip_t *za;
134 if (flags & ZIP_EXCL) {
135 zip_error_set(error, ZIP_ER_EXISTS, 0);
136 return NULL;
137 }
138 if (zip_source_open(src) < 0) {
139 _zip_error_set_from_source(error, src);
140 return NULL;
141 }
142
143 if (flags & ZIP_TRUNCATE) {
144 za = _zip_allocate_new(src, flags, error);
145 }
146 else {
147 /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */
148 za = _zip_open(src, flags, error);
149 }
150
151 if (za == NULL) {
152 zip_source_close(src);
153 return NULL;
154 }
155 return za;
156 }
157 }
158 }
159
160 ZIP_EXTERN int
zip_archive_set_tempdir(zip_t * za,const char * tempdir)161 zip_archive_set_tempdir(zip_t *za, const char *tempdir)
162 {
163 char *new_tempdir;
164
165 if (tempdir) {
166 if ((new_tempdir = strdup(tempdir)) == NULL) {
167 zip_error_set(&za->error, ZIP_ER_MEMORY, errno);
168 return -1;
169 }
170 }
171 else
172 new_tempdir = NULL;
173
174 free(za->tempdir);
175 za->tempdir = new_tempdir;
176
177 return 0;
178 }
179
180 zip_t *
_zip_open(zip_source_t * src,unsigned int flags,zip_error_t * error)181 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
182 {
183 zip_t *za;
184 zip_cdir_t *cdir;
185 struct zip_stat st;
186 zip_uint64_t len, idx;
187
188 zip_stat_init(&st);
189 if (zip_source_stat(src, &st) < 0) {
190 _zip_error_set_from_source(error, src);
191 return NULL;
192 }
193 if ((st.valid & ZIP_STAT_SIZE) == 0) {
194 zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);
195 return NULL;
196 }
197 len = st.size;
198
199 /* treat empty files as empty archives */
200 if (len == 0) {
201 if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
202 zip_source_free(src);
203 return NULL;
204 }
205
206 return za;
207 }
208
209 if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
210 return NULL;
211 }
212
213 if ((cdir = _zip_find_central_dir(za, len)) == NULL) {
214 _zip_error_copy(error, &za->error);
215 /* keep src so discard does not get rid of it */
216 zip_source_keep(src);
217 zip_discard(za);
218 return NULL;
219 }
220
221 za->entry = cdir->entry;
222 za->nentry = cdir->nentry;
223 za->nentry_alloc = cdir->nentry_alloc;
224 za->comment_orig = cdir->comment;
225
226 free(cdir);
227
228 for (idx = 0; idx < za->nentry; idx++) {
229 const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);
230 if (name == NULL) {
231 /* keep src so discard does not get rid of it */
232 zip_source_keep(src);
233 zip_discard(za);
234 return NULL;
235 }
236
237 if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) {
238 if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) {
239 _zip_error_copy(error, &za->error);
240 /* keep src so discard does not get rid of it */
241 zip_source_keep(src);
242 zip_discard(za);
243 return NULL;
244 }
245 }
246 }
247
248 za->ch_flags = za->flags;
249
250 return za;
251 }
252
253
254 void
_zip_set_open_error(int * zep,const zip_error_t * err,int ze)255 _zip_set_open_error(int *zep, const zip_error_t *err, int ze)
256 {
257 if (err) {
258 ze = zip_error_code_zip(err);
259 if (zip_error_system_type(err) == ZIP_ET_SYS) {
260 errno = zip_error_code_system(err);
261 }
262 }
263
264 if (zep)
265 *zep = ze;
266 }
267
268
269 /* _zip_readcdir:
270 tries to find a valid end-of-central-directory at the beginning of
271 buf, and then the corresponding central directory entries.
272 Returns a struct zip_cdir which contains the central directory
273 entries, or NULL if unsuccessful. */
274
275 static zip_cdir_t *
_zip_read_cdir(zip_t * za,zip_buffer_t * buffer,zip_uint64_t buf_offset,zip_error_t * error)276 _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error)
277 {
278 zip_cdir_t *cd;
279 zip_uint16_t comment_len;
280 zip_uint64_t i, left;
281 zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);
282 zip_buffer_t *cd_buffer;
283
284 if (_zip_buffer_left(buffer) < EOCDLEN) {
285 /* not enough bytes left for comment */
286 zip_error_set(error, ZIP_ER_NOZIP, 0);
287 return NULL;
288 }
289
290 /* check for end-of-central-dir magic */
291 if (memcmp(_zip_buffer_get(buffer, 4), EOCD_MAGIC, 4) != 0) {
292 zip_error_set(error, ZIP_ER_NOZIP, 0);
293 return NULL;
294 }
295
296 if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {
297 _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);
298 cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error);
299 }
300 else {
301 _zip_buffer_set_offset(buffer, eocd_offset);
302 cd = _zip_read_eocd(buffer, buf_offset, za->flags, error);
303 }
304
305 if (cd == NULL)
306 return NULL;
307
308 _zip_buffer_set_offset(buffer, eocd_offset + 20);
309 comment_len = _zip_buffer_get_16(buffer);
310
311 if (cd->offset + cd->size > buf_offset + eocd_offset) {
312 /* cdir spans past EOCD record */
313 zip_error_set(error, ZIP_ER_INCONS, 0);
314 _zip_cdir_free(cd);
315 return NULL;
316 }
317
318 if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
319 zip_uint64_t tail_len;
320
321 _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
322 tail_len = _zip_buffer_left(buffer);
323
324 if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
325 zip_error_set(error, ZIP_ER_INCONS, 0);
326 _zip_cdir_free(cd);
327 return NULL;
328 }
329
330 if (comment_len) {
331 if ((cd->comment=_zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
332 _zip_cdir_free(cd);
333 return NULL;
334 }
335 }
336 }
337
338 if (cd->offset >= buf_offset) {
339 zip_uint8_t *data;
340 /* if buffer already read in, use it */
341 _zip_buffer_set_offset(buffer, cd->offset - buf_offset);
342
343 if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
344 zip_error_set(error, ZIP_ER_INCONS, 0);
345 _zip_cdir_free(cd);
346 return NULL;
347 }
348 if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
349 zip_error_set(error, ZIP_ER_MEMORY, 0);
350 _zip_cdir_free(cd);
351 return NULL;
352 }
353 }
354 else {
355 cd_buffer = NULL;
356
357 if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
358 _zip_error_set_from_source(error, za->src);
359 _zip_cdir_free(cd);
360 return NULL;
361 }
362
363 /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */
364 if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {
365 zip_error_set(error, ZIP_ER_NOZIP, 0);
366 _zip_cdir_free(cd);
367 return NULL;
368 }
369 }
370
371 left = (zip_uint64_t)cd->size;
372 i=0;
373 while (i<cd->nentry && left > 0) {
374 zip_int64_t entry_size;
375 if ((cd->entry[i].orig=_zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, error)) < 0) {
376 _zip_cdir_free(cd);
377 _zip_buffer_free(cd_buffer);
378 return NULL;
379 }
380 i++;
381 left -= (zip_uint64_t)entry_size;
382 }
383
384 if (i != cd->nentry) {
385 zip_error_set(error, ZIP_ER_INCONS, 0);
386 _zip_buffer_free(cd_buffer);
387 _zip_cdir_free(cd);
388 return NULL;
389 }
390
391 if (za->open_flags & ZIP_CHECKCONS) {
392 bool ok;
393
394 if (cd_buffer) {
395 ok = _zip_buffer_eof(cd_buffer);
396 }
397 else {
398 zip_int64_t offset = zip_source_tell(za->src);
399
400 if (offset < 0) {
401 _zip_error_set_from_source(error, za->src);
402 _zip_buffer_free(cd_buffer);
403 _zip_cdir_free(cd);
404 return NULL;
405 }
406 ok = ((zip_uint64_t)offset == cd->offset + cd->size);
407 }
408
409 if (!ok) {
410 zip_error_set(error, ZIP_ER_INCONS, 0);
411 _zip_buffer_free(cd_buffer);
412 _zip_cdir_free(cd);
413 return NULL;
414 }
415 }
416
417 _zip_buffer_free(cd_buffer);
418 return cd;
419 }
420
421
422 /* _zip_checkcons:
423 Checks the consistency of the central directory by comparing central
424 directory entries with local headers and checking for plausible
425 file and header offsets. Returns -1 if not plausible, else the
426 difference between the lowest and the highest fileposition reached */
427
428 static zip_int64_t
_zip_checkcons(zip_t * za,zip_cdir_t * cd,zip_error_t * error)429 _zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error)
430 {
431 zip_uint64_t i;
432 zip_uint64_t min, max, j;
433 struct zip_dirent temp;
434
435 _zip_dirent_init(&temp);
436 if (cd->nentry) {
437 max = cd->entry[0].orig->offset;
438 min = cd->entry[0].orig->offset;
439 }
440 else
441 min = max = 0;
442
443 for (i=0; i<cd->nentry; i++) {
444 if (cd->entry[i].orig->offset < min)
445 min = cd->entry[i].orig->offset;
446 if (min > (zip_uint64_t)cd->offset) {
447 zip_error_set(error, ZIP_ER_NOZIP, 0);
448 return -1;
449 }
450
451 j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
452 + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
453 if (j > max)
454 max = j;
455 if (max > (zip_uint64_t)cd->offset) {
456 zip_error_set(error, ZIP_ER_NOZIP, 0);
457 return -1;
458 }
459
460 if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {
461 _zip_error_set_from_source(error, za->src);
462 return -1;
463 }
464
465 if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) {
466 _zip_dirent_finalize(&temp);
467 return -1;
468 }
469
470 if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
471 zip_error_set(error, ZIP_ER_INCONS, 0);
472 _zip_dirent_finalize(&temp);
473 return -1;
474 }
475
476 cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
477 cd->entry[i].orig->local_extra_fields_read = 1;
478 temp.extra_fields = NULL;
479
480 _zip_dirent_finalize(&temp);
481 }
482
483 return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
484 }
485
486
487 /* _zip_headercomp:
488 compares a central directory entry and a local file header
489 Return 0 if they are consistent, -1 if not. */
490
491 static int
_zip_headercomp(const zip_dirent_t * central,const zip_dirent_t * local)492 _zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local)
493 {
494 if ((central->version_needed != local->version_needed)
495 #if 0
496 /* some zip-files have different values in local
497 and global headers for the bitflags */
498 || (central->bitflags != local->bitflags)
499 #endif
500 || (central->comp_method != local->comp_method)
501 || (central->last_mod != local->last_mod)
502 || !_zip_string_equal(central->filename, local->filename))
503 return -1;
504
505 if ((central->crc != local->crc) || (central->comp_size != local->comp_size)
506 || (central->uncomp_size != local->uncomp_size)) {
507 /* InfoZip stores valid values in local header even when data descriptor is used.
508 This is in violation of the appnote. */
509 if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0
510 || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0))
511 return -1;
512 }
513
514 return 0;
515 }
516
517
518 static zip_t *
_zip_allocate_new(zip_source_t * src,unsigned int flags,zip_error_t * error)519 _zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error)
520 {
521 zip_t *za;
522
523 if ((za = _zip_new(error)) == NULL) {
524 return NULL;
525 }
526
527 za->src = src;
528 za->open_flags = flags;
529 if (flags & ZIP_RDONLY) {
530 za->flags |= ZIP_AFL_RDONLY;
531 za->ch_flags |= ZIP_AFL_RDONLY;
532 }
533 return za;
534 }
535
536
537 /*
538 * tests for file existence
539 */
540 static exists_t
_zip_file_exists(zip_source_t * src,zip_error_t * error)541 _zip_file_exists(zip_source_t *src, zip_error_t *error)
542 {
543 struct zip_stat st;
544
545 zip_stat_init(&st);
546 if (zip_source_stat(src, &st) != 0) {
547 zip_error_t *src_error = zip_source_error(src);
548 if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) {
549 return EXISTS_NOT;
550 }
551 _zip_error_copy(error, src_error);
552 return EXISTS_ERROR;
553 }
554
555 return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
556 }
557
558
559 static zip_cdir_t *
_zip_find_central_dir(zip_t * za,zip_uint64_t len)560 _zip_find_central_dir(zip_t *za, zip_uint64_t len)
561 {
562 zip_cdir_t *cdir, *cdirnew;
563 zip_uint8_t *match;
564 zip_int64_t buf_offset;
565 zip_uint64_t buflen;
566 zip_int64_t a;
567 zip_int64_t best;
568 zip_error_t error;
569 zip_buffer_t *buffer;
570
571 if (len < EOCDLEN) {
572 zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
573 return NULL;
574 }
575
576 buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);
577 if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {
578 zip_error_t *src_error = zip_source_error(za->src);
579 if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {
580 /* seek before start of file on my machine */
581 _zip_error_copy(&za->error, src_error);
582 return NULL;
583 }
584 }
585 if ((buf_offset = zip_source_tell(za->src)) < 0) {
586 _zip_error_set_from_source(&za->error, za->src);
587 return NULL;
588 }
589
590 if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
591 return NULL;
592 }
593
594 best = -1;
595 cdir = NULL;
596 if (buflen >= CDBUFSIZE) {
597 /* EOCD64 locator is before EOCD, so leave place for it */
598 _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
599 }
600 zip_error_set(&error, ZIP_ER_NOZIP, 0);
601
602 match = _zip_buffer_get(buffer, 0);
603 while ((match=_zip_memmem(match, _zip_buffer_left(buffer)-(EOCDLEN-4), (const unsigned char *)EOCD_MAGIC, 4)) != NULL) {
604 _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
605 if ((cdirnew = _zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &error)) != NULL) {
606 if (cdir) {
607 if (best <= 0) {
608 best = _zip_checkcons(za, cdir, &error);
609 }
610
611 a = _zip_checkcons(za, cdirnew, &error);
612 if (best < a) {
613 _zip_cdir_free(cdir);
614 cdir = cdirnew;
615 best = a;
616 }
617 else {
618 _zip_cdir_free(cdirnew);
619 }
620 }
621 else {
622 cdir = cdirnew;
623 if (za->open_flags & ZIP_CHECKCONS)
624 best = _zip_checkcons(za, cdir, &error);
625 else {
626 best = 0;
627 }
628 }
629 cdirnew = NULL;
630 }
631
632 match++;
633 _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
634 }
635
636 _zip_buffer_free(buffer);
637
638 if (best < 0) {
639 _zip_error_copy(&za->error, &error);
640 _zip_cdir_free(cdir);
641 return NULL;
642 }
643
644 return cdir;
645 }
646
647
648 static unsigned char *
_zip_memmem(const unsigned char * big,size_t biglen,const unsigned char * little,size_t littlelen)649 _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen)
650 {
651 const unsigned char *p;
652
653 if ((biglen < littlelen) || (littlelen == 0))
654 return NULL;
655 p = big-1;
656 while ((p=(const unsigned char *)
657 memchr(p+1, little[0], (size_t)(big-(p+1))+(size_t)(biglen-littlelen)+1)) != NULL) {
658 if (memcmp(p+1, little+1, littlelen-1)==0)
659 return (unsigned char *)p;
660 }
661
662 return NULL;
663 }
664
665
666 static zip_cdir_t *
_zip_read_eocd(zip_buffer_t * buffer,zip_uint64_t buf_offset,unsigned int flags,zip_error_t * error)667 _zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
668 {
669 zip_cdir_t *cd;
670 zip_uint64_t i, nentry, size, offset, eocd_offset;
671
672 if (_zip_buffer_left(buffer) < EOCDLEN) {
673 zip_error_set(error, ZIP_ER_INCONS, 0);
674 return NULL;
675 }
676
677 eocd_offset = _zip_buffer_offset(buffer);
678
679 _zip_buffer_get(buffer, 4); /* magic already verified */
680
681 if (_zip_buffer_get_32(buffer) != 0) {
682 zip_error_set(error, ZIP_ER_MULTIDISK, 0);
683 return NULL;
684 }
685
686 /* number of cdir-entries on this disk */
687 i = _zip_buffer_get_16(buffer);
688 /* number of cdir-entries */
689 nentry = _zip_buffer_get_16(buffer);
690
691 if (nentry != i) {
692 zip_error_set(error, ZIP_ER_NOZIP, 0);
693 return NULL;
694 }
695
696 size = _zip_buffer_get_32(buffer);
697 offset = _zip_buffer_get_32(buffer);
698
699 if (offset+size < offset) {
700 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
701 return NULL;
702 }
703
704 if (offset+size > buf_offset + eocd_offset) {
705 /* cdir spans past EOCD record */
706 zip_error_set(error, ZIP_ER_INCONS, 0);
707 return NULL;
708 }
709
710 if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
711 zip_error_set(error, ZIP_ER_INCONS, 0);
712 return NULL;
713 }
714
715 if ((cd=_zip_cdir_new(nentry, error)) == NULL)
716 return NULL;
717
718 cd->size = size;
719 cd->offset = offset;
720
721 return cd;
722 }
723
724
725 static zip_cdir_t *
_zip_read_eocd64(zip_source_t * src,zip_buffer_t * buffer,zip_uint64_t buf_offset,unsigned int flags,zip_error_t * error)726 _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
727 {
728 zip_cdir_t *cd;
729 zip_uint64_t offset;
730 zip_uint8_t eocd[EOCD64LEN];
731 zip_uint64_t eocd_offset;
732 zip_uint64_t size, nentry, i, eocdloc_offset;
733 bool free_buffer;
734 zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64;
735
736 eocdloc_offset = _zip_buffer_offset(buffer);
737
738 _zip_buffer_get(buffer, 4); /* magic already verified */
739
740 num_disks = _zip_buffer_get_16(buffer);
741 eocd_disk = _zip_buffer_get_16(buffer);
742 eocd_offset = _zip_buffer_get_64(buffer);
743
744 if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
745 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
746 return NULL;
747 }
748
749 if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
750 zip_error_set(error, ZIP_ER_INCONS, 0);
751 return NULL;
752 }
753
754 if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
755 _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
756 free_buffer = false;
757 }
758 else {
759 if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
760 _zip_error_set_from_source(error, src);
761 return NULL;
762 }
763 if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
764 return NULL;
765 }
766 free_buffer = true;
767 }
768
769 if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
770 zip_error_set(error, ZIP_ER_INCONS, 0);
771 if (free_buffer) {
772 _zip_buffer_free(buffer);
773 }
774 return NULL;
775 }
776
777 size = _zip_buffer_get_64(buffer);
778
779 if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
780 zip_error_set(error, ZIP_ER_INCONS, 0);
781 if (free_buffer) {
782 _zip_buffer_free(buffer);
783 }
784 return NULL;
785 }
786
787 _zip_buffer_get(buffer, 4); /* skip version made by/needed */
788
789 num_disks64 = _zip_buffer_get_32(buffer);
790 eocd_disk64 = _zip_buffer_get_32(buffer);
791
792 /* if eocd values are 0xffff, we have to use eocd64 values.
793 otherwise, if the values are not the same, it's inconsistent;
794 in any case, if the value is not 0, we don't support it */
795 if (num_disks == 0xffff) {
796 num_disks = num_disks64;
797 }
798 if (eocd_disk == 0xffff) {
799 eocd_disk = eocd_disk64;
800 }
801 if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
802 zip_error_set(error, ZIP_ER_INCONS, 0);
803 return NULL;
804 }
805 if (num_disks != 0 || eocd_disk != 0) {
806 zip_error_set(error, ZIP_ER_MULTIDISK, 0);
807 return NULL;
808 }
809
810 nentry = _zip_buffer_get_64(buffer);
811 i = _zip_buffer_get_64(buffer);
812
813 if (nentry != i) {
814 zip_error_set(error, ZIP_ER_MULTIDISK, 0);
815 if (free_buffer) {
816 _zip_buffer_free(buffer);
817 }
818 return NULL;
819 }
820
821 size = _zip_buffer_get_64(buffer);
822 offset = _zip_buffer_get_64(buffer);
823
824 if (!_zip_buffer_ok(buffer)) {
825 zip_error_set(error, ZIP_ER_INTERNAL, 0);
826 if (free_buffer) {
827 _zip_buffer_free(buffer);
828 }
829 return NULL;
830 }
831
832 if (free_buffer) {
833 _zip_buffer_free(buffer);
834 }
835
836 if (offset > ZIP_INT64_MAX || offset+size < offset) {
837 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
838 return NULL;
839 }
840 if (offset+size > buf_offset + eocd_offset) {
841 /* cdir spans past EOCD record */
842 zip_error_set(error, ZIP_ER_INCONS, 0);
843 return NULL;
844 }
845 if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
846 zip_error_set(error, ZIP_ER_INCONS, 0);
847 return NULL;
848 }
849
850 if ((cd=_zip_cdir_new(nentry, error)) == NULL)
851 return NULL;
852
853
854 cd->size = size;
855 cd->offset = offset;
856
857 return cd;
858 }
859