/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "ArchiveWriter.hpp" #include "LibArchiveHelper.hpp" #include "Base/Utils.hpp" #include #include #include namespace openVulkanoCpp { namespace { constexpr int TYPE_MAP[] = { ARCHIVE_FORMAT_TAR, ARCHIVE_FORMAT_CPIO, ARCHIVE_FORMAT_ISO9660, ARCHIVE_FORMAT_ZIP, ARCHIVE_FORMAT_XAR, ARCHIVE_FORMAT_7ZIP, ARCHIVE_FORMAT_WARC, ARCHIVE_FORMAT_SHAR }; constexpr std::string_view TYPE_NAMES[] = { ".tar", ".cpio", ".iso", ".zip", ".xar", ".7z", ".warc", ".shar" }; constexpr int COMP_MAP[] = { ARCHIVE_FILTER_COMPRESS, ARCHIVE_FILTER_NONE, ARCHIVE_FILTER_GZIP, ARCHIVE_FILTER_BZIP2, ARCHIVE_FILTER_XZ, ARCHIVE_FILTER_LZ4, ARCHIVE_FILTER_ZSTD }; constexpr std::string_view COMP_NAMES[] = { ".Z", "", ".gz", ".bz2", ".xz", ".lz", ".zst" }; constexpr std::string_view TAR_SORTS[] = { ".tZ", ".tar", ".tgz", ".tbz2", ".txz", ".tlz", ".tzst" }; } std::string ArchiveConfiguration::GetFileExtension() const { const std::string_view& tName = TYPE_NAMES[static_cast(type)]; if (type == ArchiveType::TAR) { const std::string_view& cName = COMP_NAMES[static_cast(compression)]; std::string extension; extension.reserve(tName.length() + cName.length()); extension.append(tName).append(cName); return extension; } return std::string(tName); } ArchiveConfiguration ArchiveConfiguration::FromFileName(const char* fileName) { std::string_view fName = fileName; ArchiveConfiguration ac; int tId = 0; for(const std::string_view& tName : TYPE_NAMES) { if (tId > 0) { if (Utils::EndsWith(fName, tName)) { ac.type = static_cast(tId); return ac; } } tId++; } tId = 0; for(const std::string_view& tsName : TAR_SORTS) { if (Utils::EndsWith(fName, tsName)) { ac.compression = static_cast(tId); return ac; } tId++; } tId = 0; for(const std::string_view& cName : COMP_NAMES) { std::string tName(".tar"); tName.append(cName); if (Utils::EndsWith(fName, tName)) { ac.compression = static_cast(tId); return ac; } tId++; } return ac; } ArchiveWriter::ArchiveWriter(const char* fileName, const std::shared_ptr& logger) : ArchiveWriter(fileName, ArchiveConfiguration::FromFileName(fileName), logger) {} ArchiveWriter::ArchiveWriter(const char* fileName, ArchiveConfiguration archiveConfiguration, const std::shared_ptr& logger) : ArchiveBase(archive_write_new(), archive_entry_new(), logger) { //TODO error handling ChkErr(archive_write_set_format(m_archive, TYPE_MAP[static_cast(archiveConfiguration.type)])); if (archiveConfiguration.type == ArchiveConfiguration::ArchiveType::TAR) { ChkErr(archive_write_add_filter(m_archive, COMP_MAP[static_cast(archiveConfiguration.compression)])); } if (archiveConfiguration.compression != ArchiveConfiguration::CompressionType::NONE && archiveConfiguration.compressionLevel > 0) { std::string level = "compression-level=" + std::to_string(archiveConfiguration.compressionLevel); ChkErr(archive_write_set_options(m_archive, level.c_str())); } ChkErr(archive_write_open_filename(m_archive, fileName)); } ArchiveWriter::~ArchiveWriter() { archive_entry_free(m_archiveEntry); } void ArchiveWriter::Close() { archive_write_close(m_archive); } bool ArchiveWriter::AddFile(const char* fileName) { std::filesystem::path path(fileName); if (std::filesystem::is_regular_file(path)) { return AddFile(fileName, path.filename().c_str()); } else if (std::filesystem::is_directory(path)) { AddFiles(fileName, path.filename().c_str()); } return false; } bool ArchiveWriter::AddFile(const char* fileName, const char* inArchiveName) { archive_entry_clear(m_archiveEntry); std::unique_ptr archiveDisk(archive_read_disk_new(), archive_free); ChkErr(archive_read_disk_open(archiveDisk.get(), fileName)); ChkErr(archive_read_next_header2(archiveDisk.get(), m_archiveEntry)); //archive_read_disk_entry_from_file(archiveDisk, m_archiveEntry, -1, nullptr); archive_entry_set_pathname(m_archiveEntry, inArchiveName); ChkErr(archive_write_header(m_archive, m_archiveEntry)); int result = LibArchiveHelper::CopyArchiveData(archiveDisk.get(), m_archive); ChkErr(result); LibArchiveHelper::CheckError(result, archiveDisk.get(), m_logger); ChkErr(archive_write_finish_entry(m_archive)); m_bytesWritten += archive_entry_size(m_archiveEntry); return true; } bool ArchiveWriter::AddFile(const char* inArchiveName, const void* buffer, size_t length) { FileDescription description = FileDescription::MakeDescriptionForFile(inArchiveName, length); return AddFile(description, buffer); } bool ArchiveWriter::AddFile(const FileDescription& description, const void* buffer) { WriteHeader(description); bool ok = ChkErr(archive_write_data(m_archive, buffer, description.size)); ChkErr(archive_write_finish_entry(m_archive)); return ok; } bool ArchiveWriter::AddFile(const char* fileName, const std::vector>& buffers) { size_t size = 0; for(const auto& buffer : buffers) { if (buffer.first == nullptr) continue; size += buffer.second; } FileDescription description = FileDescription::MakeDescriptionForFile(fileName, size); return AddFile(description, buffers); } bool ArchiveWriter::AddFile(const FileDescription& description, const std::vector>& buffers) { WriteHeader(description); for(const auto& buffer : buffers) { if (buffer.first == nullptr) continue; if (!ChkErr(archive_write_data(m_archive, buffer.first, buffer.second))) { return false; } } ChkErr(archive_write_finish_entry(m_archive)); return true; } void ArchiveWriter::WriteHeader(const FileDescription& fileDescription) { archive_entry_clear(m_archiveEntry); archive_entry_set_pathname_utf8(m_archiveEntry, fileDescription.path.c_str()); archive_entry_set_size(m_archiveEntry, fileDescription.size); archive_entry_set_filetype(m_archiveEntry, LibArchiveHelper::GetFileType(fileDescription.type)); archive_entry_set_perm(m_archiveEntry, static_cast(fileDescription.permissions)); archive_entry_set_ctime(m_archiveEntry, fileDescription.createTime, 0); archive_entry_set_mtime(m_archiveEntry, fileDescription.modTime, 0); ChkErr(archive_write_header(m_archive, m_archiveEntry)); m_bytesWritten += fileDescription.size; } bool ArchiveWriter::AddFiles(const char* dirName) { return AddFiles(dirName, ""); } bool ArchiveWriter::AddFiles(const char* dirName, const char* inArchiveDirName) { return AddFiles(std::filesystem::path(dirName), std::string(inArchiveDirName)); } bool ArchiveWriter::AddFiles(const std::filesystem::path& dirName, const std::string& inArchiveDirName) { AddFile(dirName.c_str(), inArchiveDirName.c_str()); for(const auto& entry : std::filesystem::directory_iterator(dirName)) { std::string fPath = inArchiveDirName + "/" + entry.path().filename().native(); if (entry.is_directory()) AddFiles(entry, fPath); else AddFile(entry.path().c_str(), fPath.c_str()); } return true; } }