libLicenseClient/src/ModuleManager.cpp
2018-03-27 23:03:06 +02:00

151 lines
4.4 KiB
C++

#include "ModuleManager.h"
#include "HashUtils.h"
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <algorithm>
#include <cstdio>
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<uint32_t>(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 <zip.h>
#include <stdio.h>
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<std::string> 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<std::string> 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;
}