#include "ModuleManager.h" #include "HashUtils.h" #include #include #include #include void ModuleManager::applyUpdate(const std::string & moduleId, const ModuleUpdate & update) { auto module = m_db.findModule(moduleId).value_or(Module{ moduleId, -1 , {} }); applyUpdate(module, update); m_db.storeModule(module); } void ModuleManager::applyUpdate(Module & module, const ModuleUpdate & update) { const auto updatePath = retrieveUpdate(update.updateUri); auto hash = calcSHA256(updatePath); if (hash != boost::algorithm::to_upper_copy(update.checksum)) { throw std::runtime_error("Integrity check of the update has failed"); } if (!(update.flag & static_cast(ModuleUpdateFlags::incremental))) { // We should remove old files first before extracting new ones boost::filesystem::path basePath(m_appBaseDir); std::for_each(module.filePaths.begin(), module.filePaths.end(), [&basePath](const auto& filePath) { boost::filesystem::remove(basePath / filePath); }); module.filePaths.clear(); } auto filePaths = extractUpdate(updatePath, update.instPath); module.version = update.version; module.filePaths.insert(filePaths.begin(), filePaths.end()); } boost::filesystem::path ModuleManager::retrieveUpdate(const std::string & updateUrl) { return m_downloader.download(updateUrl); } #include #include std::string zipErrorToStr(int err) { static const int bufsize = 100; char buf[bufsize] = { 0 }; zip_error_to_str(buf, bufsize, err, errno); return buf; } inline std::set ModuleManager::extractUpdate(const boost::filesystem::path& archivePath, const std::string & targetPath) { struct zip_file *zf = nullptr; struct zip_stat sb; int err; boost::filesystem::path basePath(m_appBaseDir); basePath /= targetPath; boost::filesystem::path basePathRel(targetPath); if (!boost::filesystem::exists(basePath)) { boost::filesystem::create_directories(basePath); } if (!boost::filesystem::is_directory(basePath)) { throw std::runtime_error("Target path is not a directory"); } std::set extractedFiles; struct zip *za = zip_open(archivePath.string().c_str(), 0, &err); if (za == NULL) { throw std::runtime_error(zipErrorToStr(err)); } char buf[1024] = { 0 }; const auto numZipEntries = zip_get_num_entries(za, 0); for (int i = 0; i < numZipEntries; ++i) { if (zip_stat_index(za, i, 0, &sb) == 0) { printf("==================\n"); auto len = strlen(sb.name); printf("Name: [%s], ", sb.name); printf("Size: [%llu], ", sb.size); printf("mtime: [%u]\n", (unsigned int)sb.mtime); auto outPath = basePath / sb.name; auto outPathRel = basePathRel / sb.name; if (sb.name[len - 1] == '/') { if (!boost::filesystem::is_directory(outPath) && !boost::filesystem::create_directory(outPath)) { throw std::runtime_error("Directory can't be extracted"); } } else { zf = zip_fopen_index(za, i, 0); if (!zf) { throw std::runtime_error("Can't open file from the archive"); } { std::ofstream os(outPath.string(), std::ofstream::binary); uint64_t sum = 0; while (sum != sb.size) { auto len = zip_fread(zf, buf, sizeof(buf)); if (len < 0) { throw std::runtime_error("Can't read file from the archive"); } os.write(buf, len); sum += len; } } boost::filesystem::last_write_time(outPath, sb.mtime); extractedFiles.insert(outPathRel.string()); zip_fclose(zf); } } else { throw std::runtime_error("Could not get file information from archive"); } } if (zip_close(za) == -1) { throw std::runtime_error("Can't close the zip archive"); } return extractedFiles; }