/* * 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 "MultiPartArchiveWriter.hpp" #include "LibArchiveHelper.hpp" #include //TODO replace with external fmt #include #include namespace OpenVulkano { MultiPartArchiveWriter::MultiPartArchiveWriter(const std::string& dir, const std::string& fileNamePattern, const ArchiveConfiguration& archiveConfiguration, size_t sizeLimit, bool lazyCreation, const std::shared_ptr& logger) : m_fileSizeLimit(sizeLimit), m_archiveId(0), m_archiveConfig(archiveConfiguration) , m_dir(dir), m_fileNamePattern(fileNamePattern), m_logger(logger), m_lazyCreation(lazyCreation) { if (!m_dir.empty() && !std::filesystem::exists(m_dir)) { std::filesystem::create_directories(m_dir); } if (!lazyCreation) StartNewFile(); } MultiPartArchiveWriter::~MultiPartArchiveWriter() { bool deleteLast = m_writer && m_writer->GetTotalWrittenBytes() == 0; m_writer = nullptr; if (deleteLast) std::filesystem::remove(m_archives.back()); } void MultiPartArchiveWriter::StartNewFile() { m_archives.push_back(m_dir / fmt::format(fmt::runtime(m_fileNamePattern), m_archiveId++)); #ifdef WIN32 m_writer = std::make_unique(m_archives.back().string().c_str(), m_archiveConfig, m_logger); #else m_writer = std::make_unique(m_archives.back().c_str(), m_archiveConfig, m_logger); #endif if (m_shouldCompress) m_writer->SetShouldCompressFunction(m_shouldCompress); } void MultiPartArchiveWriter::CheckSize(size_t size) { if (!m_writer || m_fileSizeLimit < m_writer->GetTotalWrittenBytes() + size) { StartNewFile(); } } bool MultiPartArchiveWriter::AddFile(const FileDescription& description, const void* buffer) { CheckSize(description.size); return m_writer->AddFile(description, buffer); } bool MultiPartArchiveWriter::AddFile(const FileDescription& description, const std::span>& buffers) { CheckSize(description.size); return m_writer->AddFile(description, buffers); } bool MultiPartArchiveWriter::AddFile(const char* fileName, const char* inArchiveName) { std::unique_ptr archiveEntry(archive_entry_new(), archive_entry_free); std::unique_ptr archiveDisk(archive_read_disk_new(), archive_free); LibArchiveHelper::CheckError(archive_read_disk_open(archiveDisk.get(), fileName), archiveDisk.get(), m_logger); LibArchiveHelper::CheckError(archive_read_next_header2(archiveDisk.get(), archiveEntry.get()), archiveDisk.get(), m_logger); CheckSize(archive_entry_size(archiveEntry.get())); return m_writer->AddFile(fileName, inArchiveName); } ArchiveOStream MultiPartArchiveWriter::AddFileStream(const FileDescription& description) { //TODO handle zip splits CheckSize(description.size); return m_writer->AddFileStream(description); } void MultiPartArchiveWriter::Move(const std::filesystem::path& newDir) { bool hasToMove = m_archives.size() > 1 || m_writer->GetTotalWrittenBytes() > 0; m_writer = nullptr; // Close current archive if (!newDir.empty() && !std::filesystem::exists(newDir)) { std::filesystem::create_directories(newDir); } if (hasToMove) { // Move all existing archives std::vector newArchivePaths; newArchivePaths.reserve(m_archives.size() + 1); for (const auto& file : m_archives) { newArchivePaths.push_back(newDir / file.filename()); std::filesystem::rename(file, newArchivePaths.back()); } m_archives = std::move(newArchivePaths); } else { m_archiveId = 0; std::filesystem::remove(m_archives.back()); m_archives.clear(); } m_dir = newDir; if (!m_lazyCreation) StartNewFile(); } void MultiPartArchiveWriter::Split() { if (!m_writer || !m_writer->GetTotalWrittenBytes()) return; // Nothing has been written yet, no need to split file m_writer = nullptr; } void MultiPartArchiveWriter::SetShouldCompressFunction(const std::function& shouldComp) { if (m_writer) m_writer->SetShouldCompressFunction(shouldComp); m_shouldCompress = shouldComp; } }