#include "ArchiveWriter.h" #include #include #include #include namespace MMCZip { ArchiveWriter::ArchiveWriter(const QString& archiveName) : m_filename(archiveName) {} ArchiveWriter::~ArchiveWriter() { close(); } bool ArchiveWriter::open() { if (m_filename.isEmpty()) { qCritical() << "Archive m_filename not set."; return false; } m_archive = archive_write_new(); if (!m_archive) { qCritical() << "Archive not initialized."; return false; } QString lowerName = m_filename.toLower(); if (lowerName.endsWith(".tar.gz") || lowerName.endsWith(".tgz")) { archive_write_set_format_pax_restricted(m_archive); archive_write_add_filter_gzip(m_archive); } else if (lowerName.endsWith(".tar.bz2") || lowerName.endsWith(".tbz")) { archive_write_set_format_pax_restricted(m_archive); archive_write_add_filter_bzip2(m_archive); } else if (lowerName.endsWith(".tar.xz") || lowerName.endsWith(".txz")) { archive_write_set_format_pax_restricted(m_archive); archive_write_add_filter_xz(m_archive); } else if (lowerName.endsWith(".zip") || lowerName.endsWith(".jar")) { archive_write_set_format_zip(m_archive); } else if (lowerName.endsWith(".tar")) { archive_write_set_format_pax_restricted(m_archive); } else { qCritical() << "Unknown archive format:" << m_filename; return false; } auto archiveNameUtf8 = m_filename.toUtf8(); if (archive_write_open_filename(m_archive, archiveNameUtf8.constData()) != ARCHIVE_OK) { qCritical() << "Failed to open archive file:" << m_filename << "-" << archive_error_string(m_archive); return false; } return true; } bool ArchiveWriter::close() { bool success = true; if (m_archive) { if (archive_write_close(m_archive) != ARCHIVE_OK) { qCritical() << "Failed to close archive" << m_filename << "-" << archive_error_string(m_archive); success = false; } if (archive_write_free(m_archive) != ARCHIVE_OK) { qCritical() << "Failed to free archive" << m_filename << "-" << archive_error_string(m_archive); success = false; } m_archive = nullptr; } return success; } bool ArchiveWriter::addFile(const QString& fileName, const QString& fileDest) { QFileInfo fileInfo(fileName); if (!fileInfo.exists()) { qCritical() << "File does not exists:" << fileInfo.filePath(); return false; } std::unique_ptr entry_ptr(archive_entry_new(), archive_entry_free); auto entry = entry_ptr.get(); if (!entry) { qCritical() << "Failed to create archive entry"; return false; } auto fileDestUtf8 = fileDest.toUtf8(); archive_entry_set_pathname(entry, fileDestUtf8.constData()); archive_entry_set_perm(entry, fileInfo.permissions() & 0777); if (fileInfo.isSymLink()) { auto target = fileInfo.symLinkTarget().toUtf8(); archive_entry_set_filetype(entry, AE_IFLNK); archive_entry_set_symlink(entry, target.constData()); archive_entry_set_size(entry, 0); if (archive_write_header(m_archive, entry) != ARCHIVE_OK) { qCritical() << "Failed to write symlink header for:" << fileDest << "-" << archive_error_string(m_archive); return false; } return true; } if (!fileInfo.isFile()) { qCritical() << "Unsupported file type:" << fileInfo.filePath(); return false; } QFile file(fileInfo.absoluteFilePath()); if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file: " << fileInfo.filePath(); return false; } archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_size(entry, file.size()); if (archive_write_header(m_archive, entry) != ARCHIVE_OK) { qCritical() << "Failed to write header for: " << fileDest; return false; } constexpr qint64 chunkSize = 8192; QByteArray buffer; buffer.resize(chunkSize); while (!file.atEnd()) { auto bytesRead = file.read(buffer.data(), chunkSize); if (bytesRead < 0) { qCritical() << "Read error in file: " << fileInfo.filePath(); return false; } if (archive_write_data(m_archive, buffer.constData(), bytesRead) < 0) { qCritical() << "Write error in archive for: " << fileDest; return false; } } return true; } bool ArchiveWriter::addFile(const QString& fileDest, const QByteArray& data) { std::unique_ptr entry_ptr(archive_entry_new(), archive_entry_free); auto entry = entry_ptr.get(); if (!entry) { qCritical() << "Failed to create archive entry"; return false; } auto fileDestUtf8 = fileDest.toUtf8(); archive_entry_set_pathname(entry, fileDestUtf8.constData()); archive_entry_set_perm(entry, 0644); archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_size(entry, data.size()); if (archive_write_header(m_archive, entry) != ARCHIVE_OK) { qCritical() << "Failed to write header for: " << fileDest; return false; } if (archive_write_data(m_archive, data.constData(), data.size()) < 0) { qCritical() << "Write error in archive for: " << fileDest; return false; } return true; } bool ArchiveWriter::addFile(archive* src, archive_entry* entry) { if (!src) { qCritical() << "Invalid source archive"; return false; } if (!entry) { // if is empty read next header if (auto r = archive_read_next_header(src, &entry); r == ARCHIVE_EOF) { return false; } else if (r != ARCHIVE_OK) { qCritical() << "Failed to read entry from source archive:" << archive_error_string(src); return false; } } if (archive_write_header(m_archive, entry) != ARCHIVE_OK) { qCritical() << "Failed to write header to entry:" << archive_entry_pathname(entry) << "-" << archive_error_string(m_archive); return false; } const void* buff; size_t size; la_int64_t offset; int status; while ((status = archive_read_data_block(src, &buff, &size, &offset)) == ARCHIVE_OK) { if (archive_write_data(m_archive, buff, size) < 0) { qCritical() << "Failed writing data block:" << archive_error_string(m_archive); return false; } } if (status != ARCHIVE_EOF) { qCritical() << "Failed reading data block:" << archive_error_string(m_archive); return false; } return true; } } // namespace MMCZip