151 lines
4.4 KiB
C++
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;
|
|
}
|