Libarchive - Creating a single .zip archive with both encrypted(PKzip) and un-encrypted files together

816 views Asked by At

I am trying out libarchive to try to find out whether it is useful for my purpose.

I have a .zip file, with few files encrypted (PKzip) and few other files un-encrypted. I am able to successfully extract my .zip file using libarchive without a problem.

But when I try to create such an archive, I am not able to do it. Any guidance is appreciated.

[Working Fine] Extraction

void Extract()
{
// In
    archive *ina = archive_read_new();
    archive_entry *entry;

    archive_read_support_format_zip(ina);
    archive_read_set_passphrase_callback(ina, &count, ReadPasswordCallback); // ReadPasswordCallback - Supplies nullptr/emptry string for extracting files with no password, and give appropriate password for extracting files with password
    archive_read_open_filename(ina, "test.zip", 10240); // ARCHIVE_OK received here

// Out
    archive *ext = archive_write_disk_new();
    archive_write_disk_set_options(ext, flags);

// Extraction
    for(;;)
    {
        archive_read_next_header(ina, &entry); // ARCHIEVE_OK received here
        archive_write_header(ext, entry); // ARCHIEVE_OK received here
        copy_data(ina, ext); // copy_data  ** defined at the bottom **
        
        // Completion of write entry
        archive_write_finish_entry(ext);
    }

// Close and Cleanup
    archive_read_close(ina);
    archive_read_free(ina);
    
    archive_write_close(ext);
    archive_write_free(ext);
}

**[NOT WORKING] Cloning - Read the same zip file and create a copy (with few files as encrypted, few others as un-encrypted as per the original zip file) and **

void Clone()
{
// In
    archive *ina = archive_read_new();
    archive_entry *entry;

    archive_read_support_format_zip(ina);
    archive_read_set_passphrase_callback(ina, &count, ReadPasswordCallback); // ReadPasswordCallback - Supplies nullptr/emptry string for extracting files with no password, and give appropriate password for extracting files with password
    archive_read_open_filename(ina, "test.zip", 10240); // ARCHIVE_OK received here

// Out
    archive *oua = archive_write_new();
    archive_write_set_format_zip(oua);
    archive_write_set_options(oua, "zip:encryption=traditional");
    archive_write_set_passphrase_callback(oua, nullptr, WritePasswordCallback); // WritePasswordCallback - Supplies nullptr/empty string for writing files with no password, and give appropriate password for writings files with password
    archive_write_open_filename(oua, "testNEW.zip");

// Cloning
    for(;;)
    {
        archive_read_next_header(ina, &entry); // ARCHIEVE_OK received here
        archive_write_header(oua, entry); // ARCHIEVE_OK received here
        copy_data(ina, oua); // copy_data ** defined at the bottom **

        // Completion of write entry
        archive_write_finish_entry(oua);
    }

// Close and Cleanup
    archive_read_close(ina);
    archive_read_free(ina);
    
    archive_write_close(oua);
    archive_write_free(oua);
}

ReadPasswordCallback is called once per entry, hence I am able to decrypt files independently by supplying the file's corresponding password. For non-encrypted files, supplying nullptr works fine.

Whereas, with the write, the behaviour is different with the WritePasswordCallback invocation. The WritePasswordCallback is getting called "only once", not once per entry as ReadPasswordCallback. Hence I am not able to supply independent encryption key for the files. Also supplying a nullptr throws an error saying encryption key is necessary for encryption, hence I am not able to have few files as unencrypted

Is this a limitation of Libarchive library? Please help, and thanks in advance!

static int
copy_data(struct archive *ar, struct archive *aw)
{
    int r;
    char buff[1024];
    
    do
    {
        r = archive_read_data(ar, buff, sizeof(buff)); // Receives 0/EOF at the last read
        if (r == 0 || r == ARCHIVE_EOF)
          return (ARCHIVE_OK);
        
        // Copy
        r = archive_write_data(aw, buff, r); // Receive ARCHIVE_OK
    } while (r > 0);
    return ARCHIVE_FATAL;
}
0

There are 0 answers