1

I'm trying to use libzip in a program that needs to archive several data chunks in different files. At the moment I have a code similar to the following snippet, edited from in-memory.c example in libzip examples.

The zip file is correctly saved with the files inside, but each file contains garbage. Any help is appreciated.

bool push_files(zip_t* za) {
  for (int i = 0; i < 10; i++) {
    // Generate data
    std::stringstream ss;
    ss << "Test file #" << i;
    std::string a = ss.str();

    zip_source_t* source = zip_source_buffer(za, a.c_str(), a.size(), 0);

    if (source == NULL) {
      std::cerr << "error creating source: " << zip_strerror(za) << std::endl;
      return false;
    }

    // Add buffer with filename
    std::stringstream fname;
    fname << "TEST-" << i;
    a = fname.str();

    if (zip_file_add(za, a.c_str(), source, ZIP_FL_ENC_UTF_8) < 0) {
      std::cerr << "error adding source: " << zip_strerror(za) << std::endl;
      return false;
    }
  }
  return true;
}

int main() {
  zip_source_t* src;
  zip_error_t error;
  zip_t* za;

  zip_error_init(&error);

  if ((src = zip_source_buffer_create(NULL, 0, 1, &error)) == NULL) {
    std::cerr << "can't create source: " << zip_error_strerror(&error) << std::endl;
    zip_error_fini(&error);
    return 1;
  }

  if ((za = zip_open_from_source(src, ZIP_TRUNCATE, &error)) == NULL) {
    std::cerr << "can't open zip from source: " << zip_error_strerror(&error) << std::endl;
    zip_source_free(src);
    zip_error_fini(&error);
    return 1;
  }

  zip_error_fini(&error);

  zip_source_keep(src);

  if (!push_files(za))
    return -1;

  if (zip_close(za) < 0) {
    std::cerr << "can't close zip archive" << zip_strerror(za) << std::endl;
    return 1;
  }

  // ... omissis, save archive to file as in in-memory.c
}
Giulio
  • 11
  • 1
  • 1
    By the way, if `zip_file_add` fails, the source is not freed and you should free it yourself with `zip_source_free` – user253751 Sep 22 '22 at 20:33

1 Answers1

2

zip_source_buffer does not copy the data out of the buffer - it just creates a zip_source_t which points to the same buffer. So you must keep the buffer alive until you're done adding the file.

Your code does not keep the buffer alive. The buffer you use is a.c_str() which is the data buffer of the string a. Fair enough, so far. But then before adding the file, you reassign the variable a = fname.str(); which (probably) frees that buffer and allocates a new one.

Solution: use a separate variable for the filename. Don't overwrite a until the file has been added.

user253751
  • 57,427
  • 7
  • 48
  • 90
  • You're right, reassigning a was not a wise move.Changed with two separate `std::string` variables, one for filename, the other for the data buffer, but still have garbage in zipped files. At this point I have a doubt: does `zip_file_add` actually copy data out of the buffer or this is done only when `zip_close` is invoked? – Giulio Sep 22 '22 at 21:15