Example #1
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 *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;
}
Example #2
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;
}