示例#1
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;
}
示例#2
0
ZIP_EXTERN int
zip_close(struct zip *za)
{
    zip_uint64_t i, j, survivors;
    int error;
    char *temp;
    FILE *out;
#ifndef _WIN32
    mode_t mask;
#endif
    struct zip_filelist *filelist;
    int reopen_on_error;
    int new_torrentzip;
    int changed;

    reopen_on_error = 0;

    if (za == NULL)
	return -1;

    changed = _zip_changed(za, &survivors);

    /* don't create zip files with no entries */
    if (survivors == 0) {
	if (za->zn && ((za->open_flags & ZIP_TRUNCATE) || (changed && za->zp))) {
	    if (remove(za->zn) != 0) {
		_zip_error_set(&za->error, ZIP_ER_REMOVE, errno);
		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=(struct zip_filelist *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL)
	return -1;

    /* archive comment is special for torrentzip */
    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) {
	/* TODO: use internal function when zip_set_archive_comment clears TORRENT flag */
	if (zip_set_archive_comment(za, TORRENT_SIG "XXXXXXXX", TORRENT_SIG_LEN + TORRENT_CRC_LEN) < 0) {
	    free(filelist);
	    return -1;
	}
    }
    /* TODO: if no longer torrentzip and archive comment not changed by user, delete it */


    /* 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;
	filelist[j].name = zip_get_name(za, i, 0);
	j++;
    }
    if (j < survivors) {
        free(filelist);
        _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
        return -1;
    }


    if ((temp=_zip_create_temp_output(za, &out)) == NULL) {
	free(filelist);
	return -1;
    }
    
    
    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
	qsort(filelist, (size_t)survivors, sizeof(filelist[0]),
	      _zip_torrentzip_cmp);

    new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1
		      && zip_get_archive_flag(za, ZIP_AFL_TORRENT,
					      ZIP_FL_UNCHANGED) == 0);
    error = 0;
    for (j=0; j<survivors; j++) {
	int new_data;
	struct zip_entry *entry;
	struct zip_dirent *de;

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

	new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || new_torrentzip || 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 (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
	    _zip_dirent_torrent_normalize(entry->changes);


	de->offset = (zip_uint64_t)ftello(out); /* TODO: check for errors */

	if (new_data) {
	    struct zip_source *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, out) < 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_GPBF_DATA_DESCRIPTOR;
	    if (_zip_dirent_write(de, out, ZIP_FL_LOCAL, &za->error) < 0) {
		error = 1;
		break;
	    }
	    if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) {
		error = 1;
		break;
	    }
	    if ((fseeko(za->zp, (off_t)offset, SEEK_SET) < 0)) {
		_zip_error_set(&za->error, ZIP_ER_SEEK, errno);
		error = 1;
		break;
	    }
	    if (copy_data(za->zp, de->comp_size, out, &za->error) < 0) {
		error = 1;
		break;
	    }
	}
    }

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

    free(filelist);

    if (error) {
	fclose(out);
	(void)remove(temp);
	free(temp);
	return -1;
    }

    if (fclose(out) != 0) {
	_zip_error_set(&za->error, ZIP_ER_CLOSE, errno);
	(void)remove(temp);
	free(temp);
	return -1;
    }
    
    if (za->zp) {
	fclose(za->zp);
	za->zp = NULL;
	reopen_on_error = 1;
    }
    if (_zip_rename(temp, za->zn) != 0) {
	_zip_error_set(&za->error, ZIP_ER_RENAME, errno);
	(void)remove(temp);
	free(temp);
	if (reopen_on_error) {
	    /* ignore errors, since we're already in an error case */
	    za->zp = fopen(za->zn, "rb");
	}
	return -1;
    }
#ifndef _WIN32
    mask = umask(0);
    umask(mask);
    chmod(za->zn, 0666&~mask);
#endif

    zip_discard(za);
    free(temp);
    
    return 0;
}
示例#3
0
ZIP_EXTERN struct zip_file *
zip_fopen_index(struct zip *za, int fileno, int flags)
{
    int len, ret;
    int zfflags;
    struct zip_file *zf;

    if ((fileno < 0) || (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;
    }

    zfflags = 0;
    switch (za->cdir->entry[fileno].comp_method) {
    case ZIP_CM_STORE:
	zfflags |= ZIP_ZF_CRC;
	break;

    case ZIP_CM_DEFLATE:
	if ((flags & ZIP_FL_COMPRESSED) == 0)
	    zfflags |= ZIP_ZF_CRC | ZIP_ZF_DECOMP;
	break;
    default:
	if ((flags & ZIP_FL_COMPRESSED) == 0) {
	    _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
	    return NULL;
	}
	break;
    }

    zf = _zip_file_new(za);

    zf->flags = zfflags;
    /* zf->name = za->cdir->entry[fileno].filename; */
    zf->method = za->cdir->entry[fileno].comp_method;
    zf->bytes_left = za->cdir->entry[fileno].uncomp_size;
    zf->cbytes_left = za->cdir->entry[fileno].comp_size;
    zf->crc_orig = za->cdir->entry[fileno].crc;

    if ((zf->fpos=_zip_file_get_offset(za, fileno)) == 0) {
	zip_fclose(zf);
	return NULL;
    }
    
    if ((zf->flags & ZIP_ZF_DECOMP) == 0)
	zf->bytes_left = zf->cbytes_left;
    else {
	if ((zf->buffer=(char *)malloc(BUFSIZE)) == NULL) {
	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
	    zip_fclose(zf);
	    return NULL;
	}

	len = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf);
	if (len <= 0) {
	    _zip_error_copy(&za->error, &zf->error);
	    zip_fclose(zf);
	return NULL;
	}

	if ((zf->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) {
	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
	    zip_fclose(zf);
	    return NULL;
	}
	zf->zstr->zalloc = Z_NULL;
	zf->zstr->zfree = Z_NULL;
	zf->zstr->opaque = NULL;
	zf->zstr->next_in = (Bytef *)zf->buffer;
	zf->zstr->avail_in = len;
	
	/* negative value to tell zlib that there is no header */
	if ((ret=inflateInit2(zf->zstr, -MAX_WBITS)) != Z_OK) {
	    _zip_error_set(&za->error, ZIP_ER_ZLIB, ret);
	    zip_fclose(zf);
	    return NULL;
	}
    }
    
    return zf;
}
示例#4
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;
}
示例#5
0
struct zip_source *
_zip_source_zip_new(struct zip *za, struct zip *srcza, zip_uint64_t srcidx, zip_flags_t flags,
		    zip_uint64_t start, zip_uint64_t len, const char *password)
{
    zip_compression_implementation comp_impl;
    zip_encryption_implementation enc_impl;
    struct zip_source *src, *s2;
    zip_uint64_t offset;
    struct zip_stat st;

    if (za == NULL)
	return NULL;

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

    if ((flags & ZIP_FL_UNCHANGED) == 0
	&& (ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx) || srcza->entry[srcidx].deleted)) {
	_zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
	return NULL;
    }

    if (zip_stat_index(srcza, srcidx, flags|ZIP_FL_UNCHANGED, &st) < 0) {
	_zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
	return NULL;
    }

    if (flags & ZIP_FL_ENCRYPTED)
	flags |= ZIP_FL_COMPRESSED;

    if ((start > 0 || len > 0) && (flags & ZIP_FL_COMPRESSED)) {
	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
	return NULL;
    }

    /* overflow or past end of file */
    if ((start > 0 || len > 0) && (start+len < start || start+len > st.size)) {
	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
	return NULL;
    }

    enc_impl = NULL;
    if (((flags & ZIP_FL_ENCRYPTED) == 0) && (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 ((offset=_zip_file_get_offset(srcza, srcidx, &za->error)) == 0)
	return NULL;

    if (st.comp_size == 0) {
	if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL)
	    return NULL;
    }
    else {
	if (start+len > 0 && enc_impl == NULL && comp_impl == NULL) {
	    struct zip_stat st2;

	    st2.size = len ? len : st.size-start;
	    st2.comp_size = st2.size;
	    st2.comp_method = ZIP_CM_STORE;
	    st2.mtime = st.mtime;
	    st2.valid = ZIP_STAT_SIZE|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_MTIME;

            /* XXX: check for overflow of st2.size */
	    if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset+start, (zip_int64_t)st2.size, 0, &st2)) == NULL)
		return NULL;
	}
	else {
            /* XXX: check for overflow of st.comp_size */
	    if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset, (zip_int64_t)st.comp_size, 0, &st)) == NULL)
		return NULL;
	}
	
	if (enc_impl) {
	    if ((s2=enc_impl(za, src, st.encryption_method, 0, password)) == NULL) {
		zip_source_free(src);
		/* XXX: set error (how?) */
		return NULL;
	    }
	    src = s2;
	}
	if (comp_impl) {
	    if ((s2=comp_impl(za, src, st.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)
	    && (len == 0 || len == st.comp_size)) {
	    /* when reading the whole file, check for crc errors */
	    if ((s2=zip_source_crc(za, src, 1)) == NULL) {
		zip_source_free(src);
		/* XXX: set error (how?) */
		return NULL;
	    }
	    src = s2;
	}

	if (start+len > 0 && (comp_impl || enc_impl)) {
	    if ((s2=zip_source_window(za, src, start, len ? len : st.size-start)) == NULL) {
		zip_source_free(src);
		/* XXX: set error (how?) (why?) */
		return NULL;
	    }
	    src = s2;
	}
    }

    return src;
}