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(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; }