Imported Upstream version 1.2.0
[platform/upstream/libzip.git] / lib / zip_open.c
1 /*
2   zip_open.c -- open zip archive by name
3   Copyright (C) 1999-2016 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 *
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 *
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 void
161 zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback)
162 {
163     za->progress_callback = progress_callback;
164 }
165
166
167 zip_t *
168 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
169 {
170     zip_t *za;
171     zip_cdir_t *cdir;
172     struct zip_stat st;
173     zip_uint64_t len, idx;
174
175     zip_stat_init(&st);
176     if (zip_source_stat(src, &st) < 0) {
177         _zip_error_set_from_source(error, src);
178         return NULL;
179     }
180     if ((st.valid & ZIP_STAT_SIZE) == 0) {
181         zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);
182         return NULL;
183     }
184     len = st.size;
185
186     /* treat empty files as empty archives */
187     if (len == 0) {
188         if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
189             zip_source_free(src);
190             return NULL;
191         }
192
193         return za;
194     }
195
196     if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
197         return NULL;
198     }
199
200     if ((cdir = _zip_find_central_dir(za, len)) == NULL) {
201         _zip_error_copy(error, &za->error);
202         /* keep src so discard does not get rid of it */
203         zip_source_keep(src);
204         zip_discard(za);
205         return NULL;
206     }
207
208     za->entry = cdir->entry;
209     za->nentry = cdir->nentry;
210     za->nentry_alloc = cdir->nentry_alloc;
211     za->comment_orig = cdir->comment;
212
213     free(cdir);
214
215     for (idx = 0; idx < za->nentry; idx++) {
216         const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);
217         if (name == NULL) {
218                 /* keep src so discard does not get rid of it */
219                 zip_source_keep(src);
220                 zip_discard(za);
221                 return NULL;
222         }
223
224         if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) {
225             if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) {
226                 _zip_error_copy(error, &za->error);
227                 /* keep src so discard does not get rid of it */
228                 zip_source_keep(src);
229                 zip_discard(za);
230                 return NULL;
231             }
232         }
233     }
234
235     za->ch_flags = za->flags;
236
237     return za;
238 }
239
240
241 void
242 _zip_set_open_error(int *zep, const zip_error_t *err, int ze)
243 {
244     if (err) {
245         ze = zip_error_code_zip(err);
246         if (zip_error_system_type(err) == ZIP_ET_SYS) {
247             errno = zip_error_code_system(err);
248         }
249     }
250
251     if (zep)
252         *zep = ze;
253 }
254
255
256 /* _zip_readcdir:
257    tries to find a valid end-of-central-directory at the beginning of
258    buf, and then the corresponding central directory entries.
259    Returns a struct zip_cdir which contains the central directory
260    entries, or NULL if unsuccessful. */
261
262 static zip_cdir_t *
263 _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error)
264 {
265     zip_cdir_t *cd;
266     zip_uint16_t comment_len;
267     zip_uint64_t i, left;
268     zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);
269     zip_buffer_t *cd_buffer;
270
271     if (_zip_buffer_left(buffer) < EOCDLEN) {
272         /* not enough bytes left for comment */
273         zip_error_set(error, ZIP_ER_NOZIP, 0);
274         return NULL;
275     }
276
277     /* check for end-of-central-dir magic */
278     if (memcmp(_zip_buffer_get(buffer, 4), EOCD_MAGIC, 4) != 0) {
279         zip_error_set(error, ZIP_ER_NOZIP, 0);
280         return NULL;
281     }
282
283     if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {
284         _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);
285         cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error);
286     }
287     else {
288         _zip_buffer_set_offset(buffer, eocd_offset);
289         cd = _zip_read_eocd(buffer, buf_offset, za->flags, error);
290     }
291
292     if (cd == NULL)
293         return NULL;
294
295     _zip_buffer_set_offset(buffer, eocd_offset + 20);
296     comment_len = _zip_buffer_get_16(buffer);
297
298     if (cd->offset + cd->size > buf_offset + eocd_offset) {
299         /* cdir spans past EOCD record */
300         zip_error_set(error, ZIP_ER_INCONS, 0);
301         _zip_cdir_free(cd);
302         return NULL;
303     }
304
305     if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
306         zip_uint64_t tail_len;
307
308         _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
309         tail_len = _zip_buffer_left(buffer);
310
311         if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
312             zip_error_set(error, ZIP_ER_INCONS, 0);
313             _zip_cdir_free(cd);
314             return NULL;
315         }
316
317         if (comment_len) {
318             if ((cd->comment=_zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
319                 _zip_cdir_free(cd);
320                 return NULL;
321             }
322         }
323     }
324
325     if (cd->offset >= buf_offset) {
326         zip_uint8_t *data;
327         /* if buffer already read in, use it */
328         _zip_buffer_set_offset(buffer, cd->offset - buf_offset);
329
330         if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
331             zip_error_set(error, ZIP_ER_INCONS, 0);
332             _zip_cdir_free(cd);
333             return NULL;
334         }
335         if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
336             zip_error_set(error, ZIP_ER_MEMORY, 0);
337             _zip_cdir_free(cd);
338             return NULL;
339         }
340     }
341     else {
342         cd_buffer = NULL;
343
344         if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
345             _zip_error_set_from_source(error, za->src);
346             _zip_cdir_free(cd);
347             return NULL;
348         }
349
350         /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */
351         if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {
352             zip_error_set(error, ZIP_ER_NOZIP, 0);
353             _zip_cdir_free(cd);
354             return NULL;
355         }
356     }
357
358     left = (zip_uint64_t)cd->size;
359     i=0;
360     while (left > 0) {
361         bool grown = false;
362         zip_int64_t entry_size;
363
364         if (i == cd->nentry) {
365             /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */
366             /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */
367
368             if (cd->is_zip64 || left < CDENTRYSIZE) {
369                 break;
370             }
371
372             if (!_zip_cdir_grow(cd, 0x10000, error)) {
373                 _zip_cdir_free(cd);
374                 _zip_buffer_free(cd_buffer);
375                 return NULL;
376             }
377             grown = true;
378         }
379
380         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) {
381             if (grown && zip_error_code_zip(error) == ZIP_ER_NOZIP) {
382                 zip_error_set(error, ZIP_ER_INCONS, 0);
383             }
384             _zip_cdir_free(cd);
385             _zip_buffer_free(cd_buffer);
386             return NULL;
387         }
388         i++;
389         left -= (zip_uint64_t)entry_size;
390     }
391
392     if (i != cd->nentry || left > 0) {
393         zip_error_set(error, ZIP_ER_INCONS, 0);
394         _zip_buffer_free(cd_buffer);
395         _zip_cdir_free(cd);
396         return NULL;
397     }
398
399     if (za->open_flags & ZIP_CHECKCONS) {
400         bool ok;
401
402         if (cd_buffer) {
403             ok = _zip_buffer_eof(cd_buffer);
404         }
405         else {
406             zip_int64_t offset = zip_source_tell(za->src);
407
408             if (offset < 0) {
409                 _zip_error_set_from_source(error, za->src);
410                 _zip_buffer_free(cd_buffer);
411                 _zip_cdir_free(cd);
412                 return NULL;
413             }
414             ok = ((zip_uint64_t)offset == cd->offset + cd->size);
415         }
416
417         if (!ok) {
418             zip_error_set(error, ZIP_ER_INCONS, 0);
419             _zip_buffer_free(cd_buffer);
420             _zip_cdir_free(cd);
421             return NULL;
422         }
423     }
424
425     _zip_buffer_free(cd_buffer);
426     return cd;
427 }
428
429
430 /* _zip_checkcons:
431    Checks the consistency of the central directory by comparing central
432    directory entries with local headers and checking for plausible
433    file and header offsets. Returns -1 if not plausible, else the
434    difference between the lowest and the highest fileposition reached */
435
436 static zip_int64_t
437 _zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error)
438 {
439     zip_uint64_t i;
440     zip_uint64_t min, max, j;
441     struct zip_dirent temp;
442
443     _zip_dirent_init(&temp);
444     if (cd->nentry) {
445         max = cd->entry[0].orig->offset;
446         min = cd->entry[0].orig->offset;
447     }
448     else
449         min = max = 0;
450
451     for (i=0; i<cd->nentry; i++) {
452         if (cd->entry[i].orig->offset < min)
453             min = cd->entry[i].orig->offset;
454         if (min > (zip_uint64_t)cd->offset) {
455             zip_error_set(error, ZIP_ER_NOZIP, 0);
456             return -1;
457         }
458
459         j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
460             + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
461         if (j > max)
462             max = j;
463         if (max > (zip_uint64_t)cd->offset) {
464             zip_error_set(error, ZIP_ER_NOZIP, 0);
465             return -1;
466         }
467
468         if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {
469             _zip_error_set_from_source(error, za->src);
470             return -1;
471         }
472
473         if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) {
474             _zip_dirent_finalize(&temp);
475             return -1;
476         }
477
478         if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
479             zip_error_set(error, ZIP_ER_INCONS, 0);
480             _zip_dirent_finalize(&temp);
481             return -1;
482         }
483
484         cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
485         cd->entry[i].orig->local_extra_fields_read = 1;
486         temp.extra_fields = NULL;
487
488         _zip_dirent_finalize(&temp);
489     }
490
491     return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
492 }
493
494
495 /* _zip_headercomp:
496    compares a central directory entry and a local file header
497    Return 0 if they are consistent, -1 if not. */
498
499 static int
500 _zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local)
501 {
502     if ((central->version_needed < local->version_needed)
503 #if 0
504         /* some zip-files have different values in local
505            and global headers for the bitflags */
506         || (central->bitflags != local->bitflags)
507 #endif
508         || (central->comp_method != local->comp_method)
509         || (central->last_mod != local->last_mod)
510         || !_zip_string_equal(central->filename, local->filename))
511         return -1;
512
513     if ((central->crc != local->crc) || (central->comp_size != local->comp_size)
514         || (central->uncomp_size != local->uncomp_size)) {
515         /* InfoZip stores valid values in local header even when data descriptor is used.
516            This is in violation of the appnote. */
517         if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0
518              || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0))
519             return -1;
520     }
521
522     return 0;
523 }
524
525
526 static zip_t *
527 _zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error)
528 {
529     zip_t *za;
530
531     if ((za = _zip_new(error)) == NULL) {
532         return NULL;
533     }
534
535     za->src = src;
536     za->open_flags = flags;
537     if (flags & ZIP_RDONLY) {
538         za->flags |= ZIP_AFL_RDONLY;
539         za->ch_flags |= ZIP_AFL_RDONLY;
540     }
541     return za;
542 }
543
544
545 /*
546  * tests for file existence
547  */
548 static exists_t
549 _zip_file_exists(zip_source_t *src, zip_error_t *error)
550 {
551     struct zip_stat st;
552
553     zip_stat_init(&st);
554     if (zip_source_stat(src, &st) != 0) {
555         zip_error_t *src_error = zip_source_error(src);
556         if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) {
557             return EXISTS_NOT;
558         }
559         _zip_error_copy(error, src_error);
560         return EXISTS_ERROR;
561     }
562
563     return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
564 }
565
566
567 static zip_cdir_t *
568 _zip_find_central_dir(zip_t *za, zip_uint64_t len)
569 {
570     zip_cdir_t *cdir, *cdirnew;
571     zip_uint8_t *match;
572     zip_int64_t buf_offset;
573     zip_uint64_t buflen;
574     zip_int64_t a;
575     zip_int64_t best;
576     zip_error_t error;
577     zip_buffer_t *buffer;
578
579     if (len < EOCDLEN) {
580         zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
581         return NULL;
582     }
583
584     buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);
585     if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {
586         zip_error_t *src_error = zip_source_error(za->src);
587         if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {
588             /* seek before start of file on my machine */
589             _zip_error_copy(&za->error, src_error);
590             return NULL;
591         }
592     }
593     if ((buf_offset = zip_source_tell(za->src)) < 0) {
594         _zip_error_set_from_source(&za->error, za->src);
595         return NULL;
596     }
597
598     if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
599         return NULL;
600     }
601
602     best = -1;
603     cdir = NULL;
604     if (buflen >= CDBUFSIZE) {
605         /* EOCD64 locator is before EOCD, so leave place for it */
606         _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
607     }
608     zip_error_set(&error, ZIP_ER_NOZIP, 0);
609
610     match = _zip_buffer_get(buffer, 0);
611     while ((match=_zip_memmem(match, _zip_buffer_left(buffer)-(EOCDLEN-4), (const unsigned char *)EOCD_MAGIC, 4)) != NULL) {
612         _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
613         if ((cdirnew = _zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &error)) != NULL) {
614             if (cdir) {
615                 if (best <= 0) {
616                     best = _zip_checkcons(za, cdir, &error);
617                 }
618
619                 a = _zip_checkcons(za, cdirnew, &error);
620                 if (best < a) {
621                     _zip_cdir_free(cdir);
622                     cdir = cdirnew;
623                     best = a;
624                 }
625                 else {
626                     _zip_cdir_free(cdirnew);
627                 }
628             }
629             else {
630                 cdir = cdirnew;
631                 if (za->open_flags & ZIP_CHECKCONS)
632                     best = _zip_checkcons(za, cdir, &error);
633                 else {
634                     best = 0;
635                 }
636             }
637             cdirnew = NULL;
638         }
639
640         match++;
641         _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
642     }
643
644     _zip_buffer_free(buffer);
645
646     if (best < 0) {
647         _zip_error_copy(&za->error, &error);
648         _zip_cdir_free(cdir);
649         return NULL;
650     }
651
652     return cdir;
653 }
654
655
656 static unsigned char *
657 _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen)
658 {
659     const unsigned char *p;
660
661     if ((biglen < littlelen) || (littlelen == 0))
662         return NULL;
663     p = big-1;
664     while ((p=(const unsigned char *)
665                 memchr(p+1, little[0], (size_t)(big-(p+1))+(size_t)(biglen-littlelen)+1)) != NULL) {
666         if (memcmp(p+1, little+1, littlelen-1)==0)
667             return (unsigned char *)p;
668     }
669
670     return NULL;
671 }
672
673
674 static zip_cdir_t *
675 _zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
676 {
677     zip_cdir_t *cd;
678     zip_uint64_t i, nentry, size, offset, eocd_offset;
679
680     if (_zip_buffer_left(buffer) < EOCDLEN) {
681         zip_error_set(error, ZIP_ER_INCONS, 0);
682         return NULL;
683     }
684
685     eocd_offset = _zip_buffer_offset(buffer);
686
687     _zip_buffer_get(buffer, 4); /* magic already verified */
688
689     if (_zip_buffer_get_32(buffer) != 0) {
690         zip_error_set(error, ZIP_ER_MULTIDISK, 0);
691         return NULL;
692     }
693
694     /* number of cdir-entries on this disk */
695     i = _zip_buffer_get_16(buffer);
696     /* number of cdir-entries */
697     nentry = _zip_buffer_get_16(buffer);
698
699     if (nentry != i) {
700         zip_error_set(error, ZIP_ER_NOZIP, 0);
701         return NULL;
702     }
703
704     size = _zip_buffer_get_32(buffer);
705     offset = _zip_buffer_get_32(buffer);
706
707     if (offset+size < offset) {
708         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
709         return NULL;
710     }
711
712     if (offset+size > buf_offset + eocd_offset) {
713         /* cdir spans past EOCD record */
714         zip_error_set(error, ZIP_ER_INCONS, 0);
715         return NULL;
716     }
717
718     if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
719         zip_error_set(error, ZIP_ER_INCONS, 0);
720         return NULL;
721     }
722
723     if ((cd=_zip_cdir_new(nentry, error)) == NULL)
724         return NULL;
725
726     cd->is_zip64 = false;
727     cd->size = size;
728     cd->offset = offset;
729
730     return cd;
731 }
732
733
734 static zip_cdir_t *
735 _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
736 {
737     zip_cdir_t *cd;
738     zip_uint64_t offset;
739     zip_uint8_t eocd[EOCD64LEN];
740     zip_uint64_t eocd_offset;
741     zip_uint64_t size, nentry, i, eocdloc_offset;
742     bool free_buffer;
743     zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64;
744
745     eocdloc_offset = _zip_buffer_offset(buffer);
746
747     _zip_buffer_get(buffer, 4); /* magic already verified */
748
749     num_disks = _zip_buffer_get_16(buffer);
750     eocd_disk = _zip_buffer_get_16(buffer);
751     eocd_offset = _zip_buffer_get_64(buffer);
752
753     if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
754         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
755         return NULL;
756     }
757
758     if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
759         zip_error_set(error, ZIP_ER_INCONS, 0);
760         return NULL;
761     }
762
763     if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
764         _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
765         free_buffer = false;
766     }
767     else {
768         if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
769             _zip_error_set_from_source(error, src);
770             return NULL;
771         }
772         if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
773             return NULL;
774         }
775         free_buffer = true;
776     }
777
778     if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
779         zip_error_set(error, ZIP_ER_INCONS, 0);
780         if (free_buffer) {
781             _zip_buffer_free(buffer);
782         }
783         return NULL;
784     }
785
786     size = _zip_buffer_get_64(buffer);
787
788     if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
789         zip_error_set(error, ZIP_ER_INCONS, 0);
790         if (free_buffer) {
791             _zip_buffer_free(buffer);
792         }
793         return NULL;
794     }
795
796     _zip_buffer_get(buffer, 4); /* skip version made by/needed */
797
798     num_disks64 = _zip_buffer_get_32(buffer);
799     eocd_disk64 = _zip_buffer_get_32(buffer);
800
801     /* if eocd values are 0xffff, we have to use eocd64 values.
802        otherwise, if the values are not the same, it's inconsistent;
803        in any case, if the value is not 0, we don't support it */
804     if (num_disks == 0xffff) {
805         num_disks = num_disks64;
806     }
807     if (eocd_disk == 0xffff) {
808         eocd_disk = eocd_disk64;
809     }
810     if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
811         zip_error_set(error, ZIP_ER_INCONS, 0);
812         return NULL;
813     }
814     if (num_disks != 0 || eocd_disk != 0) {
815         zip_error_set(error, ZIP_ER_MULTIDISK, 0);
816         return NULL;
817     }
818
819     nentry = _zip_buffer_get_64(buffer);
820     i = _zip_buffer_get_64(buffer);
821
822     if (nentry != i) {
823         zip_error_set(error, ZIP_ER_MULTIDISK, 0);
824         if (free_buffer) {
825             _zip_buffer_free(buffer);
826         }
827         return NULL;
828     }
829
830     size = _zip_buffer_get_64(buffer);
831     offset = _zip_buffer_get_64(buffer);
832
833     if (!_zip_buffer_ok(buffer)) {
834         zip_error_set(error, ZIP_ER_INTERNAL, 0);
835         if (free_buffer) {
836             _zip_buffer_free(buffer);
837         }
838         return NULL;
839     }
840
841     if (free_buffer) {
842         _zip_buffer_free(buffer);
843     }
844
845     if (offset > ZIP_INT64_MAX || offset+size < offset) {
846         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
847         return NULL;
848     }
849     if ((flags & ZIP_CHECKCONS) && offset+size != eocd_offset) {
850         zip_error_set(error, ZIP_ER_INCONS, 0);
851         return NULL;
852     }
853
854     if ((cd=_zip_cdir_new(nentry, error)) == NULL)
855         return NULL;
856
857     cd->is_zip64 = true;
858     cd->size = size;
859     cd->offset = offset;
860
861     return cd;
862 }