Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can libzip be used from C to create a zip file in memory?

Tags:

c

libzip

I am trying to using libzip to create a zip file directly in memory, not to a file on disk. My code is quite basic at the moment as I am getting stuck on creating the necessary zip_t struct from a zip_source_buffer:

#include <stdio.h>
#include <string.h>
#include <zip.h>

int main(int argc, char *arrv[])
{
    char buffer[65536] = {};
    zip_error_t error;
    zip_source_t *zs = zip_source_buffer_create(buffer, sizeof(buffer), 0, &error);

    int err = zip_source_begin_write(zs);
    printf("%p %d '%s'\n", zs, err, zip_error_strerror(&error)); 
    zip_error_fini(&error);

    zip_t * zip = zip_open_from_source(zs, ZIP_CREATE, &error);
    printf("%p '%s'\n", zip, zip_error_strerror(&error)); 
    zip_error_fini(&error);
}

the code compiles and runs, but thows an error:

$ ./ztest 
0xdd50a0 0 'No error'
(nil) 'Not a zip archive'

It's not clear if the begin_write() is needed, but it doesn't generate an error and I get the same result without it.

What am I missing? Thanks

like image 665
Dave Lawrence Avatar asked Feb 13 '18 13:02

Dave Lawrence


2 Answers

My 2 cent if anybody yet has interest in question.

Do not forget to zip_source_keep before zip_open_from_source, as zip_close will free source, but we want to use its content.

int flags = 0;
zip_error_t error;
zip_source_t *zsmem = zip_source_buffer_create(0, 0, 0, &error);
//we can fill up new zip with an old one (some template, for example)
if (exdata){
    zip_source_begin_write(zsmem);
    zip_source_write(zsmem, exdata, exdata_sz); 
    zip_source_commit_write(zsmem); 
}else
    flags |= ZIP_TRUNCATE;

zip_source_keep(zsmem); //!!
struct zip* arc = zip_open_from_source(zsmem, flags, &error);

//do more stuff adding, removing files , comments, etc

zip_close(arc);

zip_source_open(zsmem);
zip_source_seek(zsmem, 0, SEEK_END);
zip_int64_t sz = zip_source_tell(zsmem);
zip_source_seek(zsmem, 0, SEEK_SET);
zip_source_read(zsmem, outbuffer, sz);
zip_source_close(zsmem);

zip_source_free(zsmem);

send_over_network(outbuffer);
like image 115
user3567069 Avatar answered Oct 23 '22 10:10

user3567069


Use ZIP_TRUNCATE instead of ZIP_CREATE. The archive always exists in the case of a buffer source, so ZIP_CREATE has no effect, but a stream of '0's is not a valid zip file. ZIP_TRUNCATE tells libzip to ignore the buffer's current contents (i.e. override all the '0's with the new archive).

zip_source_begin_write() is called internally by libzip. It's not necessary for it to be called in this kind of situation.

like image 22
RyanCu Avatar answered Oct 23 '22 11:10

RyanCu