struct zip_extra_field * _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, struct zip_error *error) { struct zip_extra_field *ef, *ef2, *ef_head; const zip_uint8_t *p; zip_uint16_t fid, flen; ef_head = NULL; for (p=data; p<data+len; p+=flen) { if (p+4 > data+len) { _zip_error_set(error, ZIP_ER_INCONS, 0); _zip_ef_free(ef_head); return NULL; } fid = _zip_read2(&p); flen = _zip_read2(&p); if (p+flen > data+len) { _zip_error_set(error, ZIP_ER_INCONS, 0); _zip_ef_free(ef_head); return NULL; } if ((ef2=_zip_ef_new(fid, flen, p, flags)) == NULL) { _zip_error_set(error, ZIP_ER_MEMORY, 0); _zip_ef_free(ef_head); return NULL; } if (ef_head) { ef->next = ef2; ef = ef2; } else ef_head = ef = ef2; } return ef_head; }
static int write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) { off_t offset; uLong crc; char buf[TORRENT_CRC_LEN+1]; if (_zip_cdir_write(cd, out, &za->error) < 0) return -1; if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0) return 0; /* fix up torrentzip comment */ offset = ftello(out); if (_zip_filerange_crc(out, cd->offset, cd->size, &crc, &za->error) < 0) return -1; #ifndef _WIN32 snprintf(buf, sizeof(buf), "%08lX", (long)crc); #else _snprintf(buf, sizeof(buf), "%08lX", (long)crc); #endif if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { _zip_error_set(&za->error, ZIP_ER_WRITE, errno); return -1; } return 0; }
ZIP_EXTERN struct zip_source * zip_source_file(struct zip *za, const char *fname, off_t start, off_t len) { if (za == NULL) return NULL; if (fname == NULL || start < 0 || len < -1) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } return _zip_source_file_or_p(za, fname, NULL, start, len); }
ZIP_EXTERN int zip_delete(struct zip *za, zip_uint64_t idx) { if (idx >= za->nentry) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } /* allow duplicate file names, because the file will * be removed directly afterwards */ if (_zip_unchange(za, idx, 1) != 0) return -1; za->entry[idx].deleted = 1; return 0; }
int _zip_name_locate(struct zip *za, const char *fname, int flags, struct zip_error *error) { int (*cmp)(const char *, const char *); const char *fn, *p; int i, n; if (fname == NULL) { _zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry; for (i=0; i<n; i++) { if (flags & ZIP_FL_UNCHANGED) fn = za->cdir->entry[i].filename; else fn = _zip_get_name(za, i, flags, error); /* newly added (partially filled) entry */ if (fn == NULL) continue; if (flags & ZIP_FL_NODIR) { p = strrchr(fn, '/'); if (p) fn = p+1; } if (cmp(fname, fn) == 0) return i; } _zip_error_set(error, ZIP_ER_NOENT, 0); return -1; }
zip_int64_t _zip_name_locate(struct zip *za, const char *fname, zip_flags_t flags, struct zip_error *error) { int (*cmp)(const char *, const char *); const char *fn, *p; zip_uint64_t i; if (za == NULL) return -1; if (fname == NULL) { _zip_error_set(error, ZIP_ER_INVAL, 0); return -1; } cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; for (i=0; i<za->nentry; i++) { fn = _zip_get_name(za, i, flags, error); /* newly added (partially filled) entry or error */ if (fn == NULL) continue; if (flags & ZIP_FL_NODIR) { p = strrchr(fn, '/'); if (p) fn = p+1; } if (cmp(fname, fn) == 0) { _zip_error_clear(error); return (zip_int64_t)i; } } _zip_error_set(error, ZIP_ER_NOENT, 0); return -1; }
ZIP_EXTERN int zip_replace(struct zip *za, zip_uint64_t idx, struct zip_source *source) { if (idx >= za->nentry || source == NULL) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (_zip_replace(za, idx, NULL, source) == -1) return -1; return 0; }
ZIP_EXTERN struct zip_source * zip_source_filep(struct zip *za, FILE *file, off_t start, off_t len) { if (za == NULL) return NULL; if (file == NULL || start < 0 || len < -1) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } return _zip_source_file_or_p(za, NULL, file, start, len); }
static struct zip_file * _zip_file_new(struct zip *za) { struct zip_file *zf, **file; int n; if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } if (za->nfile >= za->nfile_alloc-1) { n = za->nfile_alloc + 10; file = (struct zip_file **)realloc(za->file, n*sizeof(struct zip_file *)); if (file == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); free(zf); return NULL; } za->nfile_alloc = n; za->file = file; } za->file[za->nfile++] = zf; zf->za = za; _zip_error_init(&zf->error); zf->flags = 0; zf->crc = crc32(0L, Z_NULL, 0); zf->crc_orig = 0; zf->method = -1; zf->bytes_left = zf->cbytes_left = 0; zf->fpos = 0; zf->buffer = NULL; zf->zstr = NULL; return zf; }
static char * _zip_create_temp_output(struct zip *za, FILE **outp) { char *temp; int tfd; FILE *tfp; if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } sprintf(temp, "%s.XXXXXX", za->zn); if ((tfd=mkstemp(temp)) == -1) { _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); free(temp); return NULL; } if ((tfp=fdopen(tfd, "r+b")) == NULL) { _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); close(tfd); remove(temp); free(temp); return NULL; } #ifdef _WIN32 /* According to Pierre Joye, Windows in some environments per default creates text files, so force binary mode. */ _setmode(_fileno(tfp), _O_BINARY ); #endif *outp = tfp; return temp; }
ZIP_EXTERN int zip_add_dir(struct zip *za, const char *name) { int len, ret; char *s; struct zip_source *source; if (name == NULL) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } s = NULL; len = (int)strlen(name); if (name[len-1] != '/') { if ((s=(char *)malloc(len+2)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } strcpy(s, name); s[len] = '/'; s[len+1] = '\0'; } if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) { free(s); return -1; } ret = _zip_replace(za, -1, s ? s : name, source); free(s); if (ret < 0) zip_source_free(source); return ret; }
ZIP_EXTERN struct zip_source * zip_source_pkware(struct zip *za, struct zip_source *src, zip_uint16_t em, int flags, const char *password) { struct trad_pkware *ctx; struct zip_source *s2; if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if (flags & ZIP_CODEC_ENCODE) { _zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); return NULL; } if (crc == NULL) crc = get_crc_table(); if ((ctx=(struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } ctx->e[0] = ctx->e[1] = 0; ctx->key[0] = KEY0; ctx->key[1] = KEY1; ctx->key[2] = KEY2; decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password), 1); if ((s2=zip_source_layered(za, src, pkware_decrypt, ctx)) == NULL) { pkware_free(ctx); return NULL; } return s2; }
static int write_cdir(struct zip *za, const struct zip_filelist *filelist, zip_uint64_t survivors, FILE *out) { off_t cd_start, end; zip_int64_t size; uLong crc; char buf[TORRENT_CRC_LEN+1]; cd_start = ftello(out); if ((size=_zip_cdir_write(za, filelist, survivors, out)) < 0) return -1; end = ftello(out); if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0) return 0; /* fix up torrentzip comment */ if (_zip_filerange_crc(out, cd_start, size, &crc, &za->error) < 0) return -1; snprintf(buf, sizeof(buf), "%08lX", (long)crc); if (fseeko(out, end-TORRENT_CRC_LEN, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { _zip_error_set(&za->error, ZIP_ER_WRITE, errno); return -1; } return 0; }
struct zip_entry * _zip_entry_new(struct zip *za) { struct zip_entry *ze; if (!za) { ze = (struct zip_entry *)malloc(sizeof(struct zip_entry)); if (!ze) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } } else { if (za->nentry >= za->nentry_alloc-1) { za->nentry_alloc += 16; za->entry = (struct zip_entry *)realloc(za->entry, sizeof(struct zip_entry) * za->nentry_alloc); if (!za->entry) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } } ze = za->entry+za->nentry; } ze->state = ZIP_ST_UNCHANGED; ze->ch_filename = NULL; ze->ch_comment = NULL; ze->ch_comment_len = -1; ze->source = NULL; if (za) za->nentry++; return ze; }
struct zip_source * zip_source_deflate(struct zip *za, struct zip_source *src, zip_int32_t cm, int flags) { struct deflate *ctx; struct zip_source *s2; if (src == NULL || (cm != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(cm))) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((ctx=(struct deflate *)malloc(sizeof(*ctx))) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } ctx->e[0] = ctx->e[1] = 0; ctx->eof = 0; if (flags & ZIP_CODEC_ENCODE) { if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) ctx->mem_level = TORRENT_MEM_LEVEL; else ctx->mem_level = MAX_MEM_LEVEL; } if ((s2=zip_source_layered(za, src, ((flags & ZIP_CODEC_ENCODE) ? deflate_compress : deflate_decompress), ctx)) == NULL) { deflate_free(ctx); return NULL; } return s2; }
struct zip_source * _zip_source_file_or_p(struct zip *za, const char *fname, FILE *file, off_t start, off_t len) { struct read_file *f; struct zip_source *zs; if (file == NULL && fname == NULL) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } f->fname = NULL; if (fname) { if ((f->fname=strdup(fname)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); free(f); return NULL; } } f->f = file; f->off = start; f->len = (len ? len : -1); if ((zs=zip_source_function(za, read_file, f)) == NULL) { free(f); return NULL; } return zs; }
const char * _zip_get_name(struct zip *za, int idx, int flags, struct zip_error *error) { if (idx < 0 || idx >= za->nentry) { _zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } if ((flags & ZIP_FL_UNCHANGED) == 0) { if (za->entry[idx].state == ZIP_ST_DELETED) { _zip_error_set(error, ZIP_ER_DELETED, 0); return NULL; } if (za->entry[idx].ch_filename) return za->entry[idx].ch_filename; } if (za->cdir == NULL || idx >= za->cdir->nentry) { _zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } return za->cdir->entry[idx].filename; }
zip_uint64_t _zip_file_get_offset(const struct zip *za, zip_uint64_t idx, struct zip_error *error) { zip_uint64_t offset; zip_int32_t size; offset = za->entry[idx].orig->offset; if (fseeko(za->zp, (off_t)offset, SEEK_SET) != 0) { _zip_error_set(error, ZIP_ER_SEEK, errno); return 0; } /* TODO: cache? */ if ((size=_zip_dirent_size(za->zp, ZIP_EF_LOCAL, error)) < 0) return 0; if (offset+(zip_uint32_t)size > ZIP_OFF_MAX) { _zip_error_set(error, ZIP_ER_SEEK, EFBIG); return 0; } return offset + (zip_uint32_t)size; }
void * _zip_memdup(const void *mem, size_t len, struct zip_error *error) { void *ret; ret = malloc(len); if (!ret) { _zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } memcpy(ret, mem, len); return ret; }
ZIP_EXTERN int zip_rename(struct zip *za, int idx, const char *name) { const char *old_name; int old_is_dir, new_is_dir; if (idx >= za->nentry || idx < 0 || name[0] == '\0') { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if ((old_name=zip_get_name(za, idx, 0)) == NULL) return -1; new_is_dir = (name[strlen(name)-1] == '/'); old_is_dir = (old_name[strlen(old_name)-1] == '/'); if (new_is_dir != old_is_dir) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } return _zip_set_name(za, idx, name); }
ZIP_EXTERN int zip_delete(struct zip *za, int idx) { if (idx < 0 || idx >= za->nentry) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } /* allow duplicate file names, because the file will * be removed directly afterwards */ if (_zip_unchange(za, idx, 1) != 0) return -1; za->entry[idx].state = ZIP_ST_DELETED; return 0; }
zip_source_function(struct zip *za, zip_source_callback zcb, void *ud) { struct zip_source *zs; if (za == NULL) return NULL; if ((zs=(struct zip_source *)malloc(sizeof(*zs))) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } zs->f = zcb; zs->ud = ud; return zs; }
struct zip_source * _zip_source_new(struct zip *za) { struct zip_source *src; if ((src=(struct zip_source *)malloc(sizeof(*src))) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } src->src = NULL; src->cb.f = NULL; src->ud = NULL; src->error_source = ZIP_LES_NONE; src->is_open = 0; return src; }
ZIP_EXTERN int zip_fseek(struct zip_file *zf, long pos, int whence) { off_t abspos, flen; if (!zf) return -1; if (zf->error.zip_err != 0) return -1; if (pos == 0 && whence == ZIP_SEEK_CUR) return 0; flen = zf->za->cdir->entry[zf->file_index].uncomp_size; switch (whence) { case ZIP_SEEK_CUR: abspos = zf->file_fpos + pos; break; case ZIP_SEEK_SET: abspos = pos; break; case ZIP_SEEK_END: abspos = flen + pos; break; default: /* incorrect/unspecified 'whence' parameter */ _zip_error_set(&zf->error, ZIP_ER_INVAL, 0); return -1; } if (abspos == zf->file_fpos) return 0; /* no change */ if ((zf->flags & ZIP_ZF_DECOMP) == 0) { // file data is not compressed, or file was opened to read compressed data directly return _zip_fseek_bytes(zf, abspos, flen); } else { return _zip_fseek_comp(zf, abspos, flen); } }
ZIP_EXTERN int zip_archive_set_tempdir(struct zip *za, const char *tempdir) { char *new_tempdir; if (tempdir) { if ((new_tempdir = strdup(tempdir)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, errno); return -1; } } else new_tempdir = NULL; free(za->tempdir); za->tempdir = new_tempdir; return 0; }
int _zip_fseek_by_reading(struct zip_file* zf, size_t toread) { char bytes[1024]; while (toread > 0) { ssize_t numRead = zip_fread(zf, bytes, (toread < 1024 ? toread : 1024)); if (numRead < 0 ) return -1; /* error already set */ if (numRead == 0) { /* avoid infinite loops */ _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); return -1; } toread -= numRead; } /* zf has been updated for us by zip_fread() already */ return 0; }
ZIP_EXTERN struct zip_source * zip_source_zip(struct zip *za, struct zip *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len) { if (len < -1) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if (len == -1) len = 0; if (start == 0 && len == 0) flags |= ZIP_FL_COMPRESSED; else flags &= ~ZIP_FL_COMPRESSED; return _zip_source_zip_new(za, srcza, srcidx, flags, start, (zip_uint64_t)len, NULL); }
ZIP_EXTERN const zip_uint8_t * zip_file_extra_field_get_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags) { struct zip_dirent *de; if ((flags & ZIP_EF_BOTH) == 0) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) return NULL; if (flags & ZIP_FL_LOCAL) if (_zip_read_local_ef(za, idx) < 0) return NULL; return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error); }
ZIP_EXTERN const char * zip_get_file_comment(struct zip *za, int idx, int *lenp, int flags) { if (idx < 0 || idx >= za->nentry) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } if ((flags & ZIP_FL_UNCHANGED) || (za->entry[idx].ch_comment_len == -1)) { if (lenp != NULL) *lenp = za->cdir->entry[idx].comment_len; return za->cdir->entry[idx].comment; } if (lenp != NULL) *lenp = za->entry[idx].ch_comment_len; return za->entry[idx].ch_comment; }
unsigned int _zip_file_get_offset(struct zip *za, int idx) { struct zip_dirent de; unsigned int offset; offset = za->cdir->entry[idx].offset; if (fseeko(za->zp, offset, SEEK_SET) != 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return 0; } if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) return 0; offset += LENTRYSIZE + de.filename_len + de.extrafield_len; _zip_dirent_finalize(&de); return offset; }