how to create archive file by libarchive

60 Views Asked by At

I use libarchive to create a archive, and the source is a directory, I need create the archive with the same directory tree of the source directory, so I use the archive_read_disk_open and archive_read_disk_descend, but when i create a file with archive_write_open_filename(a, "xxx.zip"),there is always only a "xxx" file in the result zip file, I have to extract the "xxx" file and then rename the "xxx" to "xxx.zip", then I get the correct zip file

If I read entry from the xxx.zip using libarchive, I can get the correct directory tree.

This is the C++ code I use to create the zip file:

bool KArchiveManager::pack(const QString& srcDirPath)
{
    struct archive* a;
    struct archive_entry* entry;
    int r;

    a = archive_write_new();
    archive_write_set_format_zip(a);
    archive_write_set_compression_compress(a);
    QString outPath= srcDirPath + ".zip";
    
    r = archive_write_open_filename_w(a, outPath.toStdWString().c_str());
    if (r != ARCHIVE_OK)
    {
        QString msg = QString("archive_write_open_filename_w : %1")
            .arg(archive_error_string(a));
        emit packArchiveError(msg);
        archive_write_close(a);
        archive_write_free(a);
        return false;
    }

    QDir compressDir(srcDirPath);
    if (!compressDir.exists())
    {
        emit packArchiveError(tr("compress dir not exist"));
        archive_write_close(a);
        archive_write_free(a);
        return false;
    }

    QStringList entryList = compressDir.entryList(
        QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
    foreach(const QString & entryName, entryList)
    {
        struct archive* disk = archive_read_disk_new();
        archive_read_disk_set_standard_lookup(disk);
        QString diskPath = compressDir.absoluteFilePath(entryName);
        r = archive_read_disk_open(disk, diskPath.toStdString().c_str());
        if (r != ARCHIVE_OK)
        {
            QString msg = QString("archive_read_disk_open : %1")
                .arg(archive_error_string(disk));
            emit packArchiveError(msg);
            archive_write_close(a);
            archive_write_free(a);
            archive_read_close(disk);
            archive_read_free(disk);
            return false;
        }

        while (true)
        {
            entry = archive_entry_new();
            r = archive_read_next_header(disk, &entry);
            if (r == ARCHIVE_EOF)
                break;
            if (r != ARCHIVE_OK)
            {
                QString msg = QString("archive_read_next_header : %1")
                    .arg(archive_error_string(disk));
                emit packArchiveError(msg);
                archive_write_close(a);
                archive_write_free(a);
                archive_read_close(disk);
                archive_read_free(disk);
                return false;
            }
            archive_read_disk_descend(disk);
            QString sourcePath = archive_entry_pathname(entry);
            QString pathName = sourcePath.mid(srcDirPath.size() + 1);
            archive_entry_set_pathname(entry, pathName.toLocal8Bit());
            r = archive_write_header(a, entry);
            if (r != ARCHIVE_OK)
            {
                QString msg = QString("archive_write_header : %1")
                    .arg(archive_error_string(a));
                emit packArchiveError(msg);
                archive_write_close(a);
                archive_write_free(a);
                archive_read_close(disk);
                archive_read_free(disk);
                return false;
            }
            //copydata
            if (archive_entry_filetype(entry) != AE_IFDIR)
            {
                QFile file(sourcePath);
                if (file.open(QIODevice::ReadOnly))
                {
                    QDataStream in(&file);
                    while (!in.atEnd())
                    {
                        QByteArray chunk = file.read(1024);
                        archive_write_data(a, chunk.data(), chunk.size());
                    }
                    file.close();
                }
            }

            archive_entry_free(entry);
        }
        archive_read_close(disk);
        archive_read_free(disk);
    }
    archive_write_close(a);
    archive_write_free(a);
    return true;
}

How can I create the correct zip file instead of a zip file always contain the same name file of the param passed to the archive_write_open_filename?

1

There are 1 best solutions below

5
pts On

Runcmd.exe, within that use the cd command to navigate to the correct directory, then run the dir command, and check the filename in the output. It will be xxx.zip.

Some file managers such as Explorer hide the extension (.zip in this case). You can configure them to show the extension.