Fail to extract binary file from Tar archive using libarchive

731 Views Asked by At

Update

The example below does work. I had misread the intention of the flag ARCHIVE_EXTRACT_TIME and was expecting to see the newly created file. Instead the file was being extracted correctly but with its original creation date. It was a long week! :-)


I have the following data stored in a Tar archive:

  • opt/
  • fw.bin
  • ad/
    • bin/
      • installer.sh

I have the following code, running on Ubuntu (g++ version 5.2.1), to extract the contents of the archive in memory using libarchive, largely taken from the examples:

int copy_data(struct archive *ar, struct archive *aw)
{
    int r;
    const void *buff;
    size_t size;
#if ARCHIVE_VERSION_NUMBER >= 3000000
    int64_t offset;
#else
    off_t offset;
#endif
    for (;;) {
        r = archive_read_data_block(ar, &buff, &size, &offset);
        if (r == ARCHIVE_EOF)
            return (ARCHIVE_OK);
        if (r != ARCHIVE_OK)
            return (r);
        r = archive_write_data(aw, buff, size);
        if (size != r)
        {
           std::cerr << "Failed to write " << (size - r) << " Bytes\n";
        }
    }
}

}

int main(int argc, char** argv)
{
    std::ifstream input("archive.tar.gz", std::ios::binary | std::ios::ate );
    auto const size = input.tellg();
    char* buffer = new char[size];
    input.seekg(0);
    input.read(buffer, size);
    input.close();

    struct archive *a;
    struct archive *ext;
    struct archive_entry *entry;
    int retCode;
    int flags = ARCHIVE_EXTRACT_TIME;

    a = archive_read_new();
    archive_read_support_format_all(a);

    ext = archive_write_disk_new();
    archive_write_disk_set_options(ext, flags);
    archive_write_disk_set_standard_lookup(ext);

    if ((retCode = archive_read_open_memory(a, buffer, size)))

    for (;;) {
        retCode = archive_read_next_header(a, &entry);
        if (retCode == ARCHIVE_EOF)
        {
            break;
        }
        if (retCode != ARCHIVE_OK)
        {
            return -1;
        }

        retCode = archive_write_header(ext, entry);
        if (retCode != ARCHIVE_OK)
        {
            return -1;
        }
        else
        {
            if (archive_entry_size(entry) > 0)
            {
                copy_data(a, ext);
            }
            retCode = archive_write_finish_entry(ext);
            if (retCode != ARCHIVE_OK)
            {
                return -1;
            }

        }
    }
    archive_read_close(a);
    archive_read_free(a);

    archive_write_close(ext);
    archive_write_free(ext);

    return 0;
}

It unpacks the directories correctly as above and writes the installer.sh file. However, the binary file (fw.bin) is missing. Are there specific settings I am missing in order to write binary files to disk? Am I using the wrong API calls?

0

There are 0 best solutions below