libzip reorganization --HG-- branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..e20b4c9 --- /dev/null +++ b/lib/Makefile.am
@@ -0,0 +1,5 @@ +noinst_LIBRARIES=libzip.a +noinst_HEADERS=zip.h \ + zipint.h + +libzip_a_SOURCES=zip_open.c
diff --git a/lib/zip.h b/lib/zip.h new file mode 100644 index 0000000..6fa7feb --- /dev/null +++ b/lib/zip.h
@@ -0,0 +1,122 @@ +#ifndef _HAD_ZIP_H +#define _HAD_ZIP_H + +#include <sys/types.h> +#include <stdio.h> +#include <zlib.h> + +enum zip_state { Z_UNCHANGED, Z_DELETED, Z_REPLACED, Z_ADDED, Z_RENAMED }; + +/* flags for zip_open */ +#define ZIP_CREATE 1 +#define ZIP_EXCL 2 +#define ZIP_CHECKCONS 4 + +int zip_err; /* global variable for errors returned by the low-level + library */ + +/* 0 is no error */ +#define ZERR_MULTIDISK 1 +#define ZERR_RENAME 2 +#define ZERR_CLOSE 3 +#define ZERR_SEEK 4 +#define ZERR_READ 5 +#define ZERR_WRITE 6 +#define ZERR_CRC 7 +#define ZERR_ZIPCLOSED 8 +#define ZERR_FILEEXISTS 9 +#define ZERR_FILENEXISTS 10 +#define ZERR_OPEN 11 + +extern char *zip_err_str[]; + +/* zip file */ + +struct zf { + char *zn; + FILE *zp; + unsigned short comlen, changes; + unsigned int cd_size, cd_offset; + char *com; + int nentry, nentry_alloc; + struct zf_entry *entry; + int nfile, nfile_alloc; + struct zf_file **file; +}; + +/* file in zip file */ + +struct zf_file { + struct zf *zf; + char *name; + int flags; /* -1: eof, >0: error */ + + int method; + /* position within zip file (fread/fwrite) */ + long fpos; + /* no of bytes left to read */ + unsigned long bytes_left; + /* no of bytes of compressed data left */ + unsigned long cbytes_left; + /* crc so far */ + unsigned long crc, crc_orig; + + char *buffer; + z_stream *zstr; +}; + +/* entry in zip file directory */ + +struct zf_entry { + unsigned short version_made, version_need, bitflags, comp_meth, + lmtime, lmdate, fnlen, eflen, fcomlen, disknrstart, intatt; + unsigned int crc, comp_size, uncomp_size, extatt, local_offset; + enum zip_state state; + char *fn, *ef, *fcom; + char *fn_old; + /* only use one of the following three for supplying new data + listed in order of priority, if more than one is set */ + struct zf *ch_data_zf; + char *ch_data_buf; + FILE *ch_data_fp; + /* offset & len of new data in ch_data_fp or ch_data_buf */ + unsigned int ch_data_offset, ch_data_len; + /* if source is another zipfile, number of file in zipfile */ + unsigned int ch_data_zf_fileno; +}; + + + +/* opening/closing zip files */ + +struct zf *zip_open(char *fn, int checkp); +int zip_close(struct zf *zf); + +int zip_name_locate(struct zf *zf, char *fn, int case_sens); + +/* read access to files in zip file */ + +struct zf_file *zff_open(struct zf *zf, char *fn, int case_sens); +struct zf_file *zff_open_index(struct zf *zf, int fileno); +int zff_read(struct zf_file *zff, char *outbuf, int toread); +int zff_close(struct zf_file *zff); + +/* high level routines to modify zip file */ + +int zip_unchange(struct zf *zf, int idx); +int zip_rename(struct zf *zf, int idx, char *name); +int zip_add_file(struct zf *zf, char *name, FILE *file, int start, int len); +int zip_add_data(struct zf *zf, char *name, char *buf, int start, int len); +int zip_add_zip(struct zf *zf, char *name, struct zf *srczf, int srcidx, + int start, int len); +int zip_replace_file(struct zf *zf, int idx, char *name, FILE *file, + int start, int len); +int zip_replace_data(struct zf *zf, int idx, char *name, char *buf, + int start, int len); +int zip_replace_zip(struct zf *zf, int idx, char *name, + struct zf *srczf, int srcidx, int start, int len); + +int zip_delete(struct zf *zf, int idx); + + +#endif /* _HAD_ZIP_H */
diff --git a/lib/zip_close.c b/lib/zip_close.c new file mode 100644 index 0000000..48be564 --- /dev/null +++ b/lib/zip_close.c
@@ -0,0 +1,522 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> + +#include "zip.h" +#include "zipint.h" + +static int _zip_entry_copy(struct zf *dest, struct zf *src, + int entry_no, char *name); +static int _zip_entry_add(struct zf *dest, struct zf *src, int entry_no); +static int writecdir(struct zf *zfp) +static void write2(FILE *fp, int i); +static void write4(FILE *fp, int i); +static void writestr(FILE *fp, char *str, int len); +static int writecdentry(FILE *fp, struct zf_entry *zfe, int localp); +static int _zip_create_entry(struct zf *dest, struct zf_entry *src_entry, + char *name); + + + +/* zip_close: + Tries to commit all changes and close the zipfile; if it fails, + zip_err (and errno) are set and *zf is unchanged, except for + problems in zf_free. */ + +int +zip_close(struct zf *zf) +{ + int i, count, tfd; + char *temp; + FILE *tfp; + struct zf *tzf; + + if (zf->changes == 0) + return zf_free(zf); + + /* look if there really are any changes */ + count = 0; + for (i=0; i<zf->nentry; i++) { + if (zf->entry[i].state != Z_UNCHANGED) { + count = 1; + break; + } + } + + /* no changes, all has been unchanged */ + if (count == 0) + return zf_free(zf); + + temp = (char *)xmalloc(strlen(zf->zn)+8); + sprintf(temp, "%s.XXXXXX", zf->zn); + + tfd = mkstemp(temp); + + if ((tfp=fdopen(tfd, "r+b")) == NULL) { + free(temp); + close(tfd); + return -1; + } + + tzf = zf_new(); + tzf->zp = tfp; + tzf->zn = temp; + tzf->nentry = 0; + tzf->comlen = zf->comlen; + tzf->cd_size = tzf->cd_offset = 0; + tzf->com = (unsigned char *)memdup(zf->com, zf->comlen); + tzf->entry = (struct zf_entry *)xmalloc(sizeof(struct + zf_entry)*ALLOC_SIZE); + tzf->nentry_alloc = ALLOC_SIZE; + + count = 0; + if (zf->entry) { + for (i=0; i<zf->nentry; i++) { + switch (zf->entry[i].state) { + case Z_UNCHANGED: + if (zip_entry_copy(tzf, zf, i, NULL)) + myerror(ERRFILE, "zip_entry_copy failed"); + break; + case Z_DELETED: + break; + case Z_REPLACED: + /* fallthrough */ + case Z_ADDED: + if (zf->entry[i].ch_data_zf) { + if (zip_entry_copy(tzf, zf->entry[i].ch_data_zf, + zf->entry[i].ch_data_zf_fileno, + zf->entry[i].fn)) + myerror(ERRFILE, "zip_entry_copy failed"); + } else if (zf->entry[i].ch_data_buf) { +#if 0 + zip_entry_add(tzf, zf, i); +#endif /* 0 */ + } else if (zf->entry[i].ch_data_fp) { +#if 0 + zip_entry_add(tzf, zf, i); +#endif /* 0 */ + } else { + /* XXX: ? */ + myerror(ERRFILE, "Z_ADDED: no data"); + break; + } + break; + case Z_RENAMED: + if (zip_entry_copy(tzf, zf, i, NULL)) + myerror(ERRFILE, "zip_entry_copy failed"); + break; + default: + /* can't happen */ + break; + } + } + } + + writecdir(tzf); + + if (fclose(tzf->zp)==0) { + if (rename(tzf->zn, zf->zn) != 0) { + zip_err = ZERR_RENAME; + zf_free(tzf); + return -1; + } + } + + free(temp); + zf_free(zf); + + return 0; +} + + + +static int +_zip_entry_copy(struct zf *dest, struct zf *src, int entry_no, char *name) +{ + char buf[BUFSIZE]; + unsigned int len, remainder; + unsigned char *null; + struct zf_entry tempzfe; + + null = NULL; + + zip_create_entry(dest, src->entry+entry_no, name); + + if (fseek(src->zp, src->entry[entry_no].local_offset, SEEK_SET) != 0) { + zip_err = ZERR_SEEK; + return -1; + } + + if (_zip_readcdentry(src->zp, &tempzfe, &null, 0, 1, 1) != 0) { + zip_err = ZERR_READ; + return -1; + } + + free(tempzfe.fn); + tempzfe.fn = xstrdup(dest->entry[dest->nentry-1].fn); + tempzfe.fnlen = dest->entry[dest->nentry-1].fnlen; + + if (writecdentry(dest->zp, &tempzfe, 1) != 0) { + zip_err = ZERR_WRITE; + return -1; + } + + remainder = src->entry[entry_no].comp_size; + len = BUFSIZE; + while (remainder) { + if (len > remainder) + len = remainder; + if (fread(buf, 1, len, src->zp)!=len) { + zip_err = ZERR_READ; + return -1; + } + if (fwrite(buf, 1, len, dest->zp)!=len) { + zip_err = ZERR_WRITE; + return -1; + } + remainder -= len; + } + + return 0; +} + + + +static int +_zip_entry_add(struct zf *dest, struct zf *src, int entry_no) +{ + z_stream *zstr; + char *outbuf; + int ret, wrote; + + char buf[BUFSIZE]; + unsigned int len, remainder; + unsigned char *null; + + null = NULL; + + if (!src) + return -1; + + zip_create_entry(dest, NULL, src->entry[entry_no].fn); + + if (writecdentry(dest->zp, dest->entry+dest->nentry, 1) != 0) { + zip_err = ZERR_WRITE; + return -1; + } + + if (src->entry[entry_no].ch_data_fp) { + if (fseek(src->entry[entry_no].ch_data_fp, + src->entry[entry_no].ch_data_offset, SEEK_SET) != 0) { + zip_err = ZERR_SEEK; + return -1; + } + } else if (src->entry[entry_no].ch_data_buf) { + if (src->entry[entry_no].ch_data_offset) + src->entry[entry_no].ch_data_buf += + src->entry[entry_no].ch_data_offset; + + if (!src->entry[entry_no].ch_data_len) { + /* obviously no data */ + dest->nentry++; + return 0; + } + } else + return 1; + + zstr->zalloc = Z_NULL; + zstr->zfree = Z_NULL; + zstr->opaque = NULL; + zstr->avail_in = 0; + zstr->avail_out = 0; + + /* -15: undocumented feature of zlib to _not_ write a zlib header */ + deflateInit2(zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 9, + Z_DEFAULT_STRATEGY); + + if (src->entry[entry_no].ch_data_buf) { + outbuf = (char *)xmalloc(src->entry[entry_no].ch_data_len*1.01+12); + zstr->next_in = src->entry[entry_no].ch_data_buf; + zstr->avail_in = src->entry[entry_no].ch_data_len; + zstr->next_out = outbuf; + zstr->avail_out = src->entry[entry_no].ch_data_len*1.01+12; + + ret = deflate(zstr, Z_FINISH); + + switch(ret) { + case Z_STREAM_END: + break; + default: + myerror(ERRDEF, "zlib error while deflating buffer: %s", + zstr->msg); + return -1; + } + dest->entry[dest->nentry-1].crc = + crc32(dest->entry[dest->nentry-1].crc, + src->entry[entry_no].ch_data_buf, + src->entry[entry_no].ch_data_len); + dest->entry[dest->nentry-1].uncomp_size = + src->entry[entry_no].ch_data_len; + dest->entry[dest->nentry-1].comp_size = zstr->total_out; + + wrote = 0; + if ((ret = fwrite(outbuf+wrote, 1, zstr->total_out-wrote, dest->zp)) + < zstr->total_out-wrote) { + if (ferror(dest->zp)) { + zip_err = ZERR_WRITE; + return -1; + } + wrote += ret; + } + + fseek(dest->zp, dest->entry[dest->nentry-1].local_offset, + SEEK_SET); + if (ferror(dest->zp)) { + zip_err = ZERR_SEEK; + return -1; + } + + if (writecdentry(dest->zp, dest->entry+dest->nentry, 1) != 0) { + zip_err = ZERR_WRITE; + return -1; + } + + fseek(dest->zp, 0, SEEK_END); + if (ferror(dest->zp)) { + zip_err = ZERR_SEEK; + return -1; + } + + dest->nentry++; + return 0; + } + + /* missing: fp, partial zf */ + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +#if 0 + /* XXX: ignore below */ + remainder = src->entry[entry_no].comp_size; + len = BUFSIZE; + while (remainder) { + if (len > remainder) + len = remainder; + if (fread(buf, 1, len, src->zp)!=len) { + zip_err = ZERR_READ; + return -1; + } + if (fwrite(buf, 1, len, dest->zp)!=len) { + zip_err = ZERR_WRITE; + return -1; + } + remainder -= len; + } + + fseek(dest->zp, 0, SEEK_END); + dest->nentry++; + return 0; +#endif + return 1; +} + + + +static int +writecdir(struct zf *zfp) +{ + int i; + long cd_offset, cd_size; + + cd_offset = ftell(zfp->zp); + + for (i=0; i<zfp->nentry; i++) { + if (writecdentry(zfp->zp, zfp->entry+i, 0) != 0) { + zip_err = ZERR_WRITE; + return -1; + } + } + + cd_size = ftell(zfp->zp) - cd_offset; + + clearerr(zfp->zp); + fprintf(zfp->zp, EOCD_MAGIC); + fprintf(zfp->zp, "%c%c%c%c", 0, 0, 0, 0); + write2(zfp->zp, zfp->nentry); + write2(zfp->zp, zfp->nentry); + write4(zfp->zp, cd_size); + write4(zfp->zp, cd_offset); + write2(zfp->zp, zfp->comlen); + writestr(zfp->zp, zfp->com, zfp->comlen); + + return 0; +} + + + +static void +write2(FILE *fp, int i) +{ + putc(i&0xff, fp); + putc((i>>8)&0xff, fp); + + return; +} + + + +static void +write4(FILE *fp, int i) +{ + putc(i&0xff, fp); + putc((i>>8)&0xff, fp); + putc((i>>16)&0xff, fp); + putc((i>>24)&0xff, fp); + + return; +} + + + +static void +writestr(FILE *fp, char *str, int len) +{ +#if WIZ + int i; + for (i=0; i<len; i++) + putc(str[i], fp); +#else + fwrite(str, 1, len, fp); +#endif + + return; +} + + + +/* writecdentry: + if localp, writes local header for zfe to zf->zp, + else write central directory entry for zfe to zf->zp. + if after writing ferror(fp), return -1, else return 0.*/ + +static int +writecdentry(FILE *fp, struct zf_entry *zfe, int localp) +{ + fprintf(fp, "%s", localp?LOCAL_MAGIC:CENTRAL_MAGIC); + + if (!localp) + write2(fp, zfe->version_made); + write2(fp, zfe->version_need); + write2(fp, zfe->bitflags); + write2(fp, zfe->comp_meth); + write2(fp, zfe->lmtime); + write2(fp, zfe->lmdate); + + write4(fp, zfe->crc); + write4(fp, zfe->comp_size); + write4(fp, zfe->uncomp_size); + + write2(fp, zfe->fnlen); + write2(fp, zfe->eflen); + if (!localp) { + write2(fp, zfe->fcomlen); + write2(fp, zfe->disknrstart); + write2(fp, zfe->intatt); + + write4(fp, zfe->extatt); + write4(fp, zfe->local_offset); + } + + if (zfe->fnlen) + writestr(fp, zfe->fn, zfe->fnlen); + if (zfe->eflen) + writestr(fp, zfe->ef, zfe->eflen); + if (zfe->fcomlen) + writestr(fp, zfe->fcom, zfe->fcomlen); + + if (ferror(fp)) + return -1; + + return 0; +} + + + +static int +_zip_create_entry(struct zf *dest, struct zf_entry *src_entry, char *name) +{ + time_t now_t; + struct tm *now; + + if (!dest) + return -1; + + zip_new_entry(dest); + + if (!src_entry) { + /* set default values for central directory entry */ + dest->entry[dest->nentry-1].version_made = 20; + dest->entry[dest->nentry-1].version_need = 20; + /* maximum compression */ + dest->entry[dest->nentry-1].bitflags = 2; + /* deflate algorithm */ + dest->entry[dest->nentry-1].comp_meth = 8; + /* standard MS-DOS format time & date of compression start -- + thanks Info-Zip! (+1 for rounding) */ + now_t = time(NULL)+1; + now = localtime(&now_t); + dest->entry[dest->nentry-1].lmtime = ((now->tm_year+1900-1980)<<9)+ + ((now->tm_mon+1)<<5) + now->tm_mday; + dest->entry[dest->nentry-1].lmdate = ((now->tm_hour)<<11)+ + ((now->tm_min)<<5) + ((now->tm_sec)>>1); + dest->entry[dest->nentry-1].fcomlen = 0; + dest->entry[dest->nentry-1].eflen = 0; + dest->entry[dest->nentry-1].disknrstart = 0; + /* binary data */ + dest->entry[dest->nentry-1].intatt = 0; + /* XXX: init CRC-32, compressed and uncompressed size -- + will be updated later */ + dest->entry[dest->nentry-1].crc = crc32(0, 0, 0); + dest->entry[dest->nentry-1].comp_size = 0; + dest->entry[dest->nentry-1].uncomp_size = 0; + dest->entry[dest->nentry-1].extatt = 0; + dest->entry[dest->nentry-1].ef = NULL; + dest->entry[dest->nentry-1].fcom = NULL; + } else { + /* copy values from original zf_entry */ + dest->entry[dest->nentry-1].version_made = src_entry->version_made; + dest->entry[dest->nentry-1].version_need = src_entry->version_need; + dest->entry[dest->nentry-1].bitflags = src_entry->bitflags; + dest->entry[dest->nentry-1].comp_meth = src_entry->comp_meth; + dest->entry[dest->nentry-1].lmtime = src_entry->lmtime; + dest->entry[dest->nentry-1].lmdate = src_entry->lmdate; + dest->entry[dest->nentry-1].fcomlen = src_entry->fcomlen; + dest->entry[dest->nentry-1].eflen = src_entry->eflen; + dest->entry[dest->nentry-1].disknrstart = src_entry->disknrstart; + dest->entry[dest->nentry-1].intatt = src_entry->intatt; + dest->entry[dest->nentry-1].crc = src_entry->crc; + dest->entry[dest->nentry-1].comp_size = src_entry->comp_size; + dest->entry[dest->nentry-1].uncomp_size = src_entry->uncomp_size; + dest->entry[dest->nentry-1].extatt = src_entry->extatt; + dest->entry[dest->nentry-1].ef = (char *)memdup(src_entry->ef, + src_entry->eflen); + dest->entry[dest->nentry-1].fcom = (char *)memdup(src_entry->fcom, + src_entry->fcomlen); + } + + dest->entry[dest->nentry-1].local_offset = ftell(dest->zp); + + if (name) { + dest->entry[dest->nentry-1].fn = xstrdup(name); + dest->entry[dest->nentry-1].fnlen = strlen(name); + } else if (src_entry && src_entry->fn) { + dest->entry[dest->nentry-1].fn = xstrdup(src_entry->fn); + dest->entry[dest->nentry-1].fnlen = src_entry->fnlen; + } else { + dest->entry[dest->nentry-1].fn = xstrdup("-"); + dest->entry[dest->nentry-1].fnlen = 1; + } + + return 0; +}
diff --git a/lib/zip_name_locate.c b/lib/zip_name_locate.c new file mode 100644 index 0000000..e6e708d --- /dev/null +++ b/lib/zip_name_locate.c
@@ -0,0 +1,21 @@ +#include <string.h> + +#include "zip.h" +#include "zipint.h" + + + +int +zip_name_locate(struct zf *zf, char *fname, int case_sens) +{ + int i; + + if (case_sens == 0) + case_sens = 1 /* XXX: os default */; + + for (i=0; i<zf->nentry; i++) + if ((case_sens ? strcmp : strcasecmp)(fname, zf->entry[i].fn) == 0) + return i; + + return -1; +}
diff --git a/lib/zip_open.c b/lib/zip_open.c new file mode 100644 index 0000000..b42cc56 --- /dev/null +++ b/lib/zip_open.c
@@ -0,0 +1,487 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "zip.h" +#include "zipint.h" + +static struct zf *readcdir(FILE *fp, unsigned char *buf, + unsigned char *eocd, int buflen); +static int read2(unsigned char **a); +static int read4(unsigned char **a); +static char *readstr(unsigned char **buf, int len, int nulp); +static char *readfpstr(FILE *fp, int len, int nulp); +static int checkcons(FILE *fp, struct zf *zf); +static int headercomp(struct zf_entry *h1, int local1p, struct zf_entry *h2, + int local2p); + + + +/* zip_open: + Tries to open the file 'fn' as a zipfile. If flags & ZIP_CHECKCONS, + also does some consistency checks (comparing local headers to + central directory entries). If flags & ZIP_CREATE, make a new file + (if flags & ZIP_EXCL, error if already existing). Returns a + zipfile struct, or NULL if unsuccessful, setting zip_err. */ + +struct zf * +zip_open(char *fn, int flags) +{ + FILE *fp; + unsigned char *buf, *match; + int a, i, buflen, best; + struct zf *cdir, *cdirnew; + long len; + struct stat st; + + if (fn == NULL) + return NULL; + + if (stat(fn, &st) != 0) { + if (flags & ZIP_CREATE) { + cdir = zf_new(); + cdir->zn = xstrdup(fn); + return cdir; + } else { + zip_err = ZERR_FILENEXISTS; + return NULL; + } + } else if ((flags & ZIP_EXCL)) { + zip_err = ZERR_FILEEXISTS; + return NULL; + } + /* ZIP_CREAT gets ignored if file exists and not ZIP_EXCL, + just like open() */ + + if ((fp=fopen(fn, "rb"))==NULL) { + zip_err = ZERR_OPEN; + return NULL; + } + + clearerr(fp); + fseek(fp, 0, SEEK_END); + len = ftell(fp); + i = fseek(fp, -(len < BUFSIZE ? len : BUFSIZE), SEEK_END); + if (i == -1 && errno != EFBIG) { + /* seek before start of file on my machine */ + fclose(fp); + return NULL; + } + + buf = (unsigned char *)xmalloc(BUFSIZE); + + clearerr(fp); + buflen = fread(buf, 1, BUFSIZE, fp); + + if (ferror(fp)) { + /* read error */ + free(buf); + fclose(fp); + return NULL; + } + + best = -1; + cdir = NULL; + match = buf; + while ((match=memmem(match, buflen-(match-buf)-18, EOCD_MAGIC, 4))!=NULL) { + /* found match -- check, if good */ + /* to avoid finding the same match all over again */ + match++; + if ((cdirnew=readcdir(fp, buf, match-1, buflen)) == NULL) + continue; + + if (cdir) { + if (best <= 0) + best = checkcons(fp, cdir); + a = checkcons(fp, cdirnew); + if (best < a) { + zf_free(cdir); + cdir = cdirnew; + best = a; + } + else + zf_free(cdirnew); + } + else { + cdir = cdirnew; + if (flags & ZIP_CHECKCONS) + best = checkcons(fp, cdir); + else + best = 0; + } + cdirnew = NULL; + } + + if (best < 0) { + /* no consistent eocd found */ + free(buf); + zf_free(cdir); + fclose(fp); + return NULL; + } + + free(buf); + + cdir->zn = xstrdup(fn); + cdir->zp = fp; + + return cdir; +} + + + +/* readcdir: + tries to find a valid end-of-central-directory at the beginning of + buf, and then the corresponding central directory entries. + Returns a zipfile struct which contains the central directory + entries, or NULL if unsuccessful. */ + +static struct zf * +readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen) +{ + struct zf *zf; + unsigned char *cdp; + int i, comlen, readp; + + comlen = buf + buflen - eocd - EOCDLEN; + if (comlen < 0) { + /* not enough bytes left for comment */ + return NULL; + } + + /* check for end-of-central-dir magic */ + if (memcmp(eocd, EOCD_MAGIC, 4) != 0) + return NULL; + + if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) { + zip_err = ZERR_MULTIDISK; + return NULL; + } + + zf = zf_new(); + + cdp = eocd + 8; + /* number of cdir-entries on this disk */ + i = read2(&cdp); + /* number of cdir-entries */ + zf->nentry = zf->nentry_alloc = read2(&cdp); + zf->cd_size = read4(&cdp); + zf->cd_offset = read4(&cdp); + zf->comlen = read2(&cdp); + zf->entry = NULL; + + if ((zf->comlen != comlen) || (zf->nentry != i)) { + /* comment size wrong -- too few or too many left after central dir */ + /* or number of cdir-entries on this disk != number of cdir-entries */ + zf_free(zf); + return NULL; + } + + zf->com = (unsigned char *)memdup(eocd+EOCDLEN, zf->comlen); + + cdp = eocd; + if (zf->cd_size < eocd-buf) { + /* if buffer already read in, use it */ + readp = 0; + cdp = eocd - zf->cd_size; + } + else { + /* go to start of cdir and read it entry by entry */ + readp = 1; + clearerr(fp); + fseek(fp, -(zf->cd_size+zf->comlen+EOCDLEN), SEEK_END); + if (ferror(fp) || (ftell(fp) != zf->cd_offset)) { + /* seek error or offset of cdir wrong */ + zf_free(zf); + return NULL; + } + } + + zf->entry = (struct zf_entry *)xmalloc(sizeof(struct zf_entry) + *zf->nentry); + for (i=0; i<zf->nentry; i++) { + zf->entry[i].fn = NULL; + zf->entry[i].ef = NULL; + zf->entry[i].fcom = NULL; + zip_entry_init(zf, i); + } + + for (i=0; i<zf->nentry; i++) { + if ((_zip_readcdentry(fp, zf->entry+i, &cdp, eocd-cdp, readp, 0)) < 0) { + /* i entries have already been filled, tell zf_free + how many to free */ + zf_free(zf); + return NULL; + } + } + + return zf; +} + + + +/* _zip_readcdentry: + fills the zipfile entry zfe with data from the buffer *cdpp, not reading + more than 'left' bytes from it; if readp != 0, it also reads more data + from fp, if necessary. If localp != 0, it reads a local header instead + of a central directory entry. Returns 0 if successful, -1 if not, + advancing *cdpp for each byte read. */ + +int +_zip_readcdentry(FILE *fp, struct zf_entry *zfe, unsigned char **cdpp, + int left, int readp, int localp) +{ + unsigned char buf[CDENTRYSIZE]; + unsigned char *cur; + int size; + + if (localp) + size = LENTRYSIZE; + else + size = CDENTRYSIZE; + + if (readp) { + /* read entry from disk */ + if ((fread(buf, 1, size, fp)<size)) + return -1; + left = size; + cur = buf; + } + else { + cur = *cdpp; + if (left < size) + return -1; + } + + if (localp) { + if (memcmp(cur, LOCAL_MAGIC, 4)!=0) + return -1; + } + else + if (memcmp(cur, CENTRAL_MAGIC, 4)!=0) + return -1; + + cur += 4; + + /* convert buffercontents to zf_entry */ + if (!localp) + zfe->version_made = read2(&cur); + else + zfe->version_made = 0; + zfe->version_need = read2(&cur); + zfe->bitflags = read2(&cur); + zfe->comp_meth = read2(&cur); + zfe->lmtime = read2(&cur); + zfe->lmdate = read2(&cur); + + zfe->crc = read4(&cur); + zfe->comp_size = read4(&cur); + zfe->uncomp_size = read4(&cur); + + zfe->fnlen = read2(&cur); + zfe->eflen = read2(&cur); + if (!localp) { + zfe->fcomlen = read2(&cur); + zfe->disknrstart = read2(&cur); + zfe->intatt = read2(&cur); + + zfe->extatt = read4(&cur); + zfe->local_offset = read4(&cur); + } + else { + zfe->fcomlen = zfe->disknrstart = zfe->intatt = 0; + zfe->extatt = zfe->local_offset = 0; + } + + if (left < CDENTRYSIZE+zfe->fnlen+zfe->eflen+zfe->fcomlen) { + if (readp) { + if (zfe->fnlen) + zfe->fn = readfpstr(fp, zfe->fnlen, 1); + else + zfe->fn = xstrdup(""); + if (zfe->eflen) + zfe->ef = readfpstr(fp, zfe->eflen, 0); + /* XXX: really null-terminate comment? */ + if (zfe->fcomlen) + zfe->fcom = readfpstr(fp, zfe->fcomlen, 1); + } + else { + /* can't get more bytes if not allowed to read */ + return -1; + } + } + else { + if (zfe->fnlen) + zfe->fn = readstr(&cur, zfe->fnlen, 1); + if (zfe->eflen) + zfe->ef = readstr(&cur, zfe->eflen, 0); + if (zfe->fcomlen) + zfe->fcom = readstr(&cur, zfe->fcomlen, 1); + } + if (!readp) + *cdpp = cur; + + /* XXX */ + zfe->ch_data_fp = NULL; + zfe->ch_data_buf = NULL; + zfe->ch_data_offset = 0; + zfe->ch_data_len = 0; + + return 0; +} + + + +static int +read2(unsigned char **a) +{ + int ret; + + ret = (*a)[0]+((*a)[1]<<8); + *a += 2; + + return ret; +} + + + +static int +read4(unsigned char **a) +{ + int ret; + + ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0]; + *a += 4; + + return ret; +} + + + +static char * +readstr(unsigned char **buf, int len, int nulp) +{ + char *r; + + r = (char *)xmalloc(nulp?len+1:len); + memcpy(r, *buf, len); + *buf += len; + + if (nulp) + r[len] = 0; + + return r; +} + + + +static char * +readfpstr(FILE *fp, int len, int nullp) +{ + char *r; + + r = (char *)xmalloc(nullp?len+1:len); + if (fread(r, 1, len, fp)<len) { + free(r); + return NULL; + } + + if (nullp) + r[len] = 0; + + return r; +} + + + +/* checkcons: + Checks the consistency of the central directory by comparing central + directory entries with local headers and checking for plausible + file and header offsets. Returns -1 if not plausible, else the + difference between the lowest and the highest fileposition reached */ + +static int +checkcons(FILE *fp, struct zf *zf) +{ + int min, max, i, j; + struct zf_entry temp; + unsigned char *buf; + + buf = NULL; + + if (zf->nentry) { + max = zf->entry[0].local_offset; + min = zf->entry[0].local_offset; + } + + for (i=0; i<zf->nentry; i++) { + if (zf->entry[i].local_offset < min) + min = zf->entry[i].local_offset; + if (min < 0) + return -1; + + j = zf->entry[i].local_offset + zf->entry[i].comp_size + + zf->entry[i].fnlen + zf->entry[i].eflen + + zf->entry[i].fcomlen + LENTRYSIZE; + if (j > max) + max = j; + if (max > zf->cd_offset) + return -1; + + if (fseek(fp, zf->entry[i].local_offset, SEEK_SET) != 0) { + zip_err = ZERR_SEEK; + return -1; + } + _zip_readcdentry(fp, &temp, &buf, 0, 1, 1); + if (headercomp(zf->entry+i, 0, &temp, 1) != 0) + return -1; + } + + return max - min; +} + + + +/* 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. */ + +static int +headercomp(struct zf_entry *h1, int local1p, struct zf_entry *h2, + int local2p) +{ + if ((h1->version_need != h2->version_need) + || (h1->bitflags != h2->bitflags) + || (h1->comp_meth != h2->comp_meth) + || (h1->lmtime != h2->lmtime) + || (h1->lmdate != h2->lmdate) + || (h1->fnlen != h2->fnlen) + || (h1->crc != h2->crc) + || (h1->comp_size != h2->comp_size) + || (h1->uncomp_size != h2->uncomp_size) + || (h1->fnlen && memcmp(h1->fn, h2->fn, h1->fnlen))) + return -1; + + /* if they are different type, nothing more to check */ + if (local1p != local2p) + return 0; + + if ((h1->version_made != h2->version_made) + || (h1->disknrstart != h2->disknrstart) + || (h1->intatt != h2->intatt) + || (h1->extatt != h2->extatt) + || (h1->local_offset != h2->local_offset) + || (h1->eflen != h2->eflen) + || (h1->eflen && memcmp(h1->fn, h2->fn, h1->fnlen)) + || (h1->fcomlen != h2->fcomlen) + || (h1->fcomlen && memcmp(h1->fcom, h2->fcom, h1->fcomlen))) { + return -1; + } + + return 0; +}
diff --git a/lib/zipint.h b/lib/zipint.h new file mode 100644 index 0000000..9a8bcf4 --- /dev/null +++ b/lib/zipint.h
@@ -0,0 +1,20 @@ +#ifndef _HAD_ZIPINT_H +#define _HAD_ZIPINT_H + + +#define MAXCOMLEN 65536 +#define EOCDLEN 22 +#define BUFSIZE (MAXCOMLEN+EOCDLEN) +#define LOCAL_MAGIC "PK\3\4" +#define CENTRAL_MAGIC "PK\1\2" +#define EOCD_MAGIC "PK\5\6" +#define DATADES_MAGIC "PK\7\8" +#define CDENTRYSIZE 46 +#define LENTRYSIZE 30 + +struct zf *_zip_zf_new(void); +int _zip_zf_free(struct zf *zf); +int _zip_readcdentry(FILE *fp, struct zf_entry *zfe, unsigned char **cdpp, + int left, int readp, int localp); + +#endif /* zipint.h */
diff --git a/zf_new_free.c b/zf_new_free.c new file mode 100644 index 0000000..c9fa182 --- /dev/null +++ b/zf_new_free.c
@@ -0,0 +1,81 @@ +#include <stdlib.h> + +#include "zip.h" +#include "zipint.h" + + + +/* _zip_zf_new: + creates a new zipfile struct, and sets the contents to zero; returns + the new struct. */ + +struct zf * +_zip_zf_new(void) +{ + struct zf *zf; + + zf = (struct zf *)xmalloc(sizeof(struct zf)); + + zf->zn = NULL; + zf->zp = NULL; + zf->comlen = zf->changes = 0; + zf->nentry = zf->nentry_alloc = zf->cd_size = zf->cd_offset = 0; + zf->nfile = zf->nfile_alloc = 0; + zf->com = NULL; + zf->entry = NULL; + zf->file = NULL; + + return zf; +} + + + +/* _zip_zf_free: + frees the space allocated to a zipfile struct, and closes the + corresponding file. Returns 0 if successful, the error returned + by fclose if not. */ + +int +_zip_zf_free(struct zf *zf) +{ + int i, ret; + + if (zf == NULL) + return 0; + + if (zf->zn) + free(zf->zn); + + if (zf->zp) + ret = fclose(zf->zp); + + if (zf->com) + free(zf->com); + + if (zf->entry) { + for (i=0; i<zf->nentry; i++) { + free(zf->entry[i].fn); + free(zf->entry[i].ef); + free(zf->entry[i].fcom); + free(zf->entry[i].fn_old); + if (zf->entry[i].ch_data_fp) + (void)fclose(zf->entry[i].ch_data_fp); + } + free (zf->entry); + } + + for (i=0; i<zf->nfile; i++) { + zf->file[i]->flags = ZERR_ZIPCLOSED; + zf->file[i]->zf = NULL; + zf->file[i]->name = NULL; + } + + free(zf->file); + + free(zf); + + if (ret) + zip_err = ZERR_CLOSE; + + return ret; +}
diff --git a/zff.c b/zff.c new file mode 100644 index 0000000..d02def9 --- /dev/null +++ b/zff.c
@@ -0,0 +1,265 @@ +#include <stdlib.h> +#include "error.h" +#include "xmalloc.h" +#include "ziplow.h" +#include "zip.h" + +struct zf_file * +zff_new(struct zf *zf) +{ + struct zf_file *zff; + + if (zf->nfile >= zf->nfile_alloc-1) { + zf->nfile_alloc += 10; + zf->file = (struct zf_file **)xrealloc(zf->file, zf->nfile_alloc + *sizeof(struct zf_file *)); + } + + zff = (struct zf_file *)xmalloc(sizeof(struct zf_file)); + zf->file[zf->nfile++] = zff; + + zff->zf = zf; + zff->flags = 0; + zff->crc = crc32(0L, Z_NULL, 0); + zff->crc_orig = 0; + zff->method = -1; + zff->bytes_left = zff->cbytes_left = 0; + zff->fpos = 0; + zff->buffer = NULL; + zff->zstr = NULL; + + return zff; +} + + + +int +zff_fillbuf(char *buf, int buflen, struct zf_file *zff) +{ + int i, j; + + if (zff->flags != 0) + return -1; + if (zff->cbytes_left <= 0 || buflen <= 0) + return 0; + + fseek(zff->zf->zp, zff->fpos, SEEK_SET); + if (buflen < zff->cbytes_left) + i = buflen; + else + i = zff->cbytes_left; + + j = fread(buf, 1, i, zff->zf->zp); + if (j == 0) + zff->flags = ZERR_SEEK; + else if (j < 0) + zff->flags = ZERR_READ; + else { + zff->fpos += j; + zff->cbytes_left -= j; + } + + return j; +} + + + +int +zff_close(struct zf_file *zff) +{ + int i, ret; + + if (zff->zstr) + inflateEnd(zff->zstr); + free(zff->buffer); + free(zff->zstr); + + for (i=0; i<zff->zf->nfile; i++) { + if (zff->zf->file[i] == zff) { + zff->zf->file[i] = zff->zf->file[zff->zf->nfile-1]; + zff->zf->nfile--; + break; + } + } + + /* EOF is ok */ + ret = (zff->flags == -1 ? 0 : zff->flags); + if (!ret) + ret = (zff->crc_orig == zff->crc); + + free(zff); + return ret; +} + + + +struct zf_file * +zff_open(struct zf *zf, char *fname, int case_sens) +{ + int idx; + + if ((idx=zip_name_locate(zf, fname, case_sens)) < 0) + return NULL; + + return zff_open_index(zf, idx); +} + + + +struct zf_file * +zff_open_index(struct zf *zf, int fileno) +{ + unsigned char buf[4], *c; + int len; + struct zf_file *zff; + + if ((fileno < 0) || (fileno >= zf->nentry)) + return NULL; + + if (zf->entry[fileno].state != Z_UNCHANGED + && zf->entry[fileno].state != Z_RENAMED) + return NULL; + + if ((zf->entry[fileno].comp_meth != 0) + && (zf->entry[fileno].comp_meth != 8)) { + myerror(ERRFILE, "unsupported compression method %d", + zf->entry[fileno].comp_meth); + return NULL; + } + + zff = zff_new(zf); + + zff->name = zf->entry[fileno].fn; + zff->method = zf->entry[fileno].comp_meth; + zff->bytes_left = zf->entry[fileno].uncomp_size; + zff->cbytes_left = zf->entry[fileno].comp_size; + zff->crc_orig = zf->entry[fileno].crc; + + /* go to start of actual data */ + fseek (zf->zp, zf->entry[fileno].local_offset+LENTRYSIZE-4, SEEK_SET); + len = fread(buf, 1, 4, zf->zp); + if (len != 4) { + myerror (ERRSTR, "can't read local header"); + return NULL; + } + c = buf; + zff->fpos = zf->entry[fileno].local_offset+LENTRYSIZE; + zff->fpos += read2(&c); + zff->fpos += read2(&c); + + if (zf->entry[fileno].comp_meth == 0) + return zff; + + zff->buffer = (char *)xmalloc(BUFSIZE); + + len = zff_fillbuf (zff->buffer, BUFSIZE, zff); + if (len <= 0) { + /* XXX: error handling */ + zff_close(zff); + return NULL; + } + + zff->zstr = (z_stream *)xmalloc(sizeof(z_stream)); + zff->zstr->zalloc = Z_NULL; + zff->zstr->zfree = Z_NULL; + zff->zstr->opaque = NULL; + zff->zstr->next_in = zff->buffer; + zff->zstr->avail_in = len; + + /* negative value to tell zlib that there is no header */ + if (inflateInit2(zff->zstr, -MAX_WBITS) != Z_OK) { + /* XXX: error here + myerror(ERRFILE, zff->zstr->msg); + */ + zff_close(zff); + return NULL; + } + + return zff; +} + + + + +int +zff_read(struct zf_file *zff, char *outbuf, int toread) +{ + int len, out_before, ret; + + if (!zff) + return -1; + + if (zff->flags != 0) + return -1; + + if (toread == 0) + return 0; + + if (zff->bytes_left == 0) { + zff->flags = -1; + if (zff->crc != zff->crc_orig) { + zff->flags = ZERR_CRC; + return -1; + } + return 0; + } + + if (zff->method == 0) { + ret = zff_fillbuf(outbuf, toread, zff); + if (ret > 0) { + zff->crc = crc32(zff->crc, outbuf, ret); + zff->bytes_left -= ret; + } + return ret; + } + + zff->zstr->next_out = outbuf; + zff->zstr->avail_out = toread; + out_before = zff->zstr->total_out; + + /* endless loop until something has been accomplished */ + for (;;) { + ret = inflate(zff->zstr, Z_SYNC_FLUSH); + + switch (ret) { + case Z_OK: + case Z_STREAM_END: + /* all ok */ + /* XXX: STREAM_END probably won't happen, since we didn't + have a header */ + len = zff->zstr->total_out - out_before; + if (len >= zff->bytes_left || len >= toread) { + zff->crc = crc32(zff->crc, outbuf, len); + zff->bytes_left -= len; + return(len); + } + break; + + case Z_BUF_ERROR: + if (zff->zstr->avail_in == 0) { + /* read some more bytes */ + len = zff_fillbuf(zff->buffer, BUFSIZE, zff); + if (len <= 0) { + /* XXX: error + myerror (ERRSTR, "read error"); + */ + return -1; + } + zff->zstr->next_in = zff->buffer; + zff->zstr->avail_in = len; + continue; + } + /* XXX: set error */ + myerror(ERRFILE, "zlib error: buf_err: %s", zff->zstr->msg); + return -1; + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_MEM_ERROR: + /* XXX: set error */ + myerror(ERRFILE, "zlib error: %s", zff->zstr->msg); + return -1; + } + } +} +
diff --git a/zip.c b/zip.c new file mode 100644 index 0000000..a344680 --- /dev/null +++ b/zip.c
@@ -0,0 +1,268 @@ +#include <stdlib.h> + +#include "zip.h" +#include "xmalloc.h" + +static int zip_unchange_data(struct zf *zf, int idx); +static int zip_set_name(struct zf *zf, int idx, char *name); + +/* XXX: place in internal header file. */ +void zip_new_entry(struct zf *zf); +void zip_entry_init(struct zf *zf, int idx); + + + +int +zip_rename(struct zf *zf, int idx, char *name) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + if (zf->entry[idx].state == Z_UNCHANGED) + zf->entry[idx].state = Z_RENAMED; + zf->changes = 1; + + zip_set_name(zf, idx, name); + + return idx; +} + + + +int +zip_add_file(struct zf *zf, char *name, FILE *file, + int start, int len) +{ + zip_new_entry(zf); + + zf->changes = 1; + zip_set_name(zf, zf->nentry-1, name ? name : "-"); + zf->entry[zf->nentry-1].ch_data_fp = file; + zf->entry[zf->nentry-1].ch_data_offset = start; + zf->entry[zf->nentry-1].ch_data_len = len; + + return zf->nentry-1; +} + + + +int +zip_add_data(struct zf *zf, char *name, char *buf, + int start, int len) +{ + zip_new_entry(zf); + + zf->changes = 1; + zip_set_name(zf, zf->nentry-1, name ? name : "-"); + zf->entry[zf->nentry-1].ch_data_buf = buf; + zf->entry[zf->nentry-1].ch_data_offset = start; + zf->entry[zf->nentry-1].ch_data_len = len; + + return zf->nentry-1; +} + + + +int +zip_add_zip(struct zf *zf, char *name, struct zf *srczf, int srcidx, + int start, int len) +{ + if (srcidx >= srczf->nentry || srcidx < 0) + return -1; + + zip_new_entry(zf); + + zf->changes = 1; + zip_set_name(zf, zf->nentry-1, name ? name : srczf->entry[srcidx].fn); + zf->entry[zf->nentry-1].ch_data_zf = srczf; + zf->entry[zf->nentry-1].ch_data_zf_fileno = srcidx; + zf->entry[zf->nentry-1].ch_data_offset = start; + zf->entry[zf->nentry-1].ch_data_len = len; + + return zf->nentry-1; +} + + + +int +zip_replace_file(struct zf *zf, int idx, char *name, FILE *file, + int start, int len) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + zip_unchange_data(zf, idx); + + zf->changes = 1; + zf->entry[idx].state = Z_REPLACED; + zip_set_name(zf, idx, name); + + zf->entry[idx].ch_data_fp = file; + zf->entry[idx].ch_data_offset = start; + zf->entry[idx].ch_data_len = len; + + return idx; +} + + + +int +zip_replace_data(struct zf *zf, int idx, char *name, char *buf, + int start, int len) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + zip_unchange_data(zf, idx); + + zf->changes = 1; + zf->entry[idx].state = Z_REPLACED; + zip_set_name(zf, idx, name); + + zf->entry[idx].ch_data_buf = buf; + zf->entry[idx].ch_data_offset = start; + zf->entry[idx].ch_data_len = len; + + return idx; +} + + + +int +zip_replace_zip(struct zf *zf, int idx, char *name, struct zf *srczf, + int srcidx, int start, int len) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + if (srcidx >= srczf->nentry || srcidx < 0) + return -1; + + zip_unchange_data(zf, idx); + + zf->changes = 1; + zf->entry[idx].state = Z_REPLACED; + zip_set_name(zf, idx, name); + + zf->entry[idx].ch_data_zf = srczf; + zf->entry[idx].ch_data_zf_fileno = srcidx; + zf->entry[idx].ch_data_offset = start; + zf->entry[idx].ch_data_len = len; + + return idx; +} + + + +int +zip_delete(struct zf *zf, int idx) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + zip_unchange(zf, idx); + + zf->changes = 1; + zf->entry[idx].state = Z_DELETED; + + return idx; +} + + + +int +zip_unchange(struct zf *zf, int idx) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + if (zf->entry[idx].fn_old) { + free(zf->entry[idx].fn); + zf->entry[idx].fn = zf->entry[idx].fn_old; + zf->entry[idx].fn_old = NULL; + zf->entry[idx].fnlen = strlen(zf->entry[idx].fn); + } + + return zip_unchange_data(zf, idx); +} + + + +static int +zip_unchange_data(struct zf *zf, int idx) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + if (zf->entry[idx].ch_data_fp) { + fclose(zf->entry[idx].ch_data_fp); + zf->entry[idx].ch_data_fp = NULL; + } + if (zf->entry[idx].ch_data_buf) { + free(zf->entry[idx].ch_data_buf); + zf->entry[idx].ch_data_buf = NULL; + } + + zf->entry[idx].ch_data_zf = NULL; + zf->entry[idx].ch_data_zf_fileno = 0; + zf->entry[idx].ch_data_offset = 0; + zf->entry[idx].ch_data_len = 0; + + zf->entry[idx].state = zf->entry[idx].fn_old ? Z_RENAMED : Z_UNCHANGED; + + return idx; +} + + + +static int +zip_set_name(struct zf *zf, int idx, char *name) +{ + if (idx >= zf->nentry || idx < 0) + return -1; + + if (name != NULL) { + if (zf->entry[idx].fn_old == NULL) + zf->entry[idx].fn_old = zf->entry[idx].fn; + else + free(zf->entry[idx].fn); + zf->entry[idx].fn = xstrdup(name); + zf->entry[idx].fnlen = strlen(name); + } + + return idx; +} + + + +void +zip_entry_init(struct zf *zf, int idx) +{ + zf->entry[idx].fn = zf->entry[idx].ef = zf->entry[idx].fcom = + zf->entry[idx].fn_old = NULL; + zf->entry[idx].state = Z_UNCHANGED; + zf->entry[idx].ch_data_zf = NULL; + zf->entry[idx].ch_data_buf = NULL; + zf->entry[idx].ch_data_fp = NULL; + zf->entry[idx].ch_data_offset = zf->entry[idx].ch_data_len = 0; + zf->entry[idx].ch_data_zf_fileno = 0; +} + + + +void +zip_new_entry(struct zf *zf) +{ + if (zf->nentry >= zf->nentry_alloc-1) { + zf->nentry_alloc += 16; + zf->entry = (struct zf_entry *)xrealloc(zf->entry, + sizeof(struct zf_entry) + * zf->nentry_alloc); + } + zip_entry_init(zf, zf->nentry); + + zf->entry[zf->nentry].fn_old = NULL; + zf->entry[zf->nentry].state = Z_ADDED; + + zf->nentry++; +}
diff --git a/zip_err_str.c b/zip_err_str.c new file mode 100644 index 0000000..d2c803c --- /dev/null +++ b/zip_err_str.c
@@ -0,0 +1,18 @@ +#include "zip.h" + + + +char * zip_err_str[]={ + "no error", + "multi-disk zip-files not supported", + "replacing zipfile with tempfile failed", + "closing zipfile failed", + "seek error", + "read error", + "write error", + "CRC error", + "zip file closed without closing this file", + "file does already exist", + "file doesn't exist", + "can't open file" +};
diff --git a/ziplow.h b/ziplow.h new file mode 100644 index 0000000..6bda41d --- /dev/null +++ b/ziplow.h
@@ -0,0 +1,34 @@ +#ifndef _HAD_ZIPLOW_H +#define _HAD_ZIPLOW_H + +#include "zip.h" + +#define MAXCOMLEN 65536 +#define EOCDLEN 22 +#define BUFSIZE (MAXCOMLEN+EOCDLEN) +#define LOCAL_MAGIC "PK\3\4" +#define CENTRAL_MAGIC "PK\1\2" +#define EOCD_MAGIC "PK\5\6" +#define DATADES_MAGIC "PK\7\8" +#define CDENTRYSIZE 46 +#define LENTRYSIZE 30 + +struct zf *readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, + int buflen); +int writecdir(struct zf *zfp); +struct zf *zf_new(void); +int zf_free(struct zf *zf); +char *readstr(unsigned char **buf, int len, int nullp); +char *readfpstr(FILE *fp, int len, int nullp); +int read2(unsigned char **a); +int read4(unsigned char **a); +int readcdentry(FILE *fp, struct zf_entry *zfe, unsigned char **cdpp, + int left, int readp, int localp); +int writecdentry(FILE *fp, struct zf_entry *zfe, int localp); +int checkcons(FILE *fp, struct zf *zf); +int headercomp(struct zf_entry *h1, int local1p, struct zf_entry *h2, + int local2p); +int zip_entry_copy(struct zf *dest, struct zf *src, int entry_no, + char *name); + +#endif /* _HAD_ZIPLOW_H */