zip_source_stat(struct zip_source *src, struct zip_stat *st) { zip_int64_t ret; if (st == NULL) { src->error_source = ZIP_LES_INVAL; return -1; } if (src->src == NULL) { if (src->cb.f(src->ud, st, sizeof(*st), ZIP_SOURCE_STAT) < 0) return -1; return 0; } if (zip_source_stat(src->src, st) < 0) { src->error_source = ZIP_LES_LOWER; return -1; } ret = src->cb.l(src->src, src->ud, st, sizeof(*st), ZIP_SOURCE_STAT); if (ret < 0) { if (ret == ZIP_SOURCE_ERR_LOWER) src->error_source = ZIP_LES_LOWER; else src->error_source = ZIP_LES_UPPER; return -1; } return 0; }
ZIP_EXTERN int zip_source_stat(zip_source_t *src, zip_stat_t *st) { if (src->source_closed) { return -1; } if (st == NULL) { zip_error_set(&src->error, ZIP_ER_INVAL, 0); return -1; } zip_stat_init(st); if (ZIP_SOURCE_IS_LAYERED(src)) { if (zip_source_stat(src->src, st) < 0) { _zip_error_set_from_source(&src->error, src->src); return -1; } } if (_zip_source_call(src, st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { return -1; } return 0; }
zip_source_t * zip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) { zip_source_t *s2; int mode = 0; zip_stat_t st; zip_uint64_t aux_length; struct winzip_aes *ctx; switch (em) { case ZIP_EM_AES_128: mode = 1; break; case ZIP_EM_AES_192: mode = 2; break; case ZIP_EM_AES_256: mode = 3; break; } if (password == NULL || src == NULL || mode == 0) { 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 (zip_source_stat(src, &st) != 0) { _zip_error_set_from_source(&za->error, src); return NULL; } aux_length = PWD_VER_LENGTH + salt_length[mode] + HMAC_LENGTH; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) { zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((ctx = winzip_aes_new(mode, password)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return NULL; } ctx->data_length = st.comp_size - aux_length; if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) { winzip_aes_free(ctx); return NULL; } return s2; }
zip_t * _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) { zip_t *za; zip_cdir_t *cdir; struct zip_stat st; zip_uint64_t len; zip_stat_init(&st); if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(error, src); return NULL; } if ((st.valid & ZIP_STAT_SIZE) == 0) { zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP); return NULL; } len = st.size; /* treat empty files as empty archives */ if (len == 0) { if ((za=_zip_allocate_new(src, flags, error)) == NULL) { zip_source_free(src); return NULL; } return za; } if ((za=_zip_allocate_new(src, flags, error)) == NULL) { return NULL; } if ((cdir = _zip_find_central_dir(za, len)) == NULL) { _zip_error_copy(error, &za->error); /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } za->entry = cdir->entry; za->nentry = cdir->nentry; za->nentry_alloc = cdir->nentry_alloc; za->comment_orig = cdir->comment; za->ch_flags = za->flags; free(cdir); return za; }
/* * tests for file existence */ static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error) { struct zip_stat st; zip_stat_init(&st); if (zip_source_stat(src, &st) != 0) { zip_error_t *src_error = zip_source_error(src); if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) { return EXISTS_NOT; } _zip_error_copy(error, src_error); return EXISTS_ERROR; } return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY; }
int main() { zip_source_t *zsrc = loadFromFile(); if (!zsrc) return 1; fprintf(stderr, "zip_open_from_source...\n"); zip_error_t error; zip_error_init(&error); zip_t *archive = zip_open_from_source(zsrc, 0, &error); if (!archive) return 2; zip_error_fini(&error); show(archive, "after zip_open_from_source"); const char *name = "y.txt"; zip_flags_t flags = 0; zip_source_t *otherZsrc = zip_source_buffer_create("hello", 5, 0, &error); fprintf(stderr, "zip_file_add...\n"); zip_int64_t i = zip_file_add(archive, name, otherZsrc, flags); fprintf(stderr, "zip_file_add(): i=%lld\n", i); // show(archive, "after zip_file_add"); zip_source_keep(zsrc); int ret; ret = zip_close(archive); // print to stdout zip_stat_t zst; ret = zip_source_stat(zsrc, &zst); fprintf(stderr, "zip_source_stat: ret=%d, zst.size=%d\n", ret, zst.size); ret = zip_source_open(zsrc); fprintf(stderr, "zip_source_open: ret=%d\n", ret); unsigned char data[10000]; zip_uint64_t n = zip_source_read(zsrc, data, sizeof(data)); fprintf(stderr, "zip_source_read: n=%d\n", n); write(1, data, n); // print to stdout }
static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) { zip_int64_t offstart, offdata, offend; struct zip_stat st; zip_source_t *s2; int ret; int is_zip64; zip_flags_t flags; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&za->error, src); return -1; } if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { st.valid |= ZIP_STAT_COMP_METHOD; st.comp_method = ZIP_CM_STORE; } if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) de->comp_method = st.comp_method; else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { st.valid |= ZIP_STAT_COMP_SIZE; st.comp_size = st.size; } else { /* we'll recompress */ st.valid &= ~ZIP_STAT_COMP_SIZE; } flags = ZIP_EF_LOCAL; if ((st.valid & ZIP_STAT_SIZE) == 0) flags |= ZIP_FL_FORCE_ZIP64; else { de->uncomp_size = st.size; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32) || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method)))) flags |= ZIP_FL_FORCE_ZIP64; } else de->comp_size = st.comp_size; } if ((offstart = zip_source_tell_write(za->src)) < 0) { return -1; } /* as long as we don't support non-seekable output, clear data descriptor bit */ de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) return -1; if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) { zip_source_t *s_store, *s_crc; zip_compression_implementation comp_impl; if (st.comp_method != ZIP_CM_STORE) { if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) { zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return -1; } if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) { /* error set by comp_impl */ return -1; } } else { /* to have the same reference count to src as in the case where it's not stored */ zip_source_keep(src); s_store = src; } s_crc = zip_source_crc(za, s_store, 0); zip_source_free(s_store); if (s_crc == NULL) { return -1; } if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) { zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); zip_source_free(s_crc); return -1; } s2 = comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE); zip_source_free(s_crc); if (s2 == NULL) { return -1; } } else { s2 = s_crc; } } else { zip_source_keep(src); s2 = src; } if ((offdata = zip_source_tell_write(za->src)) < 0) { return -1; } ret = copy_source(za, s2); if (zip_source_stat(s2, &st) < 0) ret = -1; zip_source_free(s2); if (ret < 0) return -1; if ((offend = zip_source_tell_write(za->src)) < 0) { return -1; } if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) { _zip_error_set_from_source(&za->error, za->src); return -1; } if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) { if (st.valid & ZIP_STAT_MTIME) de->last_mod = st.mtime; else time(&de->last_mod); } de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = (zip_uint64_t)(offend - offdata); if ((ret=_zip_dirent_write(za, de, flags)) < 0) return -1; if (is_zip64 != ret) { /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { _zip_error_set_from_source(&za->error, za->src); return -1; } return 0; }
static int add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, FILE *ft) { off_t offstart, offdata, offend; struct zip_stat st; struct zip_source *s2; int ret; int is_zip64; zip_flags_t flags; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&za->error, src); return -1; } if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { st.valid |= ZIP_STAT_COMP_METHOD; st.comp_method = ZIP_CM_STORE; } if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) de->comp_method = st.comp_method; else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { st.valid |= ZIP_STAT_COMP_SIZE; st.comp_size = st.size; } else { /* we'll recompress */ st.valid &= ~ZIP_STAT_COMP_SIZE; } flags = ZIP_EF_LOCAL; if ((st.valid & ZIP_STAT_SIZE) == 0) flags |= ZIP_FL_FORCE_ZIP64; else { de->uncomp_size = st.size; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32) || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method)))) flags |= ZIP_FL_FORCE_ZIP64; } else de->comp_size = st.comp_size; } offstart = ftello(ft); /* as long as we don't support non-seekable output, clear data descriptor bit */ de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; if ((is_zip64=_zip_dirent_write(de, ft, flags, &za->error)) < 0) return -1; if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) { struct zip_source *s_store, *s_crc; zip_compression_implementation comp_impl; if (st.comp_method != ZIP_CM_STORE) { if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) { _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return -1; } if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) { /* error set by comp_impl */ return -1; } } else s_store = src; if ((s_crc=zip_source_crc(za, s_store, 0)) == NULL) { if (s_store != src) zip_source_pop(s_store); return -1; } /* TODO: deflate 0-byte files for torrentzip? */ if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) { _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); zip_source_pop(s_crc); if (s_store != src) zip_source_pop(s_store); return -1; } if ((s2=comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE)) == NULL) { zip_source_pop(s_crc); if (s_store != src) zip_source_pop(s_store); return -1; } } else s2 = s_crc; } else s2 = src; offdata = ftello(ft); ret = copy_source(za, s2, ft); if (zip_source_stat(s2, &st) < 0) ret = -1; while (s2 != src) { if ((s2=zip_source_pop(s2)) == NULL) { /* TODO: set erorr */ ret = -1; break; } } if (ret < 0) return -1; offend = ftello(ft); if (fseeko(ft, offstart, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) { _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if (st.valid & ZIP_STAT_MTIME) de->last_mod = st.mtime; else time(&de->last_mod); de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = (zip_uint64_t)(offend - offdata); if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) _zip_dirent_torrent_normalize(de); if ((ret=_zip_dirent_write(de, ft, flags, &za->error)) < 0) return -1; if (is_zip64 != ret) { /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if (fseeko(ft, offend, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } return 0; }
zip_t * _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) { zip_t *za; zip_cdir_t *cdir; struct zip_stat st; zip_uint64_t len, idx; zip_stat_init(&st); if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(error, src); return NULL; } if ((st.valid & ZIP_STAT_SIZE) == 0) { zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP); return NULL; } len = st.size; /* treat empty files as empty archives */ if (len == 0) { if ((za=_zip_allocate_new(src, flags, error)) == NULL) { zip_source_free(src); return NULL; } return za; } if ((za=_zip_allocate_new(src, flags, error)) == NULL) { return NULL; } if ((cdir = _zip_find_central_dir(za, len)) == NULL) { _zip_error_copy(error, &za->error); /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } za->entry = cdir->entry; za->nentry = cdir->nentry; za->nentry_alloc = cdir->nentry_alloc; za->comment_orig = cdir->comment; free(cdir); _zip_hash_reserve_capacity(za->names, za->nentry, &za->error); for (idx = 0; idx < za->nentry; idx++) { const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error); if (name == NULL) { /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) { if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) { _zip_error_copy(error, &za->error); /* keep src so discard does not get rid of it */ zip_source_keep(src); zip_discard(za); return NULL; } } } za->ch_flags = za->flags; return za; }
static int add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, FILE *ft) { off_t offstart, offdata, offend; struct zip_stat st; struct zip_source *s2; zip_compression_implementation comp_impl; int ret; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&za->error, src); return -1; } offstart = ftello(ft); if (_zip_dirent_write(de, ft, 1, &za->error) < 0) return -1; if ((s2=zip_source_crc(za, src, 0)) == NULL) { zip_source_pop(s2); return -1; } /* XXX: deflate 0-byte files for torrentzip? */ if (((st.valid & ZIP_STAT_COMP_METHOD) == 0 || st.comp_method == ZIP_CM_STORE) && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { comp_impl = NULL; if ((comp_impl=zip_get_compression_implementation(ZIP_CM_DEFLATE)) == NULL) { _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); zip_source_pop(s2); return -1; } if ((s2=comp_impl(za, s2, ZIP_CM_DEFLATE, ZIP_CODEC_ENCODE)) == NULL) { /* XXX: set error? */ zip_source_pop(s2); return -1; } } else s2 = src; offdata = ftello(ft); ret = copy_source(za, s2, ft); if (zip_source_stat(s2, &st) < 0) ret = -1; while (s2 != src) { if ((s2=zip_source_pop(s2)) == NULL) { /* XXX: set erorr */ ret = -1; break; } } if (ret < 0) return -1; offend = ftello(ft); if (fseeko(ft, offstart, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } de->last_mod = st.mtime; de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = offend - offdata; if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) _zip_dirent_torrent_normalize(de); if (_zip_dirent_write(de, ft, 1, &za->error) < 0) return -1; if (fseeko(ft, offend, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } return 0; }
static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct crc_context *ctx; zip_int64_t n; ctx = (struct crc_context *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->position = 0; return 0; case ZIP_SOURCE_READ: if ((n = zip_source_read(src, data, len)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if (n == 0) { if (ctx->crc_position == ctx->position) { ctx->crc_complete = 1; ctx->size = ctx->position; if (ctx->validate) { struct zip_stat st; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { zip_error_set(&ctx->error, ZIP_ER_CRC, 0); return -1; } if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { zip_error_set(&ctx->error, ZIP_ER_INCONS, 0); return -1; } } } } else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) { zip_uint64_t i, nn; for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) { nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n-i); ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data+i, (uInt)nn); ctx->crc_position += nn; } } ctx->position += (zip_uint64_t)n; return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->crc_complete) { /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_SIZE|ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;; } return 0; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_SUPPORTS: { zip_int64_t mask = zip_source_supports(src); if (mask < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1); } case ZIP_SOURCE_SEEK: { zip_int64_t new_position; zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); if (args == NULL) { return -1; } if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } ctx->position = (zip_uint64_t)new_position; return 0; } case ZIP_SOURCE_TELL: return (zip_int64_t)ctx->position; default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } }
static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) { zip_int64_t offstart, offdata, offend; struct zip_stat st; zip_source_t *src_final, *src_tmp; int ret; int is_zip64; zip_flags_t flags; bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&za->error, src); return -1; } if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { st.valid |= ZIP_STAT_COMP_METHOD; st.comp_method = ZIP_CM_STORE; } if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) de->comp_method = st.comp_method; else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { st.valid |= ZIP_STAT_COMP_SIZE; st.comp_size = st.size; } else { /* we'll recompress */ st.valid &= ~ZIP_STAT_COMP_SIZE; } if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) { st.valid |= ZIP_STAT_ENCRYPTION_METHOD; st.encryption_method = ZIP_EM_NONE; } flags = ZIP_EF_LOCAL; if ((st.valid & ZIP_STAT_SIZE) == 0) flags |= ZIP_FL_FORCE_ZIP64; else { de->uncomp_size = st.size; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32) || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method)))) flags |= ZIP_FL_FORCE_ZIP64; } else de->comp_size = st.comp_size; } if ((offstart = zip_source_tell_write(za->src)) < 0) { return -1; } /* as long as we don't support non-seekable output, clear data descriptor bit */ de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) return -1; needs_recompress = !((st.comp_method == de->comp_method) || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method == ZIP_CM_DEFLATE)); needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE); needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress; needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE); needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method); needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE); needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE); src_final = src; zip_source_keep(src_final); if (needs_decrypt) { zip_encryption_implementation impl; if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); zip_source_free(src_final); return -1; } if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) { /* error set by impl */ zip_source_free(src_final); return -1; } zip_source_free(src_final); src_final = src_tmp; } if (needs_decompress) { zip_compression_implementation comp_impl; if ((comp_impl = _zip_get_compression_implementation(st.comp_method, ZIP_CODEC_DECODE)) == NULL) { zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); zip_source_free(src_final); return -1; } if ((src_tmp = comp_impl(za, src_final, st.comp_method, ZIP_CODEC_DECODE)) == NULL) { /* error set by comp_impl */ zip_source_free(src_final); return -1; } zip_source_free(src_final); src_final = src_tmp; } if (needs_crc) { if ((src_tmp = zip_source_crc(za, src_final, 0)) == NULL) { zip_source_free(src_final); return -1; } zip_source_free(src_final); src_final = src_tmp; } if (needs_compress) { zip_compression_implementation comp_impl; if ((comp_impl = _zip_get_compression_implementation(de->comp_method, ZIP_CODEC_ENCODE)) == NULL) { zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); zip_source_free(src_final); return -1; } if ((src_tmp = comp_impl(za, src_final, de->comp_method, ZIP_CODEC_ENCODE)) == NULL) { zip_source_free(src_final); return -1; } zip_source_free(src_final); src_final = src_tmp; } if (needs_encrypt) { zip_encryption_implementation impl; const char *password = NULL; if (de->password) { password = de->password; } else if (za->default_password) { password = za->default_password; } if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) { zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); zip_source_free(src_final); return -1; } if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) { /* error set by impl */ zip_source_free(src_final); return -1; } zip_source_free(src_final); src_final = src_tmp; } if ((offdata = zip_source_tell_write(za->src)) < 0) { return -1; } ret = copy_source(za, src_final); if (zip_source_stat(src_final, &st) < 0) { ret = -1; } zip_source_free(src_final); if (ret < 0) { return -1; } if ((offend = zip_source_tell_write(za->src)) < 0) { return -1; } if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) { _zip_error_set_from_source(&za->error, za->src); return -1; } if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) { if (st.valid & ZIP_STAT_MTIME) de->last_mod = st.mtime; else time(&de->last_mod); } de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = (zip_uint64_t)(offend - offdata); if ((ret=_zip_dirent_write(za, de, flags)) < 0) return -1; if (is_zip64 != ret) { /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { _zip_error_set_from_source(&za->error, za->src); return -1; } return 0; }
static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct crc_context *ctx; zip_int64_t n; ctx = (struct crc_context *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->eof = 0; ctx->crc = (zip_uint32_t)crc32(0, NULL, 0); ctx->size = 0; return 0; case ZIP_SOURCE_READ: if (ctx->eof || len == 0) return 0; if ((n=zip_source_read(src, data, len)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if (n == 0) { ctx->eof = 1; if (ctx->validate) { struct zip_stat st; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { zip_error_set(&ctx->error, ZIP_ER_CRC, 0); return -1; } if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { zip_error_set(&ctx->error, ZIP_ER_INCONS, 0); return -1; } } } else { zip_uint64_t i, nn; for (i=0; i < (zip_uint64_t)n; i += nn) { nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n-i); ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data+i, (uInt)nn); } ctx->size += (zip_uint64_t)n; } return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->eof) { /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_SIZE|ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;; } return 0; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_SUPPORTS: return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1); default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } }