2 zip_open.c -- open zip archive by name
3 Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
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
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
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.
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);
61 zip_open(const char *fn, int _flags, int *zep)
65 struct zip_error error;
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);
74 if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {
76 _zip_set_open_error(zep, &error, 0);
77 zip_error_fini(&error);
81 zip_error_fini(&error);
87 zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error)
89 static zip_int64_t needed_support_read = -1;
90 static zip_int64_t needed_support_write = -1;
93 zip_int64_t supported;
96 if (_flags < 0 || src == NULL) {
97 zip_error_set(error, ZIP_ER_INVAL, 0);
100 flags = (unsigned int)_flags;
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);
107 if ((supported & needed_support_read) != needed_support_read) {
108 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
111 if ((supported & needed_support_write) != needed_support_write) {
115 if ((flags & (ZIP_RDONLY|ZIP_TRUNCATE)) == (ZIP_RDONLY|ZIP_TRUNCATE)) {
116 zip_error_set(error, ZIP_ER_RDONLY, 0);
120 exists = _zip_file_exists(src, error);
126 if ((flags & ZIP_CREATE) == 0) {
127 zip_error_set(error, ZIP_ER_NOENT, 0);
130 return _zip_allocate_new(src, flags, error);
134 if (flags & ZIP_EXCL) {
135 zip_error_set(error, ZIP_ER_EXISTS, 0);
138 if (zip_source_open(src) < 0) {
139 _zip_error_set_from_source(error, src);
143 if (flags & ZIP_TRUNCATE) {
144 za = _zip_allocate_new(src, flags, error);
147 /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */
148 za = _zip_open(src, flags, error);
152 zip_source_close(src);
161 zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback)
163 za->progress_callback = progress_callback;
168 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
173 zip_uint64_t len, idx;
176 if (zip_source_stat(src, &st) < 0) {
177 _zip_error_set_from_source(error, src);
180 if ((st.valid & ZIP_STAT_SIZE) == 0) {
181 zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);
186 /* treat empty files as empty archives */
188 if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
189 zip_source_free(src);
196 if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
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);
208 za->entry = cdir->entry;
209 za->nentry = cdir->nentry;
210 za->nentry_alloc = cdir->nentry_alloc;
211 za->comment_orig = cdir->comment;
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);
218 /* keep src so discard does not get rid of it */
219 zip_source_keep(src);
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);
235 za->ch_flags = za->flags;
242 _zip_set_open_error(int *zep, const zip_error_t *err, int ze)
245 ze = zip_error_code_zip(err);
246 if (zip_error_system_type(err) == ZIP_ET_SYS) {
247 errno = zip_error_code_system(err);
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. */
263 _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error)
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;
271 if (_zip_buffer_left(buffer) < EOCDLEN) {
272 /* not enough bytes left for comment */
273 zip_error_set(error, ZIP_ER_NOZIP, 0);
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);
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);
288 _zip_buffer_set_offset(buffer, eocd_offset);
289 cd = _zip_read_eocd(buffer, buf_offset, za->flags, error);
295 _zip_buffer_set_offset(buffer, eocd_offset + 20);
296 comment_len = _zip_buffer_get_16(buffer);
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);
305 if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
306 zip_uint64_t tail_len;
308 _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
309 tail_len = _zip_buffer_left(buffer);
311 if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
312 zip_error_set(error, ZIP_ER_INCONS, 0);
318 if ((cd->comment=_zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
325 if (cd->offset >= buf_offset) {
327 /* if buffer already read in, use it */
328 _zip_buffer_set_offset(buffer, cd->offset - buf_offset);
330 if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
331 zip_error_set(error, ZIP_ER_INCONS, 0);
335 if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
336 zip_error_set(error, ZIP_ER_MEMORY, 0);
344 if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
345 _zip_error_set_from_source(error, za->src);
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);
358 left = (zip_uint64_t)cd->size;
362 zip_int64_t entry_size;
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. */
368 if (cd->is_zip64 || left < CDENTRYSIZE) {
372 if (!_zip_cdir_grow(cd, 0x10000, error)) {
374 _zip_buffer_free(cd_buffer);
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);
385 _zip_buffer_free(cd_buffer);
389 left -= (zip_uint64_t)entry_size;
392 if (i != cd->nentry || left > 0) {
393 zip_error_set(error, ZIP_ER_INCONS, 0);
394 _zip_buffer_free(cd_buffer);
399 if (za->open_flags & ZIP_CHECKCONS) {
403 ok = _zip_buffer_eof(cd_buffer);
406 zip_int64_t offset = zip_source_tell(za->src);
409 _zip_error_set_from_source(error, za->src);
410 _zip_buffer_free(cd_buffer);
414 ok = ((zip_uint64_t)offset == cd->offset + cd->size);
418 zip_error_set(error, ZIP_ER_INCONS, 0);
419 _zip_buffer_free(cd_buffer);
425 _zip_buffer_free(cd_buffer);
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 */
437 _zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error)
440 zip_uint64_t min, max, j;
441 struct zip_dirent temp;
443 _zip_dirent_init(&temp);
445 max = cd->entry[0].orig->offset;
446 min = cd->entry[0].orig->offset;
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);
459 j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
460 + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
463 if (max > (zip_uint64_t)cd->offset) {
464 zip_error_set(error, ZIP_ER_NOZIP, 0);
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);
473 if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) {
474 _zip_dirent_finalize(&temp);
478 if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
479 zip_error_set(error, ZIP_ER_INCONS, 0);
480 _zip_dirent_finalize(&temp);
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;
488 _zip_dirent_finalize(&temp);
491 return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
496 compares a central directory entry and a local file header
497 Return 0 if they are consistent, -1 if not. */
500 _zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local)
502 if ((central->version_needed < local->version_needed)
504 /* some zip-files have different values in local
505 and global headers for the bitflags */
506 || (central->bitflags != local->bitflags)
508 || (central->comp_method != local->comp_method)
509 || (central->last_mod != local->last_mod)
510 || !_zip_string_equal(central->filename, local->filename))
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))
527 _zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error)
531 if ((za = _zip_new(error)) == NULL) {
536 za->open_flags = flags;
537 if (flags & ZIP_RDONLY) {
538 za->flags |= ZIP_AFL_RDONLY;
539 za->ch_flags |= ZIP_AFL_RDONLY;
546 * tests for file existence
549 _zip_file_exists(zip_source_t *src, zip_error_t *error)
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) {
559 _zip_error_copy(error, src_error);
563 return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
568 _zip_find_central_dir(zip_t *za, zip_uint64_t len)
570 zip_cdir_t *cdir, *cdirnew;
572 zip_int64_t buf_offset;
577 zip_buffer_t *buffer;
580 zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
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);
593 if ((buf_offset = zip_source_tell(za->src)) < 0) {
594 _zip_error_set_from_source(&za->error, za->src);
598 if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
604 if (buflen >= CDBUFSIZE) {
605 /* EOCD64 locator is before EOCD, so leave place for it */
606 _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
608 zip_error_set(&error, ZIP_ER_NOZIP, 0);
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) {
616 best = _zip_checkcons(za, cdir, &error);
619 a = _zip_checkcons(za, cdirnew, &error);
621 _zip_cdir_free(cdir);
626 _zip_cdir_free(cdirnew);
631 if (za->open_flags & ZIP_CHECKCONS)
632 best = _zip_checkcons(za, cdir, &error);
641 _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
644 _zip_buffer_free(buffer);
647 _zip_error_copy(&za->error, &error);
648 _zip_cdir_free(cdir);
656 static unsigned char *
657 _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen)
659 const unsigned char *p;
661 if ((biglen < littlelen) || (littlelen == 0))
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;
675 _zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
678 zip_uint64_t i, nentry, size, offset, eocd_offset;
680 if (_zip_buffer_left(buffer) < EOCDLEN) {
681 zip_error_set(error, ZIP_ER_INCONS, 0);
685 eocd_offset = _zip_buffer_offset(buffer);
687 _zip_buffer_get(buffer, 4); /* magic already verified */
689 if (_zip_buffer_get_32(buffer) != 0) {
690 zip_error_set(error, ZIP_ER_MULTIDISK, 0);
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);
700 zip_error_set(error, ZIP_ER_NOZIP, 0);
704 size = _zip_buffer_get_32(buffer);
705 offset = _zip_buffer_get_32(buffer);
707 if (offset+size < offset) {
708 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
712 if (offset+size > buf_offset + eocd_offset) {
713 /* cdir spans past EOCD record */
714 zip_error_set(error, ZIP_ER_INCONS, 0);
718 if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
719 zip_error_set(error, ZIP_ER_INCONS, 0);
723 if ((cd=_zip_cdir_new(nentry, error)) == NULL)
726 cd->is_zip64 = false;
735 _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
739 zip_uint8_t eocd[EOCD64LEN];
740 zip_uint64_t eocd_offset;
741 zip_uint64_t size, nentry, i, eocdloc_offset;
743 zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64;
745 eocdloc_offset = _zip_buffer_offset(buffer);
747 _zip_buffer_get(buffer, 4); /* magic already verified */
749 num_disks = _zip_buffer_get_16(buffer);
750 eocd_disk = _zip_buffer_get_16(buffer);
751 eocd_offset = _zip_buffer_get_64(buffer);
753 if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
754 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
758 if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
759 zip_error_set(error, ZIP_ER_INCONS, 0);
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);
768 if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
769 _zip_error_set_from_source(error, src);
772 if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
778 if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
779 zip_error_set(error, ZIP_ER_INCONS, 0);
781 _zip_buffer_free(buffer);
786 size = _zip_buffer_get_64(buffer);
788 if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
789 zip_error_set(error, ZIP_ER_INCONS, 0);
791 _zip_buffer_free(buffer);
796 _zip_buffer_get(buffer, 4); /* skip version made by/needed */
798 num_disks64 = _zip_buffer_get_32(buffer);
799 eocd_disk64 = _zip_buffer_get_32(buffer);
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;
807 if (eocd_disk == 0xffff) {
808 eocd_disk = eocd_disk64;
810 if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
811 zip_error_set(error, ZIP_ER_INCONS, 0);
814 if (num_disks != 0 || eocd_disk != 0) {
815 zip_error_set(error, ZIP_ER_MULTIDISK, 0);
819 nentry = _zip_buffer_get_64(buffer);
820 i = _zip_buffer_get_64(buffer);
823 zip_error_set(error, ZIP_ER_MULTIDISK, 0);
825 _zip_buffer_free(buffer);
830 size = _zip_buffer_get_64(buffer);
831 offset = _zip_buffer_get_64(buffer);
833 if (!_zip_buffer_ok(buffer)) {
834 zip_error_set(error, ZIP_ER_INTERNAL, 0);
836 _zip_buffer_free(buffer);
842 _zip_buffer_free(buffer);
845 if (offset > ZIP_INT64_MAX || offset+size < offset) {
846 zip_error_set(error, ZIP_ER_SEEK, EFBIG);
849 if ((flags & ZIP_CHECKCONS) && offset+size != eocd_offset) {
850 zip_error_set(error, ZIP_ER_INCONS, 0);
854 if ((cd=_zip_cdir_new(nentry, error)) == NULL)