c++qtlibarchive

Adding directory to tarfile with libarchive


I am trying to add a directory to a tar archive that I am creating. The archive is created, however, it has no files in it.

Here's the code I have using libarchive (directory is a QString of the path to the directory to be tarred.)

struct archive *a;
struct archive_entry *entry;
struct stat st;
char buff[8192];
size_t bytes_read;
int fd;

// the path of the output tarfile
QByteArray outArray = (directory + ".tar").toLocal8Bit();
char *outDirectory = outArray.data();

// the path to the input directory
QByteArray inputArray = directory.toLocal8Bit();
char *inputDirectory = inputArray.data();

QFileInfo inputInfo;
inputInfo.setFile(directory);

// the name of the directory
QByteArray pathArray = inputInfo.fileName().toLocal8Bit();
char *pathDirectory = pathArray.data();

a = archive_write_new();
archive_write_add_filter_gzip(a);
archive_write_set_format_pax_restricted(a);
archive_write_open_filename(a, outDirectory);

entry = archive_entry_new();
stat(inputDirectory, &st);

archive_entry_set_pathname(entry, pathDirectory);
archive_entry_set_filetype(entry, AE_IFDIR);
archive_entry_copy_stat(entry, &st);
archive_write_header(a, entry);

fd = open(inputDirectory, O_RDONLY);
bytes_read = read(fd, buff, sizeof(buff));
while (bytes_read > 0) {
    archive_write_data(a, buff, bytes_read);
    bytes_read = read(fd, buff, sizeof(buff));
}
close(fd);

archive_write_finish_entry(a);
archive_write_close(a);
archive_write_free(a);

Solution

  • Your code logic is incorrect. You are trying to read a directory, whereas you should read the files in the directory... You would need something like this to iterate the file through:

    QDirIterator it("/etc", QDirIterator::Subdirectories);
    while (it.hasNext())
        qDebug() << it.next();
    

    This is a proof of concept code to fix your issue.

    #include <QString>
    #include <QByteArray>
    #include <QFileInfo>
    #include <QDebug>
    #include <QDirIterator>
    
    #include <archive.h>
    #include <archive_entry.h>
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main()
    {
        QString directory = "/home/lpapp/tmp/stackoverflow/test";
        struct archive *a;
        struct archive_entry *entry;
        struct stat st;
        char buff[8192];
        size_t bytes_read;
        int fd;
    
        QByteArray outArray = directory.toLocal8Bit() + ".tar";
        char *outDirectory = outArray.data();
        qDebug() << outDirectory;
    
        QByteArray inputArray = directory.toLocal8Bit();
        char *inputDirectory = inputArray.data();
        qDebug() << inputDirectory;
    
        QFileInfo inputInfo;
        inputInfo.setFile(directory);
    
        // the name of the directory
        QByteArray pathArray = inputInfo.fileName().toLocal8Bit();
        char *pathDirectory = pathArray.data();
        qDebug() << pathDirectory;
    
        a = archive_write_new();
        archive_write_add_filter_gzip(a);
        archive_write_set_format_pax_restricted(a);
        archive_write_open_filename(a, outDirectory);
    
        QDirIterator it(directory, QDirIterator::Subdirectories);
        while (it.hasNext()) {
            entry = archive_entry_new();
            stat(inputDirectory, &st);
    
            archive_entry_set_pathname(entry, it.next().toLocal8Bit().constData());
            archive_entry_set_filetype(entry, AE_IFDIR);
            archive_entry_copy_stat(entry, &st);
            archive_write_header(a, entry);
    
            fd = open(inputDirectory, O_RDONLY);
            bytes_read = read(fd, buff, sizeof(buff));
            while (bytes_read > 0) {
                archive_write_data(a, buff, bytes_read);
                bytes_read = read(fd, buff, sizeof(buff));
            }
            close(fd);
            archive_entry_free(entry);
    
            archive_write_finish_entry(a);
            archive_write_close(a);
            archive_write_free(a);
        }
    
        return 0;
    }
    

    main.pro

    TEMPLATE = app
    TARGET = main
    QT = core
    LIBS += -larchive
    SOURCES += main.cpp
    

    Build and Run

    qmake && make && ./main