summaryrefslogtreecommitdiff
path: root/ext/zip/lib/zip_open.c
diff options
context:
space:
mode:
authorStanley Sufficool <ssufficool@php.net>2014-10-20 21:33:32 -0700
committerStanley Sufficool <ssufficool@php.net>2014-10-20 21:33:32 -0700
commit8defcb855ab01d9c8ab4759cb793d80149b55a8c (patch)
treeed51eb30a2cbc92b102557498fb3e4113da1bb07 /ext/zip/lib/zip_open.c
parent9c7dbb0487f5991fde03873ea8f5e66d6688415f (diff)
parentbaddb1c73a170ef1d2c31bd54cddbc6e1ab596b9 (diff)
downloadphp-git-8defcb855ab01d9c8ab4759cb793d80149b55a8c.tar.gz
Merge branch 'master' of https://git.php.net/push/php-src
* 'master' of https://git.php.net/push/php-src: (6215 commits) Extra comma Moved proxy object support in ASSIGN_ADD (and family) from VM to slow paths of corresponding operators Simplification zend_get_property_info_quick() cleanup and optimization initialize lineno before calling compile file file in phar Use ADDREF instead of DUP, it must be enough. Removed old irrelevant comment fixed compilation error Fix bug #68262: Broken reference across cloned objects export functions needed for phpdbg Fixed compilation Optimized property access handlers. Removed EG(std_property_info). Fixed bug #68199 (PDO::pgsqlGetNotify doesn't support NOTIFY payloads) Don't make difference between undefined and unaccessible properies when call __get() and family Don't make useless CSE array_pop/array_shift optimization check for zlib headers as well as lib for mysqlnd a realpath cache key can be int or float, catching this News entry for new curl constants News entry for new curl constants ...
Diffstat (limited to 'ext/zip/lib/zip_open.c')
-rw-r--r--ext/zip/lib/zip_open.c480
1 files changed, 307 insertions, 173 deletions
diff --git a/ext/zip/lib/zip_open.c b/ext/zip/lib/zip_open.c
index 5ce1c1070a..d91fe469db 100644
--- a/ext/zip/lib/zip_open.c
+++ b/ext/zip/lib/zip_open.c
@@ -1,6 +1,6 @@
/*
zip_open.c -- open zip archive by name
- Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner
+ Copyright (C) 1999-2012 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -42,38 +42,53 @@
#include "zipint.h"
-static void set_error(int *, struct zip_error *, int);
-static struct zip *_zip_allocate_new(const char *, int *);
-static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
-static void _zip_check_torrentzip(struct zip *);
-static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, off_t);
-static int _zip_file_exists(const char *, int, int *);
-static int _zip_headercomp(struct zip_dirent *, int,
- struct zip_dirent *, int);
-static unsigned char *_zip_memmem(const unsigned char *, int,
- const unsigned char *, int);
-static struct zip_cdir *_zip_readcdir(FILE *, off_t, unsigned char *, unsigned char *,
- int, int, struct zip_error *);
+static void set_error(int *, const struct zip_error *, int);
+static struct zip *_zip_allocate_new(const char *, unsigned int, int *);
+static zip_int64_t _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
+static void _zip_check_torrentzip(struct zip *, const struct zip_cdir *);
+static struct zip_cdir *_zip_find_central_dir(FILE *, unsigned int, int *, off_t);
+static int _zip_file_exists(const char *, unsigned int, int *);
+static int _zip_headercomp(const struct zip_dirent *, const struct zip_dirent *);
+static unsigned char *_zip_memmem(const unsigned char *, size_t,
+ const unsigned char *, size_t);
+static struct zip_cdir *_zip_readcdir(FILE *, off_t, unsigned char *, const unsigned char *,
+ size_t, unsigned int, struct zip_error *);
+static struct zip_cdir *_zip_read_eocd(const unsigned char *, const unsigned char *, off_t,
+ size_t, unsigned int, struct zip_error *);
+static struct zip_cdir *_zip_read_eocd64(FILE *, const unsigned char *, const unsigned char *,
+ off_t, size_t, unsigned int, struct zip_error *);
-ZIP_EXTERN(struct zip *)
-zip_open(const char *fn, int flags, int *zep)
+ZIP_EXTERN struct zip *
+zip_open(const char *fn, int _flags, int *zep)
{
FILE *fp;
-
- if (flags & ZIP_OVERWRITE) {
- return _zip_allocate_new(fn, zep);
+ unsigned int flags;
+
+ if (_flags < 0) {
+ if (zep)
+ *zep = ZIP_ER_INVAL;
+ return NULL;
}
-
+ flags = (unsigned int)_flags;
+
switch (_zip_file_exists(fn, flags, zep)) {
case -1:
- if (!(flags & ZIP_OVERWRITE)) {
- return NULL;
- }
+ return NULL;
case 0:
- return _zip_allocate_new(fn, zep);
+ return _zip_allocate_new(fn, flags, zep);
default:
+ if (flags & ZIP_TRUNCATE) {
+ FILE *f;
+
+ if ((f = fopen(fn, "rb")) == NULL) {
+ set_error(zep, NULL, ZIP_ER_OPEN);
+ return NULL;
+ }
+ fclose(f);
+ return _zip_allocate_new(fn, flags, zep);
+ }
break;
}
@@ -82,17 +97,36 @@ zip_open(const char *fn, int flags, int *zep)
return NULL;
}
- return _zip_open(fn, fp, flags, 0, zep);
+ return _zip_open(fn, fp, flags, zep);
}
+
+ZIP_EXTERN int
+zip_archive_set_tempdir(struct zip *za, const char *tempdir)
+{
+ char *new_tempdir;
+
+ if (tempdir) {
+ if ((new_tempdir = strdup(tempdir)) == NULL) {
+ _zip_error_set(&za->error, ZIP_ER_MEMORY, errno);
+ return -1;
+ }
+ }
+ else
+ new_tempdir = NULL;
+
+ free(za->tempdir);
+ za->tempdir = new_tempdir;
+
+ return 0;
+}
struct zip *
-_zip_open(const char *fn, FILE *fp, int flags, int aflags, int *zep)
+_zip_open(const char *fn, FILE *fp, unsigned int flags, int *zep)
{
struct zip *za;
struct zip_cdir *cdir;
- int i;
off_t len;
if (fseeko(fp, 0, SEEK_END) < 0) {
@@ -103,7 +137,7 @@ _zip_open(const char *fn, FILE *fp, int flags, int aflags, int *zep)
/* treat empty files as empty archives */
if (len == 0) {
- if ((za=_zip_allocate_new(fn, zep)) == NULL)
+ if ((za=_zip_allocate_new(fn, flags, zep)) == NULL)
fclose(fp);
else
za->zp = fp;
@@ -116,34 +150,32 @@ _zip_open(const char *fn, FILE *fp, int flags, int aflags, int *zep)
return NULL;
}
- if ((za=_zip_allocate_new(fn, zep)) == NULL) {
+ if ((za=_zip_allocate_new(fn, flags, zep)) == NULL) {
_zip_cdir_free(cdir);
fclose(fp);
return NULL;
}
- za->cdir = cdir;
+ za->entry = cdir->entry;
+ za->nentry = cdir->nentry;
+ za->nentry_alloc = cdir->nentry_alloc;
+ za->comment_orig = cdir->comment;
+
za->zp = fp;
- if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
- * cdir->nentry)) == NULL) {
- set_error(zep, NULL, ZIP_ER_MEMORY);
- _zip_free(za);
- return NULL;
- }
- for (i=0; i<cdir->nentry; i++)
- _zip_entry_new(za);
+ _zip_check_torrentzip(za, cdir);
- _zip_check_torrentzip(za);
za->ch_flags = za->flags;
+ free(cdir);
+
return za;
}
static void
-set_error(int *zep, struct zip_error *err, int ze)
+set_error(int *zep, const struct zip_error *err, int ze)
{
int se;
@@ -166,16 +198,17 @@ set_error(int *zep, struct zip_error *err, int ze)
entries, or NULL if unsuccessful. */
static struct zip_cdir *
-_zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, unsigned char *eocd, int buflen,
- int flags, struct zip_error *error)
+_zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, const unsigned char *eocd, size_t buflen,
+ unsigned int flags, struct zip_error *error)
{
struct zip_cdir *cd;
- unsigned char *cdp, **bufp;
- int i, comlen, nentry;
- zip_uint32_t left;
+ const unsigned char *cdp;
+ const unsigned char **bufp;
+ zip_int64_t tail_len, comment_len;
+ zip_uint64_t i, left;
- comlen = buf + buflen - eocd - EOCDLEN;
- if (comlen < 0) {
+ tail_len = buf + buflen - eocd - EOCDLEN;
+ if (tail_len < 0) {
/* not enough bytes left for comment */
_zip_error_set(error, ZIP_ER_NOZIP, 0);
return NULL;
@@ -192,46 +225,32 @@ _zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, unsigned char *eoc
return NULL;
}
- cdp = eocd + 8;
- /* number of cdir-entries on this disk */
- i = _zip_read2(&cdp);
- /* number of cdir-entries */
- nentry = _zip_read2(&cdp);
+ if (eocd-EOCD64LOCLEN >= buf && memcmp(eocd-EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0)
+ cd = _zip_read_eocd64(fp, eocd-EOCD64LOCLEN, buf, buf_offset, buflen, flags, error);
+ else
+ cd = _zip_read_eocd(eocd, buf, buf_offset, buflen, flags, error);
- if ((cd=_zip_cdir_new(nentry, error)) == NULL)
+ if (cd == NULL)
return NULL;
- cd->size = _zip_read4(&cdp);
- cd->offset = _zip_read4(&cdp);
- cd->comment = NULL;
- cd->comment_len = _zip_read2(&cdp);
+ cdp = eocd + 20;
+ comment_len = _zip_read2(&cdp);
- if (((zip_uint64_t)cd->offset)+cd->size > buf_offset + (eocd-buf)) {
+ if ((zip_uint64_t)cd->offset+(zip_uint64_t)cd->size > (zip_uint64_t)buf_offset + (zip_uint64_t)(eocd-buf)) {
/* cdir spans past EOCD record */
_zip_error_set(error, ZIP_ER_INCONS, 0);
- cd->nentry = 0;
_zip_cdir_free(cd);
return NULL;
}
- if ((comlen < cd->comment_len) || (cd->nentry != i)) {
- _zip_error_set(error, ZIP_ER_NOZIP, 0);
- cd->nentry = 0;
- _zip_cdir_free(cd);
- return NULL;
- }
- if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) {
+ if (tail_len < comment_len || ((flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
_zip_error_set(error, ZIP_ER_INCONS, 0);
- cd->nentry = 0;
_zip_cdir_free(cd);
return NULL;
}
- if (cd->comment_len) {
- if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN,
- cd->comment_len, error))
- == NULL) {
- cd->nentry = 0;
+ if (comment_len) {
+ if ((cd->comment=_zip_string_new(eocd+EOCDLEN, (zip_uint16_t)comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
_zip_cdir_free(cd);
return NULL;
}
@@ -249,40 +268,32 @@ _zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, unsigned char *eoc
fseeko(fp, cd->offset, SEEK_SET);
/* possible consistency check: cd->offset =
len-(cd->size+cd->comment_len+EOCDLEN) ? */
- if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) {
+ if (ferror(fp) || (ftello(fp) != cd->offset)) {
/* seek error or offset of cdir wrong */
if (ferror(fp))
_zip_error_set(error, ZIP_ER_SEEK, errno);
else
_zip_error_set(error, ZIP_ER_NOZIP, 0);
- cd->nentry = 0;
_zip_cdir_free(cd);
return NULL;
}
}
- left = cd->size;
+ left = (zip_uint64_t)cd->size;
i=0;
while (i<cd->nentry && left > 0) {
- if ((_zip_dirent_read(cd->entry+i, fp, bufp, &left, 0, error)) < 0) {
- cd->nentry = i;
+ if ((cd->entry[i].orig=_zip_dirent_new()) == NULL
+ || (_zip_dirent_read(cd->entry[i].orig, fp, bufp, &left, 0, error)) < 0) {
_zip_cdir_free(cd);
return NULL;
}
i++;
-
- if (i == cd->nentry && left > 0) {
- /* Infozip extension for more than 64k entries:
- nentries wraps around, size indicates correct EOCD */
- if (_zip_cdir_grow(cd, cd->nentry+ZIP_UINT16_MAX, error) < 0) {
- cd->nentry = i;
- _zip_cdir_free(cd);
- return NULL;
- }
- }
}
-
- cd->nentry = i;
+ if (i != cd->nentry || ((flags & ZIP_CHECKCONS) && left != 0)) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ _zip_cdir_free(cd);
+ return NULL;
+ }
return cd;
}
@@ -295,54 +306,59 @@ _zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, unsigned char *eoc
file and header offsets. Returns -1 if not plausible, else the
difference between the lowest and the highest fileposition reached */
-static int
+static zip_int64_t
_zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
{
- int i;
- unsigned int min, max, j;
+ zip_uint64_t i;
+ zip_uint64_t min, max, j;
struct zip_dirent temp;
if (cd->nentry) {
- max = cd->entry[0].offset;
- min = cd->entry[0].offset;
+ max = cd->entry[0].orig->offset;
+ min = cd->entry[0].orig->offset;
}
else
min = max = 0;
for (i=0; i<cd->nentry; i++) {
- if (cd->entry[i].offset < min)
- min = cd->entry[i].offset;
- if (min > cd->offset) {
+ if (cd->entry[i].orig->offset < min)
+ min = cd->entry[i].orig->offset;
+ if (min > (zip_uint64_t)cd->offset) {
_zip_error_set(error, ZIP_ER_NOZIP, 0);
return -1;
}
- j = cd->entry[i].offset + cd->entry[i].comp_size
- + cd->entry[i].filename_len + LENTRYSIZE;
+ j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
+ + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
if (j > max)
max = j;
- if (max > cd->offset) {
+ if (max > (zip_uint64_t)cd->offset) {
_zip_error_set(error, ZIP_ER_NOZIP, 0);
return -1;
}
- if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) {
- _zip_error_set(error, ZIP_ER_SEEK, 0);
+ if (fseeko(fp, (off_t)cd->entry[i].orig->offset, SEEK_SET) != 0) {
+ _zip_error_set(error, ZIP_ER_SEEK, errno);
return -1;
}
if (_zip_dirent_read(&temp, fp, NULL, NULL, 1, error) == -1)
return -1;
- if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) {
+ if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
_zip_error_set(error, ZIP_ER_INCONS, 0);
_zip_dirent_finalize(&temp);
return -1;
}
+
+ cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
+ cd->entry[i].orig->local_extra_fields_read = 1;
+ temp.extra_fields = NULL;
+
_zip_dirent_finalize(&temp);
}
- return max - min;
+ return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
}
@@ -351,28 +367,27 @@ _zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
check whether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
static void
-_zip_check_torrentzip(struct zip *za)
+_zip_check_torrentzip(struct zip *za, const struct zip_cdir *cdir)
{
uLong crc_got, crc_should;
char buf[8+1];
char *end;
- if (za->zp == NULL || za->cdir == NULL)
+ if (za->zp == NULL || cdir == NULL)
return;
- if (za->cdir->comment_len != TORRENT_SIG_LEN+8
- || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
+ if (_zip_string_length(cdir->comment) != TORRENT_SIG_LEN+8
+ || strncmp((const char *)cdir->comment->raw, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
return;
- memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8);
+ memcpy(buf, cdir->comment->raw+TORRENT_SIG_LEN, 8);
buf[8] = '\0';
errno = 0;
crc_should = strtoul(buf, &end, 16);
if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
return;
- if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size,
- &crc_got, NULL) < 0)
+ if (_zip_filerange_crc(za->zp, cdir->offset, cdir->size, &crc_got, NULL) < 0)
return;
if (crc_got == crc_should)
@@ -383,68 +398,32 @@ _zip_check_torrentzip(struct zip *za)
/* _zip_headercomp:
- compares two headers h1 and h2; if they are local headers, set
- local1p or local2p respectively to 1, else 0. Return 0 if they
- are identical, -1 if not. */
+ compares a central directory entry and a local file header
+ Return 0 if they are consistent, -1 if not. */
static int
-_zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
- int local2p)
+_zip_headercomp(const struct zip_dirent *central, const struct zip_dirent *local)
{
- if ((h1->version_needed != h2->version_needed)
+ if ((central->version_needed != local->version_needed)
#if 0
/* some zip-files have different values in local
and global headers for the bitflags */
- || (h1->bitflags != h2->bitflags)
+ || (central->bitflags != local->bitflags)
#endif
- || (h1->comp_method != h2->comp_method)
- || (h1->last_mod != h2->last_mod)
- || (h1->filename_len != h2->filename_len)
- || !h1->filename || !h2->filename
- || strcmp(h1->filename, h2->filename))
+ || (central->comp_method != local->comp_method)
+ || (central->last_mod != local->last_mod)
+ || !_zip_string_equal(central->filename, local->filename))
return -1;
- /* check that CRC and sizes are zero if data descriptor is used */
- if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p
- && (h1->crc != 0
- || h1->comp_size != 0
- || h1->uncomp_size != 0))
- return -1;
- if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p
- && (h2->crc != 0
- || h2->comp_size != 0
- || h2->uncomp_size != 0))
- return -1;
-
- /* check that CRC and sizes are equal if no data descriptor is used */
- if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0)
- && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) {
- if ((h1->crc != h2->crc)
- || (h1->comp_size != h2->comp_size)
- || (h1->uncomp_size != h2->uncomp_size))
+
+ if ((central->crc != local->crc) || (central->comp_size != local->comp_size)
+ || (central->uncomp_size != local->uncomp_size)) {
+ /* InfoZip stores valid values in local header even when data descriptor is used.
+ This is in violation of the appnote. */
+ if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0
+ || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0))
return -1;
}
-
- if ((local1p == local2p)
- && ((h1->extrafield_len != h2->extrafield_len)
- || (h1->extrafield_len && h2->extrafield
- && memcmp(h1->extrafield, h2->extrafield,
- h1->extrafield_len))))
- return -1;
-
- /* if either is local, nothing more to check */
- if (local1p || local2p)
- return 0;
-
- if ((h1->version_madeby != h2->version_madeby)
- || (h1->disk_number != h2->disk_number)
- || (h1->int_attrib != h2->int_attrib)
- || (h1->ext_attrib != h2->ext_attrib)
- || (h1->offset != h2->offset)
- || (h1->comment_len != h2->comment_len)
- || (h1->comment_len && h2->comment
- && memcmp(h1->comment, h2->comment, h1->comment_len)))
- return -1;
return 0;
}
@@ -452,7 +431,7 @@ _zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
static struct zip *
-_zip_allocate_new(const char *fn, int *zep)
+_zip_allocate_new(const char *fn, unsigned int flags, int *zep)
{
struct zip *za;
struct zip_error error;
@@ -467,18 +446,19 @@ _zip_allocate_new(const char *fn, int *zep)
else {
za->zn = strdup(fn);
if (!za->zn) {
- _zip_free(za);
+ zip_discard(za);
set_error(zep, NULL, ZIP_ER_MEMORY);
return NULL;
}
}
+ za->open_flags = flags;
return za;
}
static int
-_zip_file_exists(const char *fn, int flags, int *zep)
+_zip_file_exists(const char *fn, unsigned int flags, int *zep)
{
struct stat st;
@@ -488,7 +468,7 @@ _zip_file_exists(const char *fn, int flags, int *zep)
}
if (stat(fn, &st) != 0) {
- if (flags & ZIP_CREATE || flags & ZIP_OVERWRITE)
+ if (flags & ZIP_CREATE)
return 0;
else {
set_error(zep, NULL, ZIP_ER_OPEN);
@@ -508,14 +488,21 @@ _zip_file_exists(const char *fn, int flags, int *zep)
static struct zip_cdir *
-_zip_find_central_dir(FILE *fp, int flags, int *zep, off_t len)
+_zip_find_central_dir(FILE *fp, unsigned int flags, int *zep, off_t len)
{
struct zip_cdir *cdir, *cdirnew;
unsigned char *buf, *match;
off_t buf_offset;
- int a, best, buflen, i;
+ size_t buflen;
+ zip_int64_t a, i;
+ zip_int64_t best;
struct zip_error zerr;
+ if (len < (off_t)EOCDLEN) {
+ set_error(zep, NULL, ZIP_ER_NOZIP);
+ return NULL;
+ }
+
i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
if (i == -1 && errno != EFBIG) {
/* seek before start of file on my machine */
@@ -541,10 +528,10 @@ _zip_find_central_dir(FILE *fp, int flags, int *zep, off_t len)
best = -1;
cdir = NULL;
- match = buf;
+ match = buf+ (buflen < CDBUFSIZE ? 0 : EOCD64LOCLEN);
_zip_error_set(&zerr, ZIP_ER_NOZIP, 0);
- while ((match=_zip_memmem(match, buflen-(match-buf)-18,
+ while ((match=_zip_memmem(match, buflen-(size_t)(match-buf)-(EOCDLEN-4),
(const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
/* found match -- check, if good */
/* to avoid finding the same match all over again */
@@ -589,8 +576,7 @@ _zip_find_central_dir(FILE *fp, int flags, int *zep, off_t len)
static unsigned char *
-_zip_memmem(const unsigned char *big, int biglen, const unsigned char *little,
- int littlelen)
+_zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen)
{
const unsigned char *p;
@@ -598,11 +584,159 @@ _zip_memmem(const unsigned char *big, int biglen, const unsigned char *little,
return NULL;
p = big-1;
while ((p=(const unsigned char *)
- memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1)))
- != NULL) {
+ memchr(p+1, little[0], (size_t)(big-(p+1))+(size_t)(biglen-littlelen)+1)) != NULL) {
if (memcmp(p+1, little+1, littlelen-1)==0)
return (unsigned char *)p;
}
return NULL;
}
+
+
+
+static struct zip_cdir *
+_zip_read_eocd(const unsigned char *eocd, const unsigned char *buf, off_t buf_offset, size_t buflen,
+ unsigned int flags, struct zip_error *error)
+{
+ struct zip_cdir *cd;
+ const unsigned char *cdp;
+ zip_uint64_t i, nentry, size, offset;
+
+ if (eocd+EOCDLEN > buf+buflen) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
+ cdp = eocd + 8;
+
+ /* number of cdir-entries on this disk */
+ i = _zip_read2(&cdp);
+ /* number of cdir-entries */
+ nentry = _zip_read2(&cdp);
+
+ if (nentry != i) {
+ _zip_error_set(error, ZIP_ER_NOZIP, 0);
+ return NULL;
+ }
+
+ size = _zip_read4(&cdp);
+ offset = _zip_read4(&cdp);
+
+ if (size > ZIP_OFF_MAX || offset > ZIP_OFF_MAX || offset+size > ZIP_OFF_MAX) {
+ _zip_error_set(error, ZIP_ER_SEEK, EFBIG);
+ return NULL;
+ }
+
+ if (offset+size > (zip_uint64_t)(buf_offset + (eocd-buf))) {
+ /* cdir spans past EOCD record */
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
+ if ((flags & ZIP_CHECKCONS) && offset+size != (zip_uint64_t)(buf_offset + (eocd-buf))) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
+ if ((cd=_zip_cdir_new(nentry, error)) == NULL)
+ return NULL;
+
+ cd->size = (off_t)size;
+ cd->offset = (off_t)offset;
+
+ return cd;
+}
+
+
+
+static struct zip_cdir *
+_zip_read_eocd64(FILE *f, const zip_uint8_t *eocd64loc, const zip_uint8_t *buf,
+ off_t buf_offset, size_t buflen, unsigned int flags, struct zip_error *error)
+{
+ struct zip_cdir *cd;
+ zip_uint64_t offset;
+ const zip_uint8_t *cdp;
+ zip_uint8_t eocd[EOCD64LEN];
+ zip_uint64_t eocd_offset;
+ zip_uint64_t size, nentry, i;
+
+ cdp = eocd64loc+8;
+ eocd_offset = _zip_read8(&cdp);
+
+ if (eocd_offset > ZIP_OFF_MAX || eocd_offset + EOCD64LEN > ZIP_OFF_MAX) {
+ _zip_error_set(error, ZIP_ER_SEEK, EFBIG);
+ return NULL;
+ }
+
+ if (eocd64loc < buf || (off_t)eocd_offset+EOCD64LEN > (buf_offset+(eocd64loc-buf))) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
+ if ((off_t)eocd_offset >= buf_offset && (off_t)eocd_offset+EOCD64LEN <= buf_offset+(ssize_t)buflen)
+ cdp = buf+((off_t)eocd_offset-buf_offset);
+ else {
+ if (fseeko(f, (off_t)eocd_offset, SEEK_SET) != 0) {
+ _zip_error_set(error, ZIP_ER_SEEK, errno);
+ return NULL;
+ }
+
+ clearerr(f);
+ if (fread(eocd, 1, EOCD64LEN, f) < EOCD64LEN) {
+ _zip_error_set(error, ZIP_ER_READ, errno);
+ return NULL;
+ }
+
+ if (ferror(f)) {
+ _zip_error_set(error, ZIP_ER_READ, errno);
+ return NULL;
+ }
+
+ cdp = eocd;
+ }
+
+ if (memcmp(cdp, EOCD64_MAGIC, 4) != 0) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+ cdp += 4;
+
+ size = _zip_read8(&cdp);
+
+ if ((flags & ZIP_CHECKCONS) && size+eocd_offset+12 != (zip_uint64_t)(buf_offset+(eocd64loc-buf))) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
+ cdp += 4; /* skip version made by/needed */
+ cdp += 8; /* skip num disks */
+
+ nentry = _zip_read8(&cdp);
+ i = _zip_read8(&cdp);
+
+ if (nentry != i) {
+ _zip_error_set(error, ZIP_ER_MULTIDISK, 0);
+ return NULL;
+ }
+
+ size = _zip_read8(&cdp);
+ offset = _zip_read8(&cdp);
+
+ if (size > ZIP_OFF_MAX || offset > ZIP_OFF_MAX || offset+size > ZIP_OFF_MAX) {
+ _zip_error_set(error, ZIP_ER_SEEK, EFBIG);
+ return NULL;
+ }
+ if ((flags & ZIP_CHECKCONS) && offset+size != eocd_offset) {
+ _zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
+ if ((cd=_zip_cdir_new(nentry, error)) == NULL)
+ return NULL;
+
+
+ cd->size = (off_t)size;
+ cd->offset = (off_t)offset;
+
+ return cd;
+}