Back to index

php5  5.3.10
zip_dirent.c
Go to the documentation of this file.
00001 /*
00002   zip_dirent.c -- read directory entry (local or central), clean dirent
00003   Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
00004 
00005   This file is part of libzip, a library to manipulate ZIP archives.
00006   The authors can be contacted at <libzip@nih.at>
00007 
00008   Redistribution and use in source and binary forms, with or without
00009   modification, are permitted provided that the following conditions
00010   are met:
00011   1. Redistributions of source code must retain the above copyright
00012      notice, this list of conditions and the following disclaimer.
00013   2. Redistributions in binary form must reproduce the above copyright
00014      notice, this list of conditions and the following disclaimer in
00015      the documentation and/or other materials provided with the
00016      distribution.
00017   3. The names of the authors may not be used to endorse or promote
00018      products derived from this software without specific prior
00019      written permission.
00020  
00021   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
00022   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
00025   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00027   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00029   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00030   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00031   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 */
00033 
00034 
00035 
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <errno.h>
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 
00043 #include "zipint.h"
00044 
00045 static time_t _zip_d2u_time(int, int);
00046 static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *);
00047 static char *_zip_readstr(unsigned char **, int, int, struct zip_error *);
00048 static void _zip_u2d_time(time_t, unsigned short *, unsigned short *);
00049 static void _zip_write2(unsigned short, FILE *);
00050 static void _zip_write4(unsigned int, FILE *);
00051 
00052 
00053 
00054 void
00055 _zip_cdir_free(struct zip_cdir *cd)
00056 {
00057     int i;
00058 
00059     if (!cd)
00060        return;
00061 
00062     for (i=0; i<cd->nentry; i++)
00063        _zip_dirent_finalize(cd->entry+i);
00064     free(cd->comment);
00065     free(cd->entry);
00066     free(cd);
00067 }
00068 
00069 
00070 
00071 int
00072 _zip_cdir_grow(struct zip_cdir *cd, int nentry, struct zip_error *error)
00073 {
00074     struct zip_dirent *entry;
00075 
00076     if (nentry < cd->nentry) {
00077        _zip_error_set(error, ZIP_ER_INTERNAL, 0);
00078        return -1;
00079     }
00080 
00081     if ((entry=((struct zip_dirent *)
00082               realloc(cd->entry, sizeof(*(cd->entry))*nentry))) == NULL) {
00083        _zip_error_set(error, ZIP_ER_MEMORY, 0);
00084        return -1;
00085     }
00086 
00087     cd->nentry = nentry;
00088     cd->entry = entry;
00089 
00090     return 0;
00091 }
00092 
00093 
00094 
00095 struct zip_cdir *
00096 _zip_cdir_new(int nentry, struct zip_error *error)
00097 {
00098     struct zip_cdir *cd;
00099     
00100     if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) {
00101        _zip_error_set(error, ZIP_ER_MEMORY, 0);
00102        return NULL;
00103     }
00104 
00105     if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry))
00106        == NULL) {
00107        _zip_error_set(error, ZIP_ER_MEMORY, 0);
00108        free(cd);
00109        return NULL;
00110     }
00111 
00112     /* entries must be initialized by caller */
00113 
00114     cd->nentry = nentry;
00115     cd->size = cd->offset = 0;
00116     cd->comment = NULL;
00117     cd->comment_len = 0;
00118 
00119     return cd;
00120 }
00121 
00122 
00123 
00124 int
00125 _zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error)
00126 {
00127     int i;
00128 
00129     cd->offset = ftello(fp);
00130 
00131     for (i=0; i<cd->nentry; i++) {
00132        if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0)
00133            return -1;
00134     }
00135 
00136     cd->size = ftello(fp) - cd->offset;
00137     
00138     /* clearerr(fp); */
00139     fwrite(EOCD_MAGIC, 1, 4, fp);
00140     _zip_write4(0, fp);
00141     _zip_write2((unsigned short)cd->nentry, fp);
00142     _zip_write2((unsigned short)cd->nentry, fp);
00143     _zip_write4(cd->size, fp);
00144     _zip_write4(cd->offset, fp);
00145     _zip_write2(cd->comment_len, fp);
00146     fwrite(cd->comment, 1, cd->comment_len, fp);
00147 
00148     if (ferror(fp)) {
00149        _zip_error_set(error, ZIP_ER_WRITE, errno);
00150        return -1;
00151     }
00152 
00153     return 0;
00154 }
00155 
00156 
00157 
00158 void
00159 _zip_dirent_finalize(struct zip_dirent *zde)
00160 {
00161     free(zde->filename);
00162     zde->filename = NULL;
00163     free(zde->extrafield);
00164     zde->extrafield = NULL;
00165     free(zde->comment);
00166     zde->comment = NULL;
00167 }
00168 
00169 
00170 
00171 void
00172 _zip_dirent_init(struct zip_dirent *de)
00173 {
00174     de->version_madeby = 0;
00175     de->version_needed = 20; /* 2.0 */
00176     de->bitflags = 0;
00177     de->comp_method = 0;
00178     de->last_mod = 0;
00179     de->crc = 0;
00180     de->comp_size = 0;
00181     de->uncomp_size = 0;
00182     de->filename = NULL;
00183     de->filename_len = 0;
00184     de->extrafield = NULL;
00185     de->extrafield_len = 0;
00186     de->comment = NULL;
00187     de->comment_len = 0;
00188     de->disk_number = 0;
00189     de->int_attrib = 0;
00190     de->ext_attrib = 0;
00191     de->offset = 0;
00192 }
00193 
00194 
00195 
00196 /* _zip_dirent_read(zde, fp, bufp, left, localp, error):
00197    Fills the zip directory entry zde.
00198 
00199    If bufp is non-NULL, data is taken from there and bufp is advanced
00200    by the amount of data used; otherwise data is read from fp as needed.
00201    
00202    if leftp is non-NULL, no more bytes than specified by it are used,
00203    and *leftp is reduced by the number of bytes used.
00204 
00205    If local != 0, it reads a local header instead of a central
00206    directory entry.
00207 
00208    Returns 0 if successful. On error, error is filled in and -1 is
00209    returned.
00210 
00211    XXX: leftp and file position undefined on error.
00212 */
00213 
00214 int
00215 _zip_dirent_read(struct zip_dirent *zde, FILE *fp,
00216                unsigned char **bufp, unsigned int *leftp, int local,
00217                struct zip_error *error)
00218 {
00219     unsigned char buf[CDENTRYSIZE];
00220     unsigned char *cur;
00221     unsigned short dostime, dosdate;
00222     unsigned int size;
00223 
00224     if (local)
00225        size = LENTRYSIZE;
00226     else
00227        size = CDENTRYSIZE;
00228 
00229     if (leftp && (*leftp < size)) {
00230        _zip_error_set(error, ZIP_ER_NOZIP, 0);
00231        return -1;
00232     }
00233 
00234     if (bufp) {
00235        /* use data from buffer */
00236        cur = *bufp;
00237     }
00238     else {
00239        /* read entry from disk */
00240        if ((fread(buf, 1, size, fp)<size)) {
00241            _zip_error_set(error, ZIP_ER_READ, errno);
00242            return -1;
00243        }
00244        cur = buf;
00245     }
00246 
00247     if (memcmp(cur, (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {
00248        _zip_error_set(error, ZIP_ER_NOZIP, 0);
00249        return -1;
00250     }
00251     cur += 4;
00252 
00253     
00254     /* convert buffercontents to zip_dirent */
00255     
00256     if (!local)
00257        zde->version_madeby = _zip_read2(&cur);
00258     else
00259        zde->version_madeby = 0;
00260     zde->version_needed = _zip_read2(&cur);
00261     zde->bitflags = _zip_read2(&cur);
00262     zde->comp_method = _zip_read2(&cur);
00263     
00264     /* convert to time_t */
00265     dostime = _zip_read2(&cur);
00266     dosdate = _zip_read2(&cur);
00267     zde->last_mod = _zip_d2u_time(dostime, dosdate);
00268     
00269     zde->crc = _zip_read4(&cur);
00270     zde->comp_size = _zip_read4(&cur);
00271     zde->uncomp_size = _zip_read4(&cur);
00272     
00273     zde->filename_len = _zip_read2(&cur);
00274     zde->extrafield_len = _zip_read2(&cur);
00275     
00276     if (local) {
00277        zde->comment_len = 0;
00278        zde->disk_number = 0;
00279        zde->int_attrib = 0;
00280        zde->ext_attrib = 0;
00281        zde->offset = 0;
00282     } else {
00283        zde->comment_len = _zip_read2(&cur);
00284        zde->disk_number = _zip_read2(&cur);
00285        zde->int_attrib = _zip_read2(&cur);
00286        zde->ext_attrib = _zip_read4(&cur);
00287        zde->offset = _zip_read4(&cur);
00288     }
00289 
00290     zde->filename = NULL;
00291     zde->extrafield = NULL;
00292     zde->comment = NULL;
00293 
00294     size += zde->filename_len+zde->extrafield_len+zde->comment_len;
00295 
00296     if (leftp && (*leftp < size)) {
00297        _zip_error_set(error, ZIP_ER_NOZIP, 0);
00298        return -1;
00299     }
00300 
00301     if (bufp) {
00302        if (zde->filename_len) {
00303            zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error);
00304            if (!zde->filename)
00305                   return -1;
00306        }
00307 
00308        if (zde->extrafield_len) {
00309            zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0,
00310                                       error);
00311            if (!zde->extrafield)
00312               return -1;
00313        }
00314 
00315        if (zde->comment_len) {
00316            zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error);
00317            if (!zde->comment)
00318               return -1;
00319        }
00320     }
00321     else {
00322        if (zde->filename_len) {
00323            zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error);
00324            if (!zde->filename)
00325                   return -1;
00326        }
00327 
00328        if (zde->extrafield_len) {
00329            zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0,
00330                                         error);
00331            if (!zde->extrafield)
00332               return -1;
00333        }
00334 
00335        if (zde->comment_len) {
00336            zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error);
00337            if (!zde->comment)
00338               return -1;
00339        }
00340     }
00341 
00342     if (bufp)
00343       *bufp = cur;
00344     if (leftp)
00345        *leftp -= size;
00346 
00347     return 0;
00348 }
00349 
00350 
00351 
00352 /* _zip_dirent_torrent_normalize(de);
00353    Set values suitable for torrentzip.
00354 */
00355 
00356 void
00357 _zip_dirent_torrent_normalize(struct zip_dirent *de)
00358 {
00359     static struct tm torrenttime;
00360     static time_t last_mod = 0;
00361 
00362     if (last_mod == 0) {
00363 #ifdef HAVE_STRUCT_TM_TM_ZONE
00364        time_t now;
00365        struct tm *l;
00366 #endif
00367 
00368        torrenttime.tm_sec = 0;
00369        torrenttime.tm_min = 32;
00370        torrenttime.tm_hour = 23;
00371        torrenttime.tm_mday = 24;
00372        torrenttime.tm_mon = 11;
00373        torrenttime.tm_year = 96;
00374        torrenttime.tm_wday = 0;
00375        torrenttime.tm_yday = 0;
00376        torrenttime.tm_isdst = 0;
00377 
00378 #ifdef HAVE_STRUCT_TM_TM_ZONE
00379        time(&now);
00380        l = localtime(&now);
00381        torrenttime.tm_gmtoff = l->tm_gmtoff;
00382        torrenttime.tm_zone = l->tm_zone;
00383 #endif
00384 
00385        last_mod = mktime(&torrenttime);
00386     }
00387     
00388     de->version_madeby = 0;
00389     de->version_needed = 20; /* 2.0 */
00390     de->bitflags = 2; /* maximum compression */
00391     de->comp_method = ZIP_CM_DEFLATE;
00392     de->last_mod = last_mod;
00393 
00394     de->disk_number = 0;
00395     de->int_attrib = 0;
00396     de->ext_attrib = 0;
00397     de->offset = 0;
00398 
00399     free(de->extrafield);
00400     de->extrafield = NULL;
00401     de->extrafield_len = 0;
00402     free(de->comment);
00403     de->comment = NULL;
00404     de->comment_len = 0;
00405 }
00406 
00407 
00408 
00409 /* _zip_dirent_write(zde, fp, localp, error):
00410    Writes zip directory entry zde to file fp.
00411 
00412    If localp != 0, it writes a local header instead of a central
00413    directory entry.
00414 
00415    Returns 0 if successful. On error, error is filled in and -1 is
00416    returned.
00417 */
00418 
00419 int
00420 _zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp,
00421                 struct zip_error *error)
00422 {
00423     unsigned short dostime, dosdate;
00424 
00425     fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
00426 
00427     if (!localp)
00428        _zip_write2(zde->version_madeby, fp);
00429     _zip_write2(zde->version_needed, fp);
00430     _zip_write2(zde->bitflags, fp);
00431     _zip_write2(zde->comp_method, fp);
00432 
00433     _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
00434     _zip_write2(dostime, fp);
00435     _zip_write2(dosdate, fp);
00436     
00437     _zip_write4(zde->crc, fp);
00438     _zip_write4(zde->comp_size, fp);
00439     _zip_write4(zde->uncomp_size, fp);
00440     
00441     _zip_write2(zde->filename_len, fp);
00442     _zip_write2(zde->extrafield_len, fp);
00443     
00444     if (!localp) {
00445        _zip_write2(zde->comment_len, fp);
00446        _zip_write2(zde->disk_number, fp);
00447        _zip_write2(zde->int_attrib, fp);
00448        _zip_write4(zde->ext_attrib, fp);
00449        _zip_write4(zde->offset, fp);
00450     }
00451 
00452     if (zde->filename_len)
00453        fwrite(zde->filename, 1, zde->filename_len, fp);
00454 
00455     if (zde->extrafield_len)
00456        fwrite(zde->extrafield, 1, zde->extrafield_len, fp);
00457 
00458     if (!localp) {
00459        if (zde->comment_len)
00460            fwrite(zde->comment, 1, zde->comment_len, fp);
00461     }
00462 
00463     if (ferror(fp)) {
00464        _zip_error_set(error, ZIP_ER_WRITE, errno);
00465        return -1;
00466     }
00467 
00468     return 0;
00469 }
00470 
00471 
00472 
00473 static time_t
00474 _zip_d2u_time(int dtime, int ddate)
00475 {
00476     struct tm tm = {0};
00477 
00478     /* let mktime decide if DST is in effect */
00479     tm.tm_isdst = -1;
00480     
00481     tm.tm_year = ((ddate>>9)&127) + 1980 - 1900;
00482     tm.tm_mon = ((ddate>>5)&15) - 1;
00483     tm.tm_mday = ddate&31;
00484 
00485     tm.tm_hour = (dtime>>11)&31;
00486     tm.tm_min = (dtime>>5)&63;
00487     tm.tm_sec = (dtime<<1)&62;
00488 
00489     return mktime(&tm);
00490 }
00491 
00492 
00493 
00494 unsigned short
00495 _zip_read2(unsigned char **a)
00496 {
00497     unsigned short ret;
00498 
00499     ret = (*a)[0]+((*a)[1]<<8);
00500     *a += 2;
00501 
00502     return ret;
00503 }
00504 
00505 
00506 
00507 unsigned int
00508 _zip_read4(unsigned char **a)
00509 {
00510     unsigned int ret;
00511 
00512     ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0];
00513     *a += 4;
00514 
00515     return ret;
00516 }
00517 
00518 
00519 
00520 static char *
00521 _zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error)
00522 {
00523     char *r, *o;
00524 
00525     r = (char *)malloc(nulp ? len+1 : len);
00526     if (!r) {
00527        _zip_error_set(error, ZIP_ER_MEMORY, 0);
00528        return NULL;
00529     }
00530 
00531     if (fread(r, 1, len, fp)<len) {
00532        free(r);
00533        _zip_error_set(error, ZIP_ER_READ, errno);
00534        return NULL;
00535     }
00536 
00537     if (nulp) {
00538        /* replace any in-string NUL characters with spaces */
00539        r[len] = 0;
00540        for (o=r; o<r+len; o++)
00541            if (*o == '\0')
00542               *o = ' ';
00543     }
00544     
00545     return r;
00546 }
00547 
00548 
00549 
00550 static char *
00551 _zip_readstr(unsigned char **buf, int len, int nulp, struct zip_error *error)
00552 {
00553     char *r, *o;
00554 
00555     r = (char *)malloc(nulp ? len+1 : len);
00556     if (!r) {
00557        _zip_error_set(error, ZIP_ER_MEMORY, 0);
00558        return NULL;
00559     }
00560     
00561     memcpy(r, *buf, len);
00562     *buf += len;
00563 
00564     if (nulp) {
00565        /* replace any in-string NUL characters with spaces */
00566        r[len] = 0;
00567        for (o=r; o<r+len; o++)
00568            if (*o == '\0')
00569               *o = ' ';
00570     }
00571 
00572     return r;
00573 }
00574 
00575 
00576 
00577 static void
00578 _zip_write2(unsigned short i, FILE *fp)
00579 {
00580     putc(i&0xff, fp);
00581     putc((i>>8)&0xff, fp);
00582 
00583     return;
00584 }
00585 
00586 
00587 
00588 static void
00589 _zip_write4(unsigned int i, FILE *fp)
00590 {
00591     putc(i&0xff, fp);
00592     putc((i>>8)&0xff, fp);
00593     putc((i>>16)&0xff, fp);
00594     putc((i>>24)&0xff, fp);
00595     
00596     return;
00597 }
00598 
00599 
00600 
00601 static void
00602 _zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate)
00603 {
00604     struct tm *tm;
00605 
00606     tm = localtime(&time);
00607     *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5)
00608        + tm->tm_mday;
00609     *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5)
00610        + ((tm->tm_sec)>>1);
00611 
00612     return;
00613 }