Beispiel #1
0
static int
copy_source(struct zip *za, struct zip_source *src, FILE *ft)
{
    char buf[BUFSIZE];
    zip_int64_t n;
    int ret;

    if (zip_source_open(src) < 0) {
	_zip_error_set_from_source(&za->error, src);
	return -1;
    }

    ret = 0;
    while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) {
	if (fwrite(buf, 1, (size_t)n, ft) != (size_t)n) {
	    _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
	    ret = -1;
	    break;
	}
    }
    
    if (n < 0) {
	if (ret == 0)
	    _zip_error_set_from_source(&za->error, src);
	ret = -1;
    }	

    zip_source_close(src);
    
    return ret;
}
Beispiel #2
0
static int
copy_source(zip_t *za, zip_source_t *src)
{
    zip_uint8_t buf[BUFSIZE];
    zip_int64_t n;
    int ret;

    if (zip_source_open(src) < 0) {
	_zip_error_set_from_source(&za->error, src);
	return -1;
    }

    ret = 0;
    while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) {
	if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
	    ret = -1;
	    break;
	}
    }
    
    if (n < 0) {
	_zip_error_set_from_source(&za->error, src);
	ret = -1;
    }

    zip_source_close(src);
    
    return ret;
}
static int
decrypt_header(zip_source_t *src, struct winzip_aes *ctx)
{
    zip_uint8_t header[MAX_HEADER_LENGTH];
    zip_uint8_t password_verification[PWD_VER_LENGTH];
    zip_uint8_t headerlen;
    zip_int64_t n;

    headerlen = PWD_VER_LENGTH + salt_length[ctx->mode];
    if ((n=zip_source_read(src, header, headerlen)) < 0) {
	_zip_error_set_from_source(&ctx->error, src);
	return -1;
    }
    
    if (n != headerlen) {
	zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
	return -1;
    }

    if (_zip_fcrypt_init(ctx->mode, ctx->password, strlen(ctx->password), header, password_verification, &ctx->fcrypt_ctx) != 0) {
	zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
	return -1;
    }
    if (memcmp(password_verification, header + salt_length[ctx->mode], PWD_VER_LENGTH) != 0) {
	zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);
	return -1;
    }
    return 0;
}
Beispiel #4
0
zip_fread(struct zip_file *zf, void *outbuf, zip_uint64_t toread)
{
    zip_int64_t n;

    if (!zf)
	return -1;

    if (zf->error.zip_err != 0)
	return -1;

    if (toread > ZIP_INT64_MAX) {
	_zip_error_set(&zf->error, ZIP_ER_INVAL, 0);
	return -1;
    }

    if ((zf->eof) || (toread == 0))
	return 0;

    if ((n=zip_source_read(zf->src, outbuf, toread)) < 0) {
	_zip_error_set_from_source(&zf->error, zf->src);
	return -1;
    }

    return n;
}
ZIP_EXTERN struct zip_file *
zip_fopen_index_encrypted(struct zip *za, zip_uint64_t index, zip_flags_t flags,
			  const char *password)
{
    struct zip_file *zf;
    struct zip_source *src;

    if ((src=_zip_source_zip_new(za, za, index, flags, 0, 0, password)) == NULL)
	return NULL;

    if (zip_source_open(src) < 0) {
	_zip_error_set_from_source(&za->error, src);
	zip_source_free(src);
	return NULL;
    }

    if ((zf=_zip_file_new(za)) == NULL) {
	zip_source_free(src);
	return NULL;
    }

    zf->src = src;

    return zf;
}
Beispiel #6
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;
}
Beispiel #7
0
static zip_int64_t
_zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error)
{
    zip_uint64_t i;
    zip_uint64_t min, max, j;
    struct zip_dirent temp;

    _zip_dirent_init(&temp);
    if (cd->nentry) {
	max = cd->entry[0].orig->offset;
	min = cd->entry[0].orig->offset;
    }
    else
	min = max = 0;

    for (i=0; i<cd->nentry; i++) {
	if (cd->entry[i].orig->offset < min)
	    min = cd->entry[i].orig->offset;
	if (min > (zip_uint64_t)cd->offset) {
	    zip_error_set(error, ZIP_ER_NOZIP, 0);
	    return -1;
	}

	j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
	    + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
	if (j > max)
	    max = j;
	if (max > (zip_uint64_t)cd->offset) {
	    zip_error_set(error, ZIP_ER_NOZIP, 0);
	    return -1;
	}

        if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {
            _zip_error_set_from_source(error, za->src);
            return -1;
	}

	if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) {
	    _zip_dirent_finalize(&temp);
	    return -1;
	}

	if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
	    zip_error_set(error, ZIP_ER_INCONS, 0);
	    _zip_dirent_finalize(&temp);
	    return -1;
	}

	cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
	cd->entry[i].orig->local_extra_fields_read = 1;
	temp.extra_fields = NULL;

	_zip_dirent_finalize(&temp);
    }

    return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
}
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;
}
Beispiel #9
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;

    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;
}
int
_zip_filerange_crc(zip_source_t *src, zip_uint64_t start, zip_uint64_t len, uLong *crcp, zip_error_t *error)
{
    Bytef buf[BUFSIZE];
    zip_int64_t n;

    *crcp = crc32(0L, Z_NULL, 0);

    if (start > ZIP_INT64_MAX) {
	zip_error_set(error, ZIP_ER_SEEK, EFBIG);
	return -1;
    }

    if (zip_source_seek(src, (zip_int64_t)start, SEEK_SET) != 0) {
	_zip_error_set_from_source(error, src);
	return -1;
    }
    
    while (len > 0) {
	n = (zip_int64_t)(len > BUFSIZE ? BUFSIZE : len);
	if ((n = zip_source_read(src, buf, (zip_uint64_t)n)) < 0) {
	    _zip_error_set_from_source(error, src);
	    return -1;
	}
	if (n == 0) {
	    zip_error_set(error, ZIP_ER_EOF, 0);
	    return -1;
	}

	*crcp = crc32(*crcp, buf, (uInt)n);

	len -= (zip_uint64_t)n;
    }

    return 0;
}
Beispiel #11
0
int
_zip_write(zip_t *za, const void *data, zip_uint64_t length)
{
    zip_int64_t n;
    
    if ((n = zip_source_write(za->src, data, length)) < 0) {
        _zip_error_set_from_source(&za->error, za->src);
        return -1;
    }
    if ((zip_uint64_t)n != length) {
        zip_error_set(&za->error, ZIP_ER_WRITE, EINTR);
        return -1;
    }
    
    return 0;
}
static bool
verify_hmac(zip_source_t *src, struct winzip_aes *ctx)
{
    unsigned char computed[HMAC_LENGTH], from_file[HMAC_LENGTH];
    if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) {
	_zip_error_set_from_source(&ctx->error, src);
	return false;
    }

    _zip_fcrypt_end(computed, &ctx->fcrypt_ctx);
    
    if (memcmp(from_file, computed, HMAC_LENGTH) != 0) {
	zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
	return false;
    }

    return true;
}
Beispiel #13
0
ZIP_EXTERN int
zip_source_open(zip_source_t *src) {
    if (src->source_closed) {
	return -1;
    }
    if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) {
	zip_error_set(&src->error, ZIP_ER_DELETED, 0);
	return -1;
    }

    if (ZIP_SOURCE_IS_OPEN_READING(src)) {
	if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) == 0) {
	    zip_error_set(&src->error, ZIP_ER_INUSE, 0);
	    return -1;
	}
    }
    else {
	if (ZIP_SOURCE_IS_LAYERED(src)) {
	    if (zip_source_open(src->src) < 0) {
		_zip_error_set_from_source(&src->error, src->src);
		return -1;
	    }
	}

	if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) {
	    if (ZIP_SOURCE_IS_LAYERED(src)) {
		zip_source_close(src->src);
	    }
	    return -1;
	}
    }

    src->eof = false;
    src->had_read_error = false;
    _zip_error_clear(&src->error);
    src->open_count++;

    return 0;
}
Beispiel #14
0
int
_zip_read(zip_source_t *src, zip_uint8_t *b, zip_uint64_t length, zip_error_t *error)
{
    zip_int64_t n;

    if (length > ZIP_INT64_MAX) {
	zip_error_set(error, ZIP_ER_INTERNAL, 0);
	return -1;
    }

    if ((n = zip_source_read(src, b, length)) < 0) {
	_zip_error_set_from_source(error, src);
	return -1;
    }

    if (n < (zip_int64_t)length) {
	zip_error_set(error, ZIP_ER_EOF, 0);
	return -1;
    }

    return 0;
}
Beispiel #15
0
zip_uint64_t
_zip_file_get_offset(const zip_t *za, zip_uint64_t idx, zip_error_t *error)
{
    zip_uint64_t offset;
    zip_int32_t size;

    offset = za->entry[idx].orig->offset;

    if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {
	_zip_error_set_from_source(error, za->src);
	return 0;
    }

    /* TODO: cache? */
    if ((size=_zip_dirent_size(za->src, ZIP_EF_LOCAL, error)) < 0)
	return 0;

    if (offset+(zip_uint32_t)size > ZIP_INT64_MAX) {
        zip_error_set(error, ZIP_ER_SEEK, EFBIG);
        return 0;
    }
    
    return offset + (zip_uint32_t)size;
}
Beispiel #16
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;
}
Beispiel #17
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;
}
Beispiel #18
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;
}
Beispiel #19
0
static zip_cdir_t *
_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error)
{
    zip_cdir_t *cd;
    zip_uint16_t comment_len;
    zip_uint64_t i, left;
    zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);
    zip_buffer_t *cd_buffer;

    if (_zip_buffer_left(buffer) < EOCDLEN) {
	/* not enough bytes left for comment */
	zip_error_set(error, ZIP_ER_NOZIP, 0);
	return NULL;
    }

    /* check for end-of-central-dir magic */
    if (memcmp(_zip_buffer_get(buffer, 4), EOCD_MAGIC, 4) != 0) {
	zip_error_set(error, ZIP_ER_NOZIP, 0);
	return NULL;
    }

    if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {
        _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);
        cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error);
    }
    else {
        _zip_buffer_set_offset(buffer, eocd_offset);
        cd = _zip_read_eocd(buffer, buf_offset, za->flags, error);
    }

    if (cd == NULL)
	return NULL;

    _zip_buffer_set_offset(buffer, eocd_offset + 20);
    comment_len = _zip_buffer_get_16(buffer);

    if (cd->offset + cd->size > buf_offset + eocd_offset) {
	/* cdir spans past EOCD record */
	zip_error_set(error, ZIP_ER_INCONS, 0);
	_zip_cdir_free(cd);
	return NULL;
    }

    if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
        zip_uint64_t tail_len;

        _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
        tail_len = _zip_buffer_left(buffer);

        if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
            zip_error_set(error, ZIP_ER_INCONS, 0);
            _zip_cdir_free(cd);
            return NULL;
        }

        if (comment_len) {
            if ((cd->comment=_zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
                _zip_cdir_free(cd);
                return NULL;
            }
        }
    }

    if (cd->offset >= buf_offset) {
        zip_uint8_t *data;
	/* if buffer already read in, use it */
        _zip_buffer_set_offset(buffer, cd->offset - buf_offset);

        if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
            zip_error_set(error, ZIP_ER_INCONS, 0);
            _zip_cdir_free(cd);
            return NULL;
        }
        if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
            zip_error_set(error, ZIP_ER_MEMORY, 0);
            _zip_cdir_free(cd);
            return NULL;
        }
    }
    else {
        cd_buffer = NULL;

        if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
            _zip_error_set_from_source(error, za->src);
            _zip_cdir_free(cd);
            return NULL;
        }

	/* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */
	if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {
            zip_error_set(error, ZIP_ER_NOZIP, 0);
	    _zip_cdir_free(cd);
	    return NULL;
	}
    }

    left = (zip_uint64_t)cd->size;
    i=0;
    while (left > 0) {
	bool grown = false;
        zip_int64_t entry_size;

	if (i == cd->nentry) {
	    /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */
	    /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */

	    if (cd->is_zip64 || left < CDENTRYSIZE) {
		break;
	    }

	    if (!_zip_cdir_grow(cd, 0x10000, error)) {
		_zip_cdir_free(cd);
		_zip_buffer_free(cd_buffer);
		return NULL;
	    }
	    grown = true;
	}

	if ((cd->entry[i].orig=_zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, error)) < 0) {
	    if (grown && zip_error_code_zip(error) == ZIP_ER_NOZIP) {
		zip_error_set(error, ZIP_ER_INCONS, 0);
	    }
	    _zip_cdir_free(cd);
            _zip_buffer_free(cd_buffer);
	    return NULL;
	}
	i++;
        left -= (zip_uint64_t)entry_size;
    }

    if (i != cd->nentry || left > 0) {
        zip_error_set(error, ZIP_ER_INCONS, 0);
        _zip_buffer_free(cd_buffer);
        _zip_cdir_free(cd);
        return NULL;
    }

    if (za->open_flags & ZIP_CHECKCONS) {
        bool ok;

        if (cd_buffer) {
            ok = _zip_buffer_eof(cd_buffer);
        }
        else {
            zip_int64_t offset = zip_source_tell(za->src);

            if (offset < 0) {
                _zip_error_set_from_source(error, za->src);
                _zip_cdir_free(cd);
                return NULL;
            }
            ok = ((zip_uint64_t)offset == cd->offset + cd->size);
        }

        if (!ok) {
            zip_error_set(error, ZIP_ER_INCONS, 0);
            _zip_buffer_free(cd_buffer);
            _zip_cdir_free(cd);
            return NULL;
        }
    }

    _zip_buffer_free(cd_buffer);
    return cd;
}
static zip_int64_t
compress_read(zip_source_t *src, struct deflate *ctx, void *data, zip_uint64_t len)
{
    int end, ret;
    zip_int64_t n;
    zip_uint64_t out_offset;
    uInt out_len;

    if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK)
	return -1;
    
    if (len == 0 || ctx->is_stored) {
	return 0;
    }
	
    out_offset = 0;
    out_len = (uInt)ZIP_MIN(UINT_MAX, len);
    ctx->zstr.next_out = (Bytef *)data;
    ctx->zstr.avail_out = out_len;

    end = 0;
    while (!end) {
	ret = deflate(&ctx->zstr, ctx->eof ? Z_FINISH : 0);

	switch (ret) {
        case Z_STREAM_END:
            if (ctx->can_store && ctx->zstr.total_in <= ctx->zstr.total_out) {
                ctx->is_stored = true;
                ctx->size = ctx->zstr.total_in;
                memcpy(data, ctx->buffer, ctx->size);
                return (zip_int64_t)ctx->size;
            }
            /* fallthrough */
	case Z_OK:
	    /* all ok */

	    if (ctx->zstr.avail_out == 0) {
		out_offset += out_len;
		if (out_offset < len) {
		    out_len = (uInt)ZIP_MIN(UINT_MAX, len-out_offset);
		    ctx->zstr.next_out = (Bytef *)data+out_offset;
		    ctx->zstr.avail_out = out_len;
		}
		else {
                    ctx->can_store = false;
		    end = 1;
		}
	    }
	    else if (ctx->eof && ctx->zstr.avail_in == 0)
		end = 1;
	    break;

	case Z_BUF_ERROR:
	    if (ctx->zstr.avail_in == 0) {
		if (ctx->eof) {
		    end = 1;
		    break;
		}

		if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
                    _zip_error_set_from_source(&ctx->error, src);
		    end = 1;
		    break;
		}
		else if (n == 0) {
		    ctx->eof = true;
		    /* TODO: check against stat of src? */
		    ctx->size = ctx->zstr.total_in;
		}
		else {
                    if (ctx->zstr.total_in > 0) {
                        /* we overwrote a previously filled ctx->buffer */
                        ctx->can_store = false;
                    }
		    ctx->zstr.next_in = (Bytef *)ctx->buffer;
		    ctx->zstr.avail_in = (uInt)n;
		}
		continue;
	    }
	    /* fallthrough */
	case Z_NEED_DICT:
	case Z_DATA_ERROR:
	case Z_STREAM_ERROR:
	case Z_MEM_ERROR:
            zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);

	    end = 1;
	    break;
	}
    }

    if (ctx->zstr.avail_out < len) {
	ctx->can_store = false;
	return (zip_int64_t)(len - ctx->zstr.avail_out);
    }

    return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
}
Beispiel #21
0
ZIP_EXTERN zip_t *
zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error)
{
    static zip_int64_t needed_support_read = -1;
    static zip_int64_t needed_support_write = -1;

    unsigned int flags;
    zip_int64_t supported;
    exists_t exists;

    if (_flags < 0 || src == NULL) {
	zip_error_set(error, ZIP_ER_INVAL, 0);
        return NULL;
    }
    flags = (unsigned int)_flags;

    supported = zip_source_supports(src);
    if (needed_support_read == -1) {
        needed_support_read = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_STAT, -1);
        needed_support_write = 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);
    }
    if ((supported & needed_support_read) != needed_support_read) {
        zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
        return NULL;
    }
    if ((supported & needed_support_write) != needed_support_write) {
        flags |= ZIP_RDONLY;
    }

    if ((flags & (ZIP_RDONLY|ZIP_TRUNCATE)) == (ZIP_RDONLY|ZIP_TRUNCATE)) {
	zip_error_set(error, ZIP_ER_RDONLY, 0);
	return NULL;
    }

    exists = _zip_file_exists(src, error);
    switch (exists) {
    case EXISTS_ERROR:
	return NULL;

    case EXISTS_NOT:
	if ((flags & ZIP_CREATE) == 0) {
	    zip_error_set(error, ZIP_ER_NOENT, 0);
	    return NULL;
	}
	return _zip_allocate_new(src, flags, error);

    default: {
	zip_t *za;
	if (flags & ZIP_EXCL) {
	    zip_error_set(error, ZIP_ER_EXISTS, 0);
	    return NULL;
	}
	if (zip_source_open(src) < 0) {
	    _zip_error_set_from_source(error, src);
	    return NULL;
	}

	if (flags & ZIP_TRUNCATE) {
	    za = _zip_allocate_new(src, flags, error);
	}
	else {
	    /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */
	    za = _zip_open(src, flags, error);
	}

	if (za == NULL) {
	    zip_source_close(src);
	    return NULL;
	}
	return za;
    }
    }
}
static zip_int64_t
decompress_read(zip_source_t *src, struct deflate *ctx, void *data, zip_uint64_t len)
{
    int end, ret;
    zip_int64_t n;
    zip_uint64_t out_offset;
    uInt out_len;

    if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK)
	return -1;
    
    if (len == 0)
	return 0;

    out_offset = 0;
    out_len = (uInt)ZIP_MIN(UINT_MAX, len);
    ctx->zstr.next_out = (Bytef *)data;
    ctx->zstr.avail_out = out_len;

    end = 0;
    while (!end) {
	ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);

	switch (ret) {
	case Z_OK:
	    if (ctx->zstr.avail_out == 0) {
		out_offset += out_len;
		if (out_offset < len) {
		    out_len = (uInt)ZIP_MIN(UINT_MAX, len-out_offset);
		    ctx->zstr.next_out = (Bytef *)data+out_offset;
		    ctx->zstr.avail_out = out_len;
		}
		else {
		    end = 1;
		}
	    }
	    break;
	    
	case Z_STREAM_END:
	    ctx->eof = 1;
	    end = 1;
	    break;

	case Z_BUF_ERROR:
	    if (ctx->zstr.avail_in == 0) {
		if (ctx->eof) {
		    end = 1;
		    break;
		}

		if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
                    _zip_error_set_from_source(&ctx->error, src);
		    end = 1;
		    break;
		}
		else if (n == 0) {
		    ctx->eof = 1;
		}
		else {
		    ctx->zstr.next_in = (Bytef *)ctx->buffer;
		    ctx->zstr.avail_in = (uInt)n;
		}
		continue;
	    }
	    /* fallthrough */
	case Z_NEED_DICT:
	case Z_DATA_ERROR:
	case Z_STREAM_ERROR:
	case Z_MEM_ERROR:
            zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);
	    end = 1;
	    break;
	}
    }

    if (ctx->zstr.avail_out < len)
	return (zip_int64_t)(len - ctx->zstr.avail_out);

    return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
}
Beispiel #23
0
zip_fopen_index_encrypted(struct zip *za, zip_uint64_t fileno, int flags,
			  const char *password)
{
    struct zip_file *zf;
    zip_compression_implementation comp_impl;
    zip_encryption_implementation enc_impl;
    struct zip_source *src, *s2;
    zip_uint64_t start;
    struct zip_stat st;

    if (fileno >= za->nentry) {
	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
	return NULL;
    }

    if ((flags & ZIP_FL_UNCHANGED) == 0
	&& ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) {
	_zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
	return NULL;
    }

    if (fileno >= za->cdir->nentry) {
	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
	return NULL;
    }

    if (flags & ZIP_FL_ENCRYPTED)
	flags |= ZIP_FL_COMPRESSED;

    zip_stat_index(za, fileno, flags, &st);

    enc_impl = NULL;
    if ((flags & ZIP_FL_ENCRYPTED) == 0) {
	if (st.encryption_method != ZIP_EM_NONE) {
	    if (password == NULL) {
		_zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
		return NULL;
	    }
	    if ((enc_impl=zip_get_encryption_implementation(
		     st.encryption_method)) == NULL) {
		_zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
		return NULL;
	    }
	}
    }

    comp_impl = NULL;
    if ((flags & ZIP_FL_COMPRESSED) == 0) {
	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 NULL;
	    }
	}
    }

    if ((start=_zip_file_get_offset(za, fileno)) == 0)
	return NULL;

    if (st.comp_size == 0) {
	if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL)
	    return NULL;
    }
    else {
	if ((src=_zip_source_file_or_p(za, NULL, za->zp, start, st.comp_size,
				       0, &st)) == NULL)
	    return NULL;
	if (enc_impl) {
	    if ((s2=enc_impl(za, src, ZIP_EM_TRAD_PKWARE, 0,
			     password)) == NULL) {
		zip_source_free(src);
		/* XXX: set error (how?) */
		return NULL;
	    }
	    src = s2;
	}
	if (comp_impl) {
	    if ((s2=comp_impl(za, src, za->cdir->entry[fileno].comp_method,
			      0)) == NULL) {
		zip_source_free(src);
		/* XXX: set error (how?) */
		return NULL;
	    }
	    src = s2;
	}
	if ((flags & ZIP_FL_COMPRESSED) == 0
	    || st.comp_method == ZIP_CM_STORE ) {
	    if ((s2=zip_source_crc(za, src, 1)) == NULL) {
		zip_source_free(src);
		/* XXX: set error (how?) */
		return NULL;
	    }
	    src = s2;
	}
    }

    if (zip_source_open(src) < 0) {
	_zip_error_set_from_source(&za->error, src);
	zip_source_free(src);
	return NULL;
    }

    zf = _zip_file_new(za);

    zf->src = src;

    return zf;
}
Beispiel #24
0
static zip_cdir_t *
_zip_find_central_dir(zip_t *za, zip_uint64_t len)
{
    zip_cdir_t *cdir, *cdirnew;
    zip_uint8_t *match;
    zip_int64_t buf_offset;
    zip_uint64_t buflen;
    zip_int64_t a;
    zip_int64_t best;
    zip_error_t error;
    zip_buffer_t *buffer;

    if (len < EOCDLEN) {
	zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
        return NULL;
    }

    buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);
    if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {
	zip_error_t *src_error = zip_source_error(za->src);
	if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {
	    /* seek before start of file on my machine */
	    _zip_error_copy(&za->error, src_error);
	    return NULL;
	}
    }
    if ((buf_offset = zip_source_tell(za->src)) < 0) {
        _zip_error_set_from_source(&za->error, za->src);
        return NULL;
    }

    if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
        return NULL;
    }

    best = -1;
    cdir = NULL;
    if (buflen >= CDBUFSIZE) {
        /* EOCD64 locator is before EOCD, so leave place for it */
        _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
    }
    zip_error_set(&error, ZIP_ER_NOZIP, 0);

    match = _zip_buffer_get(buffer, 0);
    while ((match=_zip_memmem(match, _zip_buffer_left(buffer)-(EOCDLEN-4), (const unsigned char *)EOCD_MAGIC, 4)) != NULL) {
        _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
        if ((cdirnew = _zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &error)) != NULL) {
            if (cdir) {
                if (best <= 0) {
                    best = _zip_checkcons(za, cdir, &error);
                }

                a = _zip_checkcons(za, cdirnew, &error);
                if (best < a) {
                    _zip_cdir_free(cdir);
                    cdir = cdirnew;
                    best = a;
                }
                else {
                    _zip_cdir_free(cdirnew);
                }
            }
            else {
                cdir = cdirnew;
                if (za->open_flags & ZIP_CHECKCONS)
                    best = _zip_checkcons(za, cdir, &error);
                else {
                    best = 0;
                }
            }
            cdirnew = NULL;
        }

        match++;
        _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
    }

    _zip_buffer_free(buffer);

    if (best < 0) {
        _zip_error_copy(&za->error, &error);
        _zip_cdir_free(cdir);
        return NULL;
    }

    return cdir;
}
Beispiel #25
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;
    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;
}
Beispiel #26
0
static zip_cdir_t *
_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
{
    zip_cdir_t *cd;
    zip_uint64_t offset;
    zip_uint8_t eocd[EOCD64LEN];
    zip_uint64_t eocd_offset;
    zip_uint64_t size, nentry, i, eocdloc_offset;
    bool free_buffer;
    zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64;

    eocdloc_offset = _zip_buffer_offset(buffer);

    _zip_buffer_get(buffer, 4); /* magic already verified */

    num_disks = _zip_buffer_get_16(buffer);
    eocd_disk = _zip_buffer_get_16(buffer);
    eocd_offset = _zip_buffer_get_64(buffer);

    if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
        zip_error_set(error, ZIP_ER_SEEK, EFBIG);
        return NULL;
    }

    if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
	zip_error_set(error, ZIP_ER_INCONS, 0);
	return NULL;
    }

    if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
        _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
        free_buffer = false;
    }
    else {
        if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
            _zip_error_set_from_source(error, src);
            return NULL;
        }
        if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
            return NULL;
        }
        free_buffer = true;
    }

    if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
	zip_error_set(error, ZIP_ER_INCONS, 0);
        if (free_buffer) {
            _zip_buffer_free(buffer);
        }
	return NULL;
    }

    size = _zip_buffer_get_64(buffer);

    if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
	zip_error_set(error, ZIP_ER_INCONS, 0);
        if (free_buffer) {
            _zip_buffer_free(buffer);
        }
        return NULL;
    }

    _zip_buffer_get(buffer, 4); /* skip version made by/needed */

    num_disks64 = _zip_buffer_get_32(buffer);
    eocd_disk64 = _zip_buffer_get_32(buffer);

    /* if eocd values are 0xffff, we have to use eocd64 values.
       otherwise, if the values are not the same, it's inconsistent;
       in any case, if the value is not 0, we don't support it */
    if (num_disks == 0xffff) {
	num_disks = num_disks64;
    }
    if (eocd_disk == 0xffff) {
	eocd_disk = eocd_disk64;
    }
    if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
	zip_error_set(error, ZIP_ER_INCONS, 0);
        if (free_buffer) {
            _zip_buffer_free(buffer);
        }
	return NULL;
    }
    if (num_disks != 0 || eocd_disk != 0) {
	zip_error_set(error, ZIP_ER_MULTIDISK, 0);
        if (free_buffer) {
            _zip_buffer_free(buffer);
        }
	return NULL;
    }

    nentry = _zip_buffer_get_64(buffer);
    i = _zip_buffer_get_64(buffer);

    if (nentry != i) {
	zip_error_set(error, ZIP_ER_MULTIDISK, 0);
        if (free_buffer) {
            _zip_buffer_free(buffer);
        }
	return NULL;
    }

    size = _zip_buffer_get_64(buffer);
    offset = _zip_buffer_get_64(buffer);

    if (!_zip_buffer_ok(buffer)) {
        zip_error_set(error, ZIP_ER_INTERNAL, 0);
        if (free_buffer) {
            _zip_buffer_free(buffer);
        }
        return NULL;
    }

    if (free_buffer) {
        _zip_buffer_free(buffer);
    }

    if (offset > ZIP_INT64_MAX || offset+size < offset) {
        zip_error_set(error, ZIP_ER_SEEK, EFBIG);
        return NULL;
    }
    if (offset+size > buf_offset + eocd_offset) {
	/* cdir spans past EOCD record */
	zip_error_set(error, ZIP_ER_INCONS, 0);
	return NULL;
    }
    if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
	zip_error_set(error, ZIP_ER_INCONS, 0);
	return NULL;
    }

    if ((cd=_zip_cdir_new(nentry, error)) == NULL)
	return NULL;

    cd->is_zip64 = true;
    cd->size = size;
    cd->offset = offset;

    return cd;
}
Beispiel #27
0
ZIP_EXTERN int
zip_close(zip_t *za)
{
    zip_uint64_t i, j, survivors;
    zip_int64_t off;
    int error;
    zip_filelist_t *filelist;
    int changed;

    if (za == NULL)
	return -1;

    changed = _zip_changed(za, &survivors);

    /* don't create zip files with no entries */
    if (survivors == 0) {
	if ((za->open_flags & ZIP_TRUNCATE) || changed) {
	    if (zip_source_remove(za->src) < 0) {
		_zip_error_set_from_source(&za->error, za->src);
		return -1;
	    }
	}
	zip_discard(za);
	return 0;
    }	       

    if (!changed) {
	zip_discard(za);
	return 0;
    }

    if (survivors > za->nentry) {
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
        return -1;
    }
    
    if ((filelist=(zip_filelist_t *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL)
	return -1;

    /* create list of files with index into original archive  */
    for (i=j=0; i<za->nentry; i++) {
	if (za->entry[i].deleted)
	    continue;

        if (j >= survivors) {
            free(filelist);
            zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
            return -1;
        }
        
	filelist[j].idx = i;
	j++;
    }
    if (j < survivors) {
        free(filelist);
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
        return -1;
    }

    if (zip_source_begin_write(za->src) < 0) {
	_zip_error_set_from_source(&za->error, za->src);
	free(filelist);
	return -1;
    }
    
    error = 0;
    for (j=0; j<survivors; j++) {
	int new_data;
	zip_entry_t *entry;
	zip_dirent_t *de;

	i = filelist[j].idx;
	entry = za->entry+i;

	new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD));

	/* create new local directory entry */
	if (entry->changes == NULL) {
	    if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) {
                zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
                error = 1;
                break;
	    }
	}
	de = entry->changes;

	if (_zip_read_local_ef(za, i) < 0) {
	    error = 1;
	    break;
	}

        if ((off = zip_source_tell_write(za->src)) < 0) {
            error = 1;
            break;
        }
        de->offset = (zip_uint64_t)off;

	if (new_data) {
	    zip_source_t *zs;

	    zs = NULL;
	    if (!ZIP_ENTRY_DATA_CHANGED(entry)) {
		if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) {
		    error = 1;
		    break;
		}
	    }

	    /* add_data writes dirent */
	    if (add_data(za, zs ? zs : entry->source, de) < 0) {
		error = 1;
		if (zs)
		    zip_source_free(zs);
		break;
	    }
	    if (zs)
		zip_source_free(zs);
	}
	else {
	    zip_uint64_t offset;

	    /* when copying data, all sizes are known -> no data descriptor needed */
	    de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
	    if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {
		error = 1;
		break;
	    }
	    if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) {
		error = 1;
		break;
	    }
	    if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {
		_zip_error_set_from_source(&za->error, za->src);
		error = 1;
		break;
	    }
	    if (copy_data(za, de->comp_size) < 0) {
		error = 1;
		break;
	    }
	}
    }

    if (!error) {
	if (write_cdir(za, filelist, survivors) < 0)
	    error = 1;
    }

    free(filelist);

    if (!error) {
	if (zip_source_commit_write(za->src) != 0) {
	    _zip_error_set_from_source(&za->error, za->src);
	    error = 1;
	}
    }

    if (error) {
	zip_source_rollback_write(za->src);
	return -1;
    }

    zip_discard(za);
    
    return 0;
}
static zip_int64_t
deflate_decompress(zip_source_t *src, void *ud, void *data,
		   zip_uint64_t len, zip_source_cmd_t cmd)
{
    struct deflate *ctx;
    zip_int64_t n;
    int ret;

    ctx = (struct deflate *)ud;

    switch (cmd) {
        case ZIP_SOURCE_OPEN:
            if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
                _zip_error_set_from_source(&ctx->error, src);
                return -1;
            }

            ctx->zstr.zalloc = Z_NULL;
            ctx->zstr.zfree = Z_NULL;
            ctx->zstr.opaque = NULL;
            ctx->zstr.next_in = (Bytef *)ctx->buffer;
            ctx->zstr.avail_in = (uInt)n;

            /* negative value to tell zlib that there is no header */
            if ((ret=inflateInit2(&ctx->zstr, -MAX_WBITS)) != Z_OK) {
                zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret);
                return -1;
            }
            return 0;

        case ZIP_SOURCE_READ:
            return decompress_read(src, ctx, data, len);

        case ZIP_SOURCE_CLOSE:
            inflateEnd(&ctx->zstr);
            return 0;

        case ZIP_SOURCE_STAT:
        {
            zip_stat_t *st;
            
            st = (zip_stat_t *)data;
            
            st->comp_method = ZIP_CM_STORE;
            if (st->comp_size > 0 && st->size > 0)
                st->comp_size = st->size;
            
            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;
    }
}
static zip_int64_t
winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
{
    struct winzip_aes *ctx;
    zip_int64_t n;
    zip_uint64_t total, offset;

    ctx = (struct winzip_aes *)ud;

    switch (cmd) {
    case ZIP_SOURCE_OPEN:
	if (decrypt_header(src, ctx) < 0) {
	    return -1;
	}
	ctx->current_position = 0;
	return 0;

    case ZIP_SOURCE_READ:
	if (len > ctx->data_length - ctx->current_position) {
	    len = ctx->data_length - ctx->current_position;
	}

	if (len == 0) {
	    if (!verify_hmac(src, ctx)) {
		return -1;
	    }
	    return 0;
	}
	
	if ((n=zip_source_read(src, data, len)) < 0) {
	    _zip_error_set_from_source(&ctx->error, src);
	    return -1;
	}
	ctx->current_position += n;

	total = (zip_uint64_t)n;
	for (offset = 0; offset < total; offset += ZIP_MIN(total - offset, UINT_MAX)) {
	    _zip_fcrypt_decrypt(data + offset, ZIP_MIN(total - offset, UINT_MAX), &ctx->fcrypt_ctx);
	}

	return n;

    case ZIP_SOURCE_CLOSE:
	return 0;

    case ZIP_SOURCE_STAT:
    {
	zip_stat_t *st;

	st = (zip_stat_t *)data;

	st->encryption_method = ZIP_EM_NONE;
	st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
	if (st->valid & ZIP_STAT_COMP_SIZE) {
	    st->comp_size -= 12 + salt_length[ctx->mode];
	}
	
	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);

    case ZIP_SOURCE_ERROR:
	return zip_error_to_data(&ctx->error, data, len);

    case ZIP_SOURCE_FREE:
	winzip_aes_free(ctx);
	return 0;

    default:
	zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
	return -1;
    }
}
Beispiel #30
0
int
_zip_read_local_ef(zip_t *za, zip_uint64_t idx)
{
    zip_entry_t *e;
    unsigned char b[4];
    zip_buffer_t *buffer;
    zip_uint16_t fname_len, ef_len;

    if (idx >= za->nentry) {
	zip_error_set(&za->error, ZIP_ER_INVAL, 0);
	return -1;
    }

    e = za->entry+idx;

    if (e->orig == NULL || e->orig->local_extra_fields_read)
	return 0;

    if (e->orig->offset + 26 > ZIP_INT64_MAX) {
	zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG);
	return -1;
    }	

    if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) {
	_zip_error_set_from_source(&za->error, za->src);
	return -1;
    }
    
    if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) {
        return -1;
    }
    
    fname_len = _zip_buffer_get_16(buffer);
    ef_len = _zip_buffer_get_16(buffer);
    
    if (!_zip_buffer_eof(buffer)) {
        _zip_buffer_free(buffer);
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
        return -1;
    }
    
    _zip_buffer_free(buffer);
    
    if (ef_len > 0) {
	zip_extra_field_t *ef;
	zip_uint8_t *ef_raw;

	if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) {
	    zip_error_set(&za->error, ZIP_ER_SEEK, errno);
	    return -1;
	}

	ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error);

	if (ef_raw == NULL)
	    return -1;

	if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) {
	    free(ef_raw);
	    return -1;
	}
	free(ef_raw);

	if (ef) {
	    ef = _zip_ef_remove_internal(ef);
	    e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
	}
    }

    e->orig->local_extra_fields_read = 1;
    
    if (e->changes && e->changes->local_extra_fields_read == 0) {
	e->changes->extra_fields = e->orig->extra_fields;
	e->changes->local_extra_fields_read = 1;
    }

    return 0;
}