Annotation of embedaddon/php/ext/zip/lib/zip_open.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:   zip_open.c -- open zip archive
                      3:   Copyright (C) 1999-2009 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: 
                     36: #include <sys/stat.h>
                     37: #include <errno.h>
                     38: #include <limits.h>
                     39: #include <stdio.h>
                     40: #include <stdlib.h>
                     41: #include <string.h>
                     42: 
                     43: #include "zipint.h"
                     44: 
                     45: static void set_error(int *, struct zip_error *, int);
                     46: static struct zip *_zip_allocate_new(const char *, int *);
                     47: static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
                     48: static void _zip_check_torrentzip(struct zip *);
                     49: static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, off_t);
                     50: static int _zip_file_exists(const char *, int, int *);
                     51: static int _zip_headercomp(struct zip_dirent *, int,
                     52:                           struct zip_dirent *, int);
                     53: static unsigned char *_zip_memmem(const unsigned char *, int,
                     54:                                  const unsigned char *, int);
                     55: static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *,
                     56:                                 int, int, struct zip_error *);
                     57: 
                     58: 
                     59: 
                     60: ZIP_EXTERN(struct zip *)
                     61: zip_open(const char *fn, int flags, int *zep)
                     62: {
                     63:     FILE *fp;
                     64:     struct zip *za;
                     65:     struct zip_cdir *cdir;
                     66:     int i;
                     67:     off_t len;
                     68: 
                     69:     if (flags & ZIP_OVERWRITE) {
                     70:        return _zip_allocate_new(fn, zep);
                     71:     }
                     72: 
                     73:     switch (_zip_file_exists(fn, flags, zep)) {
                     74:     case -1:
                     75:                        if (!(flags & ZIP_OVERWRITE)) {
                     76:                                return NULL;
                     77:                        }
                     78: 
                     79:     case 0:
                     80:        return _zip_allocate_new(fn, zep);
                     81: 
                     82:     default:
                     83:        break;
                     84:     }
                     85: 
                     86:     if ((fp=fopen(fn, "rb")) == NULL) {
                     87:        set_error(zep, NULL, ZIP_ER_OPEN);
                     88:        return NULL;
                     89:     }
                     90: 
                     91:     fseeko(fp, 0, SEEK_END);
                     92:     len = ftello(fp);
                     93: 
                     94:     /* treat empty files as empty archives */
                     95:     if (len == 0) {
                     96:        if ((za=_zip_allocate_new(fn, zep)) == NULL)
                     97:            fclose(fp);
                     98:        else
                     99:            za->zp = fp;
                    100:        return za;
                    101:     }
                    102: 
                    103:     cdir = _zip_find_central_dir(fp, flags, zep, len);
                    104:     if (cdir == NULL) {
                    105:        fclose(fp);
                    106:        return NULL;
                    107:     }
                    108: 
                    109:     if ((za=_zip_allocate_new(fn, zep)) == NULL) {
                    110:        _zip_cdir_free(cdir);
                    111:        fclose(fp);
                    112:        return NULL;
                    113:     }
                    114: 
                    115:     za->cdir = cdir;
                    116:     za->zp = fp;
                    117: 
                    118:     if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
                    119:                                              * cdir->nentry)) == NULL) {
                    120:        set_error(zep, NULL, ZIP_ER_MEMORY);
                    121:        _zip_free(za);
                    122:        return NULL;
                    123:     }
                    124:     for (i=0; i<cdir->nentry; i++)
                    125:        _zip_entry_new(za);
                    126: 
                    127:     _zip_check_torrentzip(za);
                    128:     za->ch_flags = za->flags;
                    129: 
                    130:     return za;
                    131: }
                    132: 
                    133: 
                    134: 
                    135: static void
                    136: set_error(int *zep, struct zip_error *err, int ze)
                    137: {
                    138:     int se;
                    139: 
                    140:     if (err) {
                    141:        _zip_error_get(err, &ze, &se);
                    142:        if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
                    143:            errno = se;
                    144:     }
                    145: 
                    146:     if (zep)
                    147:        *zep = ze;
                    148: }
                    149: 
                    150: 
                    151: 
                    152: /* _zip_readcdir:
                    153:    tries to find a valid end-of-central-directory at the beginning of
                    154:    buf, and then the corresponding central directory entries.
                    155:    Returns a struct zip_cdir which contains the central directory 
                    156:    entries, or NULL if unsuccessful. */
                    157: 
                    158: static struct zip_cdir *
                    159: _zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen,
                    160:              int flags, struct zip_error *error)
                    161: {
                    162:     struct zip_cdir *cd;
                    163:     unsigned char *cdp, **bufp;
                    164:     int i, comlen, nentry;
                    165:     unsigned int left;
                    166: 
                    167:     comlen = buf + buflen - eocd - EOCDLEN;
                    168:     if (comlen < 0) {
                    169:        /* not enough bytes left for comment */
                    170:        _zip_error_set(error, ZIP_ER_NOZIP, 0);
                    171:        return NULL;
                    172:     }
                    173: 
                    174:     /* check for end-of-central-dir magic */
                    175:     if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
                    176:        _zip_error_set(error, ZIP_ER_NOZIP, 0);
                    177:        return NULL;
                    178:     }
                    179: 
                    180:     if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
                    181:        _zip_error_set(error, ZIP_ER_MULTIDISK, 0);
                    182:        return NULL;
                    183:     }
                    184: 
                    185:     cdp = eocd + 8;
                    186:     /* number of cdir-entries on this disk */
                    187:     i = _zip_read2(&cdp);
                    188:     /* number of cdir-entries */
                    189:     nentry = _zip_read2(&cdp);
                    190: 
                    191:     if ((cd=_zip_cdir_new(nentry, error)) == NULL)
                    192:        return NULL;
                    193: 
                    194:     cd->size = _zip_read4(&cdp);
                    195:     cd->offset = _zip_read4(&cdp);
                    196:     cd->comment = NULL;
                    197:     cd->comment_len = _zip_read2(&cdp);
                    198: 
                    199:     if ((comlen < cd->comment_len) || (cd->nentry != i)) {
                    200:        _zip_error_set(error, ZIP_ER_NOZIP, 0);
                    201:        free(cd);
                    202:        return NULL;
                    203:     }
                    204:     if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) {
                    205:        _zip_error_set(error, ZIP_ER_INCONS, 0);
                    206:        free(cd);
                    207:        return NULL;
                    208:     }
                    209: 
                    210:     if (cd->comment_len) {
                    211:        if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN,
                    212:                                             cd->comment_len, error))
                    213:            == NULL) {
                    214:            free(cd);
                    215:            return NULL;
                    216:        }
                    217:     }
                    218: 
                    219:     if (cd->size < (unsigned int)(eocd-buf)) {
                    220:        /* if buffer already read in, use it */
                    221:        cdp = eocd - cd->size;
                    222:        bufp = &cdp;
                    223:     }
                    224:     else {
                    225:        /* go to start of cdir and read it entry by entry */
                    226:        bufp = NULL;
                    227:        clearerr(fp);
                    228:        fseeko(fp, cd->offset, SEEK_SET);
                    229:        /* possible consistency check: cd->offset =
                    230:           len-(cd->size+cd->comment_len+EOCDLEN) ? */
                    231:        if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) {
                    232:            /* seek error or offset of cdir wrong */
                    233:            if (ferror(fp))
                    234:                _zip_error_set(error, ZIP_ER_SEEK, errno);
                    235:            else
                    236:                _zip_error_set(error, ZIP_ER_NOZIP, 0);
                    237:            free(cd);
                    238:            return NULL;
                    239:        }
                    240:     }
                    241: 
                    242:     left = cd->size;
                    243:     i=0;
                    244:     do {
                    245:        if (i == cd->nentry && left > 0) {
                    246:            /* Infozip extension for more than 64k entries:
                    247:               nentries wraps around, size indicates correct EOCD */
                    248:            _zip_cdir_grow(cd, cd->nentry+0x10000, error);
                    249:        }
                    250: 
                    251:        if ((_zip_dirent_read(cd->entry+i, fp, bufp, &left, 0, error)) < 0) {
                    252:            cd->nentry = i;
                    253:            _zip_cdir_free(cd);
                    254:            return NULL;
                    255:        }
                    256:        i++;
                    257:        
                    258:     } while (i<cd->nentry);
                    259:     
                    260:     return cd;
                    261: }
                    262: 
                    263: 
                    264: 
                    265: /* _zip_checkcons:
                    266:    Checks the consistency of the central directory by comparing central
                    267:    directory entries with local headers and checking for plausible
                    268:    file and header offsets. Returns -1 if not plausible, else the
                    269:    difference between the lowest and the highest fileposition reached */
                    270: 
                    271: static int
                    272: _zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
                    273: {
                    274:     int i;
                    275:     unsigned int min, max, j;
                    276:     struct zip_dirent temp;
                    277: 
                    278:     if (cd->nentry) {
                    279:        max = cd->entry[0].offset;
                    280:        min = cd->entry[0].offset;
                    281:     }
                    282:     else
                    283:        min = max = 0;
                    284: 
                    285:     for (i=0; i<cd->nentry; i++) {
                    286:        if (cd->entry[i].offset < min)
                    287:            min = cd->entry[i].offset;
                    288:        if (min > cd->offset) {
                    289:            _zip_error_set(error, ZIP_ER_NOZIP, 0);
                    290:            return -1;
                    291:        }
                    292:        
                    293:        j = cd->entry[i].offset + cd->entry[i].comp_size
                    294:            + cd->entry[i].filename_len + LENTRYSIZE;
                    295:        if (j > max)
                    296:            max = j;
                    297:        if (max > cd->offset) {
                    298:            _zip_error_set(error, ZIP_ER_NOZIP, 0);
                    299:            return -1;
                    300:        }
                    301:        
                    302:        if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) {
                    303:            _zip_error_set(error, ZIP_ER_SEEK, 0);
                    304:            return -1;
                    305:        }
                    306:        
                    307:        if (_zip_dirent_read(&temp, fp, NULL, NULL, 1, error) == -1)
                    308:            return -1;
                    309:        
                    310:        if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) {
                    311:            _zip_error_set(error, ZIP_ER_INCONS, 0);
                    312:            _zip_dirent_finalize(&temp);
                    313:            return -1;
                    314:        }
                    315:        _zip_dirent_finalize(&temp);
                    316:     }
                    317: 
                    318:     return max - min;
                    319: }
                    320: 
                    321: 
                    322: 
                    323: /* _zip_check_torrentzip:
                    324:    check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
                    325: 
                    326: static void
                    327: _zip_check_torrentzip(struct zip *za)
                    328: {
                    329:     uLong crc_got, crc_should;
                    330:     char buf[8+1];
                    331:     char *end;
                    332: 
                    333:     if (za->zp == NULL || za->cdir == NULL)
                    334:        return;
                    335: 
                    336:     if (za->cdir->comment_len != TORRENT_SIG_LEN+8
                    337:        || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
                    338:        return;
                    339:     
                    340:     memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8);
                    341:     buf[8] = '\0';
                    342:     errno = 0;
                    343:     crc_should = strtoul(buf, &end, 16);
                    344:     if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
                    345:        return;
                    346:     
                    347:     if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size,
                    348:                           &crc_got, NULL) < 0)
                    349:            return;
                    350: 
                    351:     if (crc_got == crc_should)
                    352:        za->flags |= ZIP_AFL_TORRENT;
                    353: }
                    354: 
                    355: 
                    356: 
                    357: 
                    358: /* _zip_headercomp:
                    359:    compares two headers h1 and h2; if they are local headers, set
                    360:    local1p or local2p respectively to 1, else 0. Return 0 if they
                    361:    are identical, -1 if not. */
                    362: 
                    363: static int
                    364: _zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
                    365:           int local2p)
                    366: {
                    367:     if ((h1->version_needed != h2->version_needed)
                    368: #if 0
                    369:        /* some zip-files have different values in local
                    370:           and global headers for the bitflags */
                    371:        || (h1->bitflags != h2->bitflags)
                    372: #endif
                    373:        || (h1->comp_method != h2->comp_method)
                    374:        || (h1->last_mod != h2->last_mod)
                    375:        || (h1->filename_len != h2->filename_len)
                    376:        || !h1->filename || !h2->filename
                    377:        || strcmp(h1->filename, h2->filename))
                    378:        return -1;
                    379: 
                    380:     /* check that CRC and sizes are zero if data descriptor is used */
                    381:     if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p
                    382:        && (h1->crc != 0
                    383:            || h1->comp_size != 0
                    384:            || h1->uncomp_size != 0))
                    385:        return -1;
                    386:     if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p
                    387:        && (h2->crc != 0
                    388:            || h2->comp_size != 0
                    389:            || h2->uncomp_size != 0))
                    390:        return -1;
                    391:     
                    392:     /* check that CRC and sizes are equal if no data descriptor is used */
                    393:     if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0)
                    394:        && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) {
                    395:        if ((h1->crc != h2->crc)
                    396:            || (h1->comp_size != h2->comp_size)
                    397:            || (h1->uncomp_size != h2->uncomp_size))
                    398:            return -1;
                    399:     }
                    400:     
                    401:     if ((local1p == local2p)
                    402:        && ((h1->extrafield_len != h2->extrafield_len)
                    403:            || (h1->extrafield_len && h2->extrafield
                    404:                && memcmp(h1->extrafield, h2->extrafield,
                    405:                          h1->extrafield_len))))
                    406:        return -1;
                    407: 
                    408:     /* if either is local, nothing more to check */
                    409:     if (local1p || local2p)
                    410:        return 0;
                    411: 
                    412:     if ((h1->version_madeby != h2->version_madeby)
                    413:        || (h1->disk_number != h2->disk_number)
                    414:        || (h1->int_attrib != h2->int_attrib)
                    415:        || (h1->ext_attrib != h2->ext_attrib)
                    416:        || (h1->offset != h2->offset)
                    417:        || (h1->comment_len != h2->comment_len)
                    418:        || (h1->comment_len && h2->comment
                    419:            && memcmp(h1->comment, h2->comment, h1->comment_len)))
                    420:        return -1;
                    421: 
                    422:     return 0;
                    423: }
                    424: 
                    425: 
                    426: 
                    427: static struct zip *
                    428: _zip_allocate_new(const char *fn, int *zep)
                    429: {
                    430:     struct zip *za;
                    431:     struct zip_error error;
                    432: 
                    433:     if ((za=_zip_new(&error)) == NULL) {
                    434:        set_error(zep, &error, 0);
                    435:        return NULL;
                    436:     }
                    437:        
                    438:     za->zn = strdup(fn);
                    439:     if (!za->zn) {
                    440:        _zip_free(za);
                    441:        set_error(zep, NULL, ZIP_ER_MEMORY);
                    442:        return NULL;
                    443:     }
                    444:     return za;
                    445: }
                    446: 
                    447: 
                    448: 
                    449: static int
                    450: _zip_file_exists(const char *fn, int flags, int *zep)
                    451: {
                    452:     struct stat st;
                    453: 
                    454:     if (fn == NULL) {
                    455:        set_error(zep, NULL, ZIP_ER_INVAL);
                    456:        return -1;
                    457:     }
                    458:     
                    459:     if (stat(fn, &st) != 0) {
                    460:        if (flags & ZIP_CREATE || flags & ZIP_OVERWRITE)
                    461:            return 0;
                    462:        else {
                    463:            set_error(zep, NULL, ZIP_ER_OPEN);
                    464:            return -1;
                    465:        }
                    466:     }
                    467:     else if ((flags & ZIP_EXCL)) {
                    468:        set_error(zep, NULL, ZIP_ER_EXISTS);
                    469:        return -1;
                    470:     }
                    471:     /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
                    472:        just like open() */
                    473: 
                    474:     return 1;
                    475: }
                    476: 
                    477: 
                    478: 
                    479: static struct zip_cdir *
                    480: _zip_find_central_dir(FILE *fp, int flags, int *zep, off_t len)
                    481: {
                    482:     struct zip_cdir *cdir, *cdirnew;
                    483:     unsigned char *buf, *match;
                    484:     int a, best, buflen, i;
                    485:     struct zip_error zerr;
                    486: 
                    487:     i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
                    488:     if (i == -1 && errno != EFBIG) {
                    489:        /* seek before start of file on my machine */
                    490:        set_error(zep, NULL, ZIP_ER_SEEK);
                    491:        return NULL;
                    492:     }
                    493: 
                    494:     /* 64k is too much for stack */
                    495:     if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) {
                    496:        set_error(zep, NULL, ZIP_ER_MEMORY);
                    497:        return NULL;
                    498:     }
                    499: 
                    500:     clearerr(fp);
                    501:     buflen = fread(buf, 1, CDBUFSIZE, fp);
                    502: 
                    503:     if (ferror(fp)) {
                    504:        set_error(zep, NULL, ZIP_ER_READ);
                    505:        free(buf);
                    506:        return NULL;
                    507:     }
                    508:     
                    509:     best = -1;
                    510:     cdir = NULL;
                    511:     match = buf;
                    512:     _zip_error_set(&zerr, ZIP_ER_NOZIP, 0);
                    513: 
                    514:     while ((match=_zip_memmem(match, buflen-(match-buf)-18,
                    515:                              (const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
                    516:        /* found match -- check, if good */
                    517:        /* to avoid finding the same match all over again */
                    518:        match++;
                    519:        if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags,
                    520:                                   &zerr)) == NULL)
                    521:            continue;
                    522: 
                    523:        if (cdir) {
                    524:            if (best <= 0)
                    525:                best = _zip_checkcons(fp, cdir, &zerr);
                    526:            a = _zip_checkcons(fp, cdirnew, &zerr);
                    527:            if (best < a) {
                    528:                _zip_cdir_free(cdir);
                    529:                cdir = cdirnew;
                    530:                best = a;
                    531:            }
                    532:            else
                    533:                _zip_cdir_free(cdirnew);
                    534:        }
                    535:        else {
                    536:            cdir = cdirnew;
                    537:            if (flags & ZIP_CHECKCONS)
                    538:                best = _zip_checkcons(fp, cdir, &zerr);
                    539:            else
                    540:                best = 0;
                    541:        }
                    542:        cdirnew = NULL;
                    543:     }
                    544: 
                    545:     free(buf);
                    546:     
                    547:     if (best < 0) {
                    548:        set_error(zep, &zerr, 0);
                    549:        _zip_cdir_free(cdir);
                    550:        return NULL;
                    551:     }
                    552: 
                    553:     return cdir;
                    554: }
                    555: 
                    556: 
                    557: 
                    558: static unsigned char *
                    559: _zip_memmem(const unsigned char *big, int biglen, const unsigned char *little, 
                    560:        int littlelen)
                    561: {
                    562:     const unsigned char *p;
                    563:     
                    564:     if ((biglen < littlelen) || (littlelen == 0))
                    565:        return NULL;
                    566:     p = big-1;
                    567:     while ((p=(const unsigned char *)
                    568:                memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1)))
                    569:           != NULL) {
                    570:        if (memcmp(p+1, little+1, littlelen-1)==0)
                    571:            return (unsigned char *)p;
                    572:     }
                    573: 
                    574:     return NULL;
                    575: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>