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