WinUpdater: Check OS and VC++ Redist versions.

This commit is contained in:
Shawn Hoffman
2022-09-10 23:21:12 -07:00
parent 22197c09a3
commit 717c36bc43
13 changed files with 435 additions and 8 deletions

View File

@ -0,0 +1,100 @@
// Copyright 2018 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <map>
#include <optional>
#include <sstream>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
namespace Platform
{
struct BuildVersion
{
u32 major{};
u32 minor{};
u32 build{};
auto operator<=>(BuildVersion const& rhs) const = default;
static std::optional<BuildVersion> from_string(const std::string& str)
{
auto components = SplitString(str, '.');
// Allow variable number of components (truncating after "build"), but not
// empty.
if (components.size() == 0)
return {};
BuildVersion version;
if (!TryParse(components[0], &version.major, 10))
return {};
if (components.size() > 1 && !TryParse(components[1], &version.minor, 10))
return {};
if (components.size() > 2 && !TryParse(components[2], &version.build, 10))
return {};
return version;
}
};
enum class VersionCheckStatus
{
NothingToDo,
UpdateOptional,
UpdateRequired,
};
struct VersionCheckResult
{
VersionCheckStatus status{VersionCheckStatus::NothingToDo};
std::optional<BuildVersion> current_version{};
std::optional<BuildVersion> target_version{};
};
class BuildInfo
{
using Map = std::map<std::string, std::string>;
public:
BuildInfo() = default;
BuildInfo(const std::string& content);
std::optional<std::string> GetString(const std::string& name) const
{
auto it = map.find(name);
if (it == map.end() || it->second.size() == 0)
return {};
return it->second;
}
std::optional<BuildVersion> GetVersion(const std::string& name) const
{
auto str = GetString(name);
if (!str.has_value())
return {};
return BuildVersion::from_string(str.value());
}
private:
void Parse(const std::string& content)
{
std::stringstream content_stream(content);
std::string line;
while (std::getline(content_stream, line))
{
if (line.starts_with("//"))
continue;
const size_t equals_index = line.find('=');
if (equals_index == line.npos)
continue;
auto key = line.substr(0, equals_index);
auto key_it = map.find(key);
if (key_it == map.end())
continue;
key_it->second = line.substr(equals_index + 1);
}
}
Map map;
};
bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_info);
} // namespace Platform

View File

@ -18,6 +18,7 @@
#include "Common/HttpRequest.h"
#include "Common/ScopeGuard.h"
#include "Common/StringUtil.h"
#include "UpdaterCommon/Platform.h"
#include "UpdaterCommon/UI.h"
#ifndef _WIN32
@ -278,6 +279,41 @@ bool DownloadContent(const std::vector<TodoList::DownloadOp>& to_download,
return true;
}
bool PlatformVersionCheck(const std::vector<TodoList::UpdateOp>& to_update,
const std::string& install_base_path, const std::string& temp_dir)
{
UI::SetDescription("Checking platform...");
const auto op_it = std::find_if(to_update.cbegin(), to_update.cend(),
[&](const auto& op) { return op.filename == "build_info.txt"; });
if (op_it == to_update.cend())
return true;
const auto op = *op_it;
std::string build_info_path =
temp_dir + DIR_SEP + HexEncode(op.new_hash.data(), op.new_hash.size());
std::string build_info_content;
if (!File::ReadFileToString(build_info_path, build_info_content) ||
op.new_hash != ComputeHash(build_info_content))
{
fprintf(log_fp, "Failed to read %s\n.", build_info_path.c_str());
return false;
}
auto next_build_info = Platform::BuildInfo(build_info_content);
build_info_path = install_base_path + DIR_SEP + "build_info.txt";
auto this_build_info = Platform::BuildInfo();
if (File::ReadFileToString(build_info_path, build_info_content))
{
if (op.old_hash != ComputeHash(build_info_content))
fprintf(log_fp, "Using modified existing BuildInfo %s.\n", build_info_path.c_str());
this_build_info = Platform::BuildInfo(build_info_content);
}
// The existing BuildInfo may have been modified. Be careful not to overly trust its contents!
return Platform::VersionCheck(this_build_info, next_build_info);
}
TodoList ComputeActionsToDo(Manifest this_manifest, Manifest next_manifest)
{
TodoList todo;
@ -474,6 +510,11 @@ bool PerformUpdate(const TodoList& todo, const std::string& install_base_path,
return false;
fprintf(log_fp, "Download step completed.\n");
fprintf(log_fp, "Starting platform version check step...\n");
if (!PlatformVersionCheck(todo.to_update, install_base_path, temp_path))
return false;
fprintf(log_fp, "Platform version check step completed.\n");
fprintf(log_fp, "Starting update step...\n");
if (!UpdateFiles(todo.to_update, install_base_path, temp_path))
return false;