Back to index

php5  5.3.10
Functions
zip_open.c File Reference
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zipint.h"

Go to the source code of this file.

Functions

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 *, unsigned char *, unsigned char *, int, int, struct zip_error *)
 zip_open (const char *fn, int flags, int *zep)

Function Documentation

static struct zip * _zip_allocate_new ( const char *  fn,
int zep 
) [static, read]

Definition at line 428 of file zip_open.c.

{
    struct zip *za;
    struct zip_error error;

    if ((za=_zip_new(&error)) == NULL) {
       set_error(zep, &error, 0);
       return NULL;
    }
       
    za->zn = strdup(fn);
    if (!za->zn) {
       _zip_free(za);
       set_error(zep, NULL, ZIP_ER_MEMORY);
       return NULL;
    }
    return za;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _zip_check_torrentzip ( struct zip za) [static]

Definition at line 327 of file zip_open.c.

{
    uLong crc_got, crc_should;
    char buf[8+1];
    char *end;

    if (za->zp == NULL || za->cdir == NULL)
       return;

    if (za->cdir->comment_len != TORRENT_SIG_LEN+8
       || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
       return;
    
    memcpy(buf, za->cdir->comment+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)
           return;

    if (crc_got == crc_should)
       za->flags |= ZIP_AFL_TORRENT;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int _zip_checkcons ( FILE *  fp,
struct zip_cdir cd,
struct zip_error error 
) [static]

Definition at line 272 of file zip_open.c.

{
    int i;
    unsigned int min, max, j;
    struct zip_dirent temp;

    if (cd->nentry) {
       max = cd->entry[0].offset;
       min = cd->entry[0].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) {
           _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;
       if (j > max)
           max = j;
       if (max > 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);
           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) {
           _zip_error_set(error, ZIP_ER_INCONS, 0);
           _zip_dirent_finalize(&temp);
           return -1;
       }
       _zip_dirent_finalize(&temp);
    }

    return max - min;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int _zip_file_exists ( const char *  fn,
int  flags,
int zep 
) [static]

Definition at line 450 of file zip_open.c.

{
    struct stat st;

    if (fn == NULL) {
       set_error(zep, NULL, ZIP_ER_INVAL);
       return -1;
    }
    
    if (stat(fn, &st) != 0) {
       if (flags & ZIP_CREATE || flags & ZIP_OVERWRITE)
           return 0;
       else {
           set_error(zep, NULL, ZIP_ER_OPEN);
           return -1;
       }
    }
    else if ((flags & ZIP_EXCL)) {
       set_error(zep, NULL, ZIP_ER_EXISTS);
       return -1;
    }
    /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
       just like open() */

    return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct zip_cdir * _zip_find_central_dir ( FILE *  fp,
int  flags,
int zep,
off_t  len 
) [static, read]

Definition at line 480 of file zip_open.c.

{
    struct zip_cdir *cdir, *cdirnew;
    unsigned char *buf, *match;
    int a, best, buflen, i;
    struct zip_error zerr;

    i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
    if (i == -1 && errno != EFBIG) {
       /* seek before start of file on my machine */
       set_error(zep, NULL, ZIP_ER_SEEK);
       return NULL;
    }

    /* 64k is too much for stack */
    if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) {
       set_error(zep, NULL, ZIP_ER_MEMORY);
       return NULL;
    }

    clearerr(fp);
    buflen = fread(buf, 1, CDBUFSIZE, fp);

    if (ferror(fp)) {
       set_error(zep, NULL, ZIP_ER_READ);
       free(buf);
       return NULL;
    }
    
    best = -1;
    cdir = NULL;
    match = buf;
    _zip_error_set(&zerr, ZIP_ER_NOZIP, 0);

    while ((match=_zip_memmem(match, buflen-(match-buf)-18,
                           (const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
       /* found match -- check, if good */
       /* to avoid finding the same match all over again */
       match++;
       if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags,
                               &zerr)) == NULL)
           continue;

       if (cdir) {
           if (best <= 0)
              best = _zip_checkcons(fp, cdir, &zerr);
           a = _zip_checkcons(fp, cdirnew, &zerr);
           if (best < a) {
              _zip_cdir_free(cdir);
              cdir = cdirnew;
              best = a;
           }
           else
              _zip_cdir_free(cdirnew);
       }
       else {
           cdir = cdirnew;
           if (flags & ZIP_CHECKCONS)
              best = _zip_checkcons(fp, cdir, &zerr);
           else
              best = 0;
       }
       cdirnew = NULL;
    }

    free(buf);
    
    if (best < 0) {
       set_error(zep, &zerr, 0);
       _zip_cdir_free(cdir);
       return NULL;
    }

    return cdir;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int _zip_headercomp ( struct zip_dirent h1,
int  local1p,
struct zip_dirent h2,
int  local2p 
) [static]

Definition at line 364 of file zip_open.c.

{
    if ((h1->version_needed != h2->version_needed)
#if 0
       /* some zip-files have different values in local
          and global headers for the bitflags */
       || (h1->bitflags != h2->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))
       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))
           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;
}

Here is the caller graph for this function:

static unsigned char * _zip_memmem ( const unsigned char *  big,
int  biglen,
const unsigned char *  little,
int  littlelen 
) [static]

Definition at line 559 of file zip_open.c.

{
    const unsigned char *p;
    
    if ((biglen < littlelen) || (littlelen == 0))
       return NULL;
    p = big-1;
    while ((p=(const unsigned char *)
               memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1)))
          != NULL) {
       if (memcmp(p+1, little+1, littlelen-1)==0)
           return (unsigned char *)p;
    }

    return NULL;
}

Here is the caller graph for this function:

static struct zip_cdir * _zip_readcdir ( FILE *  fp,
unsigned char *  buf,
unsigned char *  eocd,
int  buflen,
int  flags,
struct zip_error error 
) [static, read]

Definition at line 159 of file zip_open.c.

{
    struct zip_cdir *cd;
    unsigned char *cdp, **bufp;
    int i, comlen, nentry;
    unsigned int left;

    comlen = buf + buflen - eocd - EOCDLEN;
    if (comlen < 0) {
       /* not enough bytes left for comment */
       _zip_error_set(error, ZIP_ER_NOZIP, 0);
       return NULL;
    }

    /* check for end-of-central-dir magic */
    if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
       _zip_error_set(error, ZIP_ER_NOZIP, 0);
       return NULL;
    }

    if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
       _zip_error_set(error, ZIP_ER_MULTIDISK, 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 ((cd=_zip_cdir_new(nentry, error)) == NULL)
       return NULL;

    cd->size = _zip_read4(&cdp);
    cd->offset = _zip_read4(&cdp);
    cd->comment = NULL;
    cd->comment_len = _zip_read2(&cdp);

    if ((comlen < cd->comment_len) || (cd->nentry != i)) {
       _zip_error_set(error, ZIP_ER_NOZIP, 0);
       free(cd);
       return NULL;
    }
    if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) {
       _zip_error_set(error, ZIP_ER_INCONS, 0);
       free(cd);
       return NULL;
    }

    if (cd->comment_len) {
       if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN,
                                        cd->comment_len, error))
           == NULL) {
           free(cd);
           return NULL;
       }
    }

    if (cd->size < (unsigned int)(eocd-buf)) {
       /* if buffer already read in, use it */
       cdp = eocd - cd->size;
       bufp = &cdp;
    }
    else {
       /* go to start of cdir and read it entry by entry */
       bufp = NULL;
       clearerr(fp);
       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)) {
           /* 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);
           free(cd);
           return NULL;
       }
    }

    left = cd->size;
    i=0;
    do {
       if (i == cd->nentry && left > 0) {
           /* Infozip extension for more than 64k entries:
              nentries wraps around, size indicates correct EOCD */
           _zip_cdir_grow(cd, cd->nentry+0x10000, error);
       }

       if ((_zip_dirent_read(cd->entry+i, fp, bufp, &left, 0, error)) < 0) {
           cd->nentry = i;
           _zip_cdir_free(cd);
           return NULL;
       }
       i++;
       
    } while (i<cd->nentry);
    
    return cd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void set_error ( int zep,
struct zip_error err,
int  ze 
) [static]

Definition at line 136 of file zip_open.c.

{
    int se;

    if (err) {
       _zip_error_get(err, &ze, &se);
       if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
           errno = se;
    }

    if (zep)
       *zep = ze;
}

Here is the call graph for this function:

Here is the caller graph for this function:

zip_open ( const char *  fn,
int  flags,
int zep 
)

Definition at line 61 of file zip_open.c.

{
    FILE *fp;
    struct zip *za;
    struct zip_cdir *cdir;
    int i;
    off_t len;

    if (flags & ZIP_OVERWRITE) {
       return _zip_allocate_new(fn, zep);
    }

    switch (_zip_file_exists(fn, flags, zep)) {
    case -1:
                     if (!(flags & ZIP_OVERWRITE)) {
                            return NULL;
                     }

    case 0:
       return _zip_allocate_new(fn, zep);

    default:
       break;
    }

    if ((fp=fopen(fn, "rb")) == NULL) {
       set_error(zep, NULL, ZIP_ER_OPEN);
       return NULL;
    }

    fseeko(fp, 0, SEEK_END);
    len = ftello(fp);

    /* treat empty files as empty archives */
    if (len == 0) {
       if ((za=_zip_allocate_new(fn, zep)) == NULL)
           fclose(fp);
       else
           za->zp = fp;
       return za;
    }

    cdir = _zip_find_central_dir(fp, flags, zep, len);
    if (cdir == NULL) {
       fclose(fp);
       return NULL;
    }

    if ((za=_zip_allocate_new(fn, zep)) == NULL) {
       _zip_cdir_free(cdir);
       fclose(fp);
       return NULL;
    }

    za->cdir = cdir;
    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);
    za->ch_flags = za->flags;

    return za;
}

Here is the call graph for this function:

Here is the caller graph for this function: