0

I am creating an archive dynamically an need to write some binary data dynamically as file entries. I am also using the extra_field API to add more metadata. Unfortunately when I write using source_buffer the data written gets corrupted.

API calls are along the lines of:

const std::string diff; //this is initialized and passed from a function
zip_t z_; //class member initialized before
const std::string f; // name of the virtual file, passed in the function
// use unique_ptr to manage the lifetime of zip_source_t
std::unique_ptr<zip_source_t, void (*)(zip_source_t*)>  p_zf(
    zip_source_buffer_create((const void*)diff.data(), diff.size(), 0, 0),
    [](zip_source_t* p) { if(p) zip_source_free(p); }
);
if (!p_zf)
    throw exception ...;
// write inside archive and initialize the fields
const zip_int64_t idx = zip_file_add(z_, f.c_str(), p_zf.get(), ZIP_FL_ENC_GUESS);
if(-1 == idx)
    throw exception ...;
// write extra field
if(zip_file_extra_field_set(z_, idx, FS_ZIP_EXTRA_FIELD_ID, 0, (const zip_uint8_t*)&metadata, sizeof(metadata), ZIP_FL_LOCAL))
    throw exception ...;

The code above 'works' but then when I read the archive back for the virtual file f I get some garbled values. The metadata (fairly large, 256 bytes) is perfectly stored.

If I replace the zip_source_buffer_create with:

zip_source_buffer(z_, (const void*)diff.data(), diff.size(), 0)

I get the very same garbled data (the size is always as expected, but the content gets polluted). Only if I write a temporary file and then initialize the zip_source_t via filesystem API (i.e. zip_source_file_create) then all is saved fine:

std::unique_ptr<zip_source_t, void (*)(zip_source_t*)>  p_zf(
    zip_source_file_create(tmp_filename, 0, -1, 0),
    [](zip_source_t* p) { if(p) zip_source_close(p); }
);

Am I doing anything wrong? Please note that the lifetime of diff is const within the scope of both zip_source_buffer_create, zip_source_buffer and zip_file_add. Is this a potential bug in libzip? I'm using version 1.7.3 on Ubuntu 22.04 64 bit.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
Emanuele
  • 1,408
  • 1
  • 15
  • 39
  • the man page sample uses `zip_source_buffer` not the api you are using https://libzip.org/documentation/zip_file_add.html – pm100 Jan 03 '23 at 01:08
  • [`zip_source_free` documentation](https://libzip.org/documentation/zip_source_free.html) reads: *NOTE: This function should not be called on a source after it was used successfully in a `zip_open_from_source`, `zip_file_add`, or `zip_file_replace` call.* – Evg Jan 03 '23 at 02:27
  • Unfortunately even if I comment out the destructors and/or use zip_source_buffer API, the issue is still there. Also the API doesn't specify the lifetime of the buffers initialized from zip_source_buffer (and similar). For example is zip_file_add to synchronously writing in the ZIP file, thus removing the need for the zip_source_t*? Or instead one should keep the zip_source_t* (and related memory buffers) valid for the whole lifetime of main zip zip_t* zip_open? This would be a crazy requirement... – Emanuele Jan 03 '23 at 07:45
  • I've actually sorted out as per linked question. Looked into the sources of _zip_file_add_ and indeed it doesn't do much with the `zip_source_t` and it will definitely write it upon _zip_close_, which means one has to guarantee the buffer lifetime since then _or_ duplicate the buffer and have it managed by libzip itself. Bad design imho. – Emanuele Jan 03 '23 at 09:57

0 Answers0