/* * ArchiveWriter.cc * * Created on: 26 sept. 2013 * Author: CS */ #include "ArchiveWriter.hh" #include "archive.h" #include #include #include #include #include #include #include #include #include namespace postprocessing { log4cxx::LoggerPtr ArchiveWriter::_logger = log4cxx::Logger::getLogger( "AMDA-Kernel.ArchiveWriter"); ArchiveWriter::ArchiveWriter(const std::string& pArchiveFileName, const Formats& pFormat) : _open(true), _archive(archive_write_new()), _entry(archive_entry_new()), _archiveFileName( pArchiveFileName), _format(pFormat) { switch (pFormat) { case TAR: checkError(archive_write_set_format_gnutar(_archive), true); break; case ZIP: checkError(archive_write_set_format_zip(_archive), true); break; } checkError(archive_write_open_filename(_archive, pArchiveFileName.c_str()), true); } ArchiveWriter::~ArchiveWriter() { close(); } void ArchiveWriter::checkError(const int pErrCode, const bool pCloseBeforeThrow) { if (pCloseBeforeThrow && pErrCode == ARCHIVE_FATAL) close(); if (pErrCode != ARCHIVE_OK && pErrCode != ARCHIVE_WARN) throw std::runtime_error(archive_error_string(_archive)); } void ArchiveWriter::addHeader(const std::string& pFilePath, const std::string& pEntryName) { struct archive* a = archive_read_disk_new(); BOOST_SCOPE_EXIT(&a) { if (a != NULL) { archive_read_close(a); archive_read_free(a); } } BOOST_SCOPE_EXIT_END _entry = archive_entry_clear(_entry); archive_entry_set_pathname(_entry, pEntryName.c_str()); archive_entry_copy_sourcepath(_entry, pFilePath.c_str()); checkError(archive_read_disk_entry_from_file(a, _entry, -1, 0)); checkError(archive_write_header(_archive, _entry)); } void ArchiveWriter::addFinish() { archive_write_finish_entry(_archive); } void ArchiveWriter::addFile(const std::string& pFilePath, const std::string& pEntryName) { if (boost::filesystem::exists(pFilePath)) { boost::filesystem::file_status file_stat = boost::filesystem::status( pFilePath); addHeader(pFilePath, pEntryName.empty() ? pFilePath : pEntryName); if (file_stat.type() == boost::filesystem::regular_file) { std::fstream entry_file(pFilePath.c_str(), std::ios::in); char buff[8192]; while (entry_file.good()) { entry_file.read(buff, 8192); archive_write_data(_archive, buff, static_cast(entry_file.gcount())); } entry_file.close(); } else throw std::runtime_error("Entry file type not yet supported."); addFinish(); } else throw std::runtime_error("Entry file not found."); } void ArchiveWriter::close() { if (_open) { if (_archive != NULL) { archive_write_close(_archive); archive_write_free(_archive); LOG4CXX_INFO(_logger, "Written archive " + _archiveFileName); } if (_entry != NULL) archive_entry_free(_entry); _open = false; } } std::string ArchiveWriter::createArchive(const Formats& pFormat, const std::string& pExtension, const std::vector& pFiles, const std::string& pPrefix, const std::string& pOutDir) { if (pFiles.empty()) { LOG4CXX_WARN(_logger, "No file to archive or compress."); return std::string(); } // calculate out file name (timestamp) std::ostringstream archiveFileName; if (!pPrefix.empty()) { archiveFileName << pPrefix << "_"; } archiveFileName << std::time(0) << pExtension; std::string archiveCompletePath; // calculate out file path if (!pOutDir.empty()) { // user path archiveCompletePath = pOutDir + "/" + archiveFileName.str(); } else { // default path is first file parent path std::string firstFile = pFiles.front(); if(boost::filesystem::path(firstFile).parent_path().string().empty()){ archiveCompletePath = archiveFileName.str(); } else { archiveCompletePath = boost::filesystem::path(firstFile).parent_path().string() + "/" + archiveFileName.str(); } } // create archive ArchiveWriter writer(archiveCompletePath, pFormat); // add each file to the archive for (auto file : pFiles) { // Remove "./" at the begining of the filename if (file.compare (0, 2, "./") == 0) file = file.substr(2); boost::filesystem::path path(file); writer.addFile(file, path.c_str()); boost::filesystem::remove(path); } // close the archive writer.close(); return archiveCompletePath; } } /* namespace postprocessing */