MacUpdater: check os version
This commit is contained in:
parent
68875dc06b
commit
089886a6f8
Source/Core
Common
MacUpdater
UpdaterCommon
WinUpdater
|
@ -2,7 +2,6 @@
|
||||||
// Updater will fail the update if the user does not meet this requirement.
|
// Updater will fail the update if the user does not meet this requirement.
|
||||||
OSMinimumVersionWin10=10.0.15063.0
|
OSMinimumVersionWin10=10.0.15063.0
|
||||||
OSMinimumVersionWin11=10.0.22000.0
|
OSMinimumVersionWin11=10.0.22000.0
|
||||||
OSMinimumVersionMacOS=10.14
|
|
||||||
|
|
||||||
// This is the runtime which was compiled against - providing a way for Updater to detect if update
|
// This is the runtime which was compiled against - providing a way for Updater to detect if update
|
||||||
// is needed before executing this binary. Note that, annoyingly, the version in environment
|
// is needed before executing this binary. Note that, annoyingly, the version in environment
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "UpdaterCommon/Platform.h"
|
#include "UpdaterCommon/Platform.h"
|
||||||
#include "UpdaterCommon/UI.h"
|
#include "UpdaterCommon/UI.h"
|
||||||
|
#include "UpdaterCommon/UpdaterCommon.h"
|
||||||
|
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -138,20 +139,56 @@ void UI::Init()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform::BuildInfo::BuildInfo(const std::string& content)
|
bool Platform::VersionCheck(const std::vector<TodoList::UpdateOp>& to_update,
|
||||||
|
const std::string& install_base_path, const std::string& temp_dir,
|
||||||
|
FILE* log_fp)
|
||||||
{
|
{
|
||||||
map = {{"OSMinimumVersionMacOS", ""}};
|
const auto op_it = std::find_if(to_update.cbegin(), to_update.cend(), [&](const auto& op) {
|
||||||
Parse(content);
|
return op.filename == "Dolphin.app/Contents/Info.plist";
|
||||||
}
|
});
|
||||||
|
if (op_it == to_update.cend())
|
||||||
|
return true;
|
||||||
|
|
||||||
bool Platform::VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_info)
|
const auto op = *op_it;
|
||||||
{
|
std::string plist_path = temp_dir + "/" + HexEncode(op.new_hash.data(), op.new_hash.size());
|
||||||
// TODO implement OS Minimum Version check
|
|
||||||
// It should go something like this:
|
NSData* data = [NSData dataWithContentsOfFile:[NSString stringWithCString:plist_path.c_str()]];
|
||||||
// auto target_version = next_build_info.GetVersion("OSMinimumVersionMacOS");
|
if (!data)
|
||||||
// if (!target_version.has_value() || current_version >= target_version)
|
{
|
||||||
// return true;
|
fprintf(log_fp, "Failed to read %s, skipping platform version check.\n", plist_path.c_str());
|
||||||
// show error
|
return true;
|
||||||
// return false;
|
}
|
||||||
|
|
||||||
|
NSError* error = nil;
|
||||||
|
NSDictionary* info_dict =
|
||||||
|
[NSPropertyListSerialization propertyListWithData:data
|
||||||
|
options:NSPropertyListImmutable
|
||||||
|
format:nil
|
||||||
|
error:&error];
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Failed to parse %s, skipping platform version check.\n", plist_path.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
NSString* min_version_str = info_dict[@"LSMinimumSystemVersion"];
|
||||||
|
if (!min_version_str)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "LSMinimumSystemVersion key missing, skipping platform version check.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray* components = [min_version_str componentsSeparatedByString:@"."];
|
||||||
|
NSOperatingSystemVersion next_version{
|
||||||
|
[components[0] integerValue], [components[1] integerValue], [components[2] integerValue]};
|
||||||
|
|
||||||
|
fprintf(log_fp, "Platform version check: next_version=%ld.%ld.%ld\n",
|
||||||
|
(long)next_version.majorVersion, (long)next_version.minorVersion,
|
||||||
|
(long)next_version.patchVersion);
|
||||||
|
|
||||||
|
if (![[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:next_version])
|
||||||
|
{
|
||||||
|
UI::Error("Please update macOS in order to update Dolphin.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,91 +10,10 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
#include "UpdaterCommon/UpdaterCommon.h"
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
struct BuildVersion
|
bool VersionCheck(const std::vector<TodoList::UpdateOp>& to_update,
|
||||||
{
|
const std::string& install_base_path, const std::string& temp_dir, FILE* log_fp);
|
||||||
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
|
} // namespace Platform
|
||||||
|
|
|
@ -34,51 +34,14 @@
|
||||||
|
|
||||||
// Refer to docs/autoupdate_overview.md for a detailed overview of the autoupdate process
|
// Refer to docs/autoupdate_overview.md for a detailed overview of the autoupdate process
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// Where to log updater output.
|
// Where to log updater output.
|
||||||
FILE* log_fp = stderr;
|
static FILE* log_fp = stderr;
|
||||||
|
|
||||||
// Public key used to verify update manifests.
|
// Public key used to verify update manifests.
|
||||||
const std::array<u8, 32> UPDATE_PUB_KEY = {
|
const std::array<u8, 32> UPDATE_PUB_KEY = {
|
||||||
0x2a, 0xb3, 0xd1, 0xdc, 0x6e, 0xf5, 0x07, 0xf6, 0xa0, 0x6c, 0x7c, 0x54, 0xdf, 0x54, 0xf4, 0x42,
|
0x2a, 0xb3, 0xd1, 0xdc, 0x6e, 0xf5, 0x07, 0xf6, 0xa0, 0x6c, 0x7c, 0x54, 0xdf, 0x54, 0xf4, 0x42,
|
||||||
0x80, 0xa6, 0x28, 0x8b, 0x6d, 0x70, 0x14, 0xb5, 0x4c, 0x34, 0x95, 0x20, 0x4d, 0xd4, 0xd3, 0x5d};
|
0x80, 0xa6, 0x28, 0x8b, 0x6d, 0x70, 0x14, 0xb5, 0x4c, 0x34, 0x95, 0x20, 0x4d, 0xd4, 0xd3, 0x5d};
|
||||||
|
|
||||||
struct Manifest
|
|
||||||
{
|
|
||||||
using Filename = std::string;
|
|
||||||
using Hash = std::array<u8, 16>;
|
|
||||||
std::map<Filename, Hash> entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Represent the operations to be performed by the updater.
|
|
||||||
struct TodoList
|
|
||||||
{
|
|
||||||
struct DownloadOp
|
|
||||||
{
|
|
||||||
Manifest::Filename filename;
|
|
||||||
Manifest::Hash hash{};
|
|
||||||
};
|
|
||||||
std::vector<DownloadOp> to_download;
|
|
||||||
|
|
||||||
struct UpdateOp
|
|
||||||
{
|
|
||||||
Manifest::Filename filename;
|
|
||||||
std::optional<Manifest::Hash> old_hash;
|
|
||||||
Manifest::Hash new_hash{};
|
|
||||||
};
|
|
||||||
std::vector<UpdateOp> to_update;
|
|
||||||
|
|
||||||
struct DeleteOp
|
|
||||||
{
|
|
||||||
Manifest::Filename filename;
|
|
||||||
Manifest::Hash old_hash{};
|
|
||||||
};
|
|
||||||
std::vector<DeleteOp> to_delete;
|
|
||||||
|
|
||||||
void Log() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool ProgressCallback(double total, double now, double, double)
|
bool ProgressCallback(double total, double now, double, double)
|
||||||
{
|
{
|
||||||
UI::SetCurrentProgress(static_cast<int>(now), static_cast<int>(total));
|
UI::SetCurrentProgress(static_cast<int>(now), static_cast<int>(total));
|
||||||
|
@ -289,35 +252,7 @@ bool PlatformVersionCheck(const std::vector<TodoList::UpdateOp>& to_update,
|
||||||
const std::string& install_base_path, const std::string& temp_dir)
|
const std::string& install_base_path, const std::string& temp_dir)
|
||||||
{
|
{
|
||||||
UI::SetDescription("Checking platform...");
|
UI::SetDescription("Checking platform...");
|
||||||
|
return Platform::VersionCheck(to_update, install_base_path, temp_dir, log_fp);
|
||||||
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 ComputeActionsToDo(Manifest this_manifest, Manifest next_manifest)
|
||||||
|
@ -732,7 +667,6 @@ std::optional<Options> ParseCommandLine(std::vector<std::string>& args)
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
}; // namespace
|
|
||||||
|
|
||||||
bool RunUpdater(std::vector<std::string> args)
|
bool RunUpdater(std::vector<std::string> args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,4 +14,41 @@
|
||||||
|
|
||||||
// Refer to docs/autoupdate_overview.md for a detailed overview of the autoupdate process
|
// Refer to docs/autoupdate_overview.md for a detailed overview of the autoupdate process
|
||||||
|
|
||||||
|
struct Manifest
|
||||||
|
{
|
||||||
|
using Filename = std::string;
|
||||||
|
using Hash = std::array<u8, 16>;
|
||||||
|
std::map<Filename, Hash> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represent the operations to be performed by the updater.
|
||||||
|
struct TodoList
|
||||||
|
{
|
||||||
|
struct DownloadOp
|
||||||
|
{
|
||||||
|
Manifest::Filename filename;
|
||||||
|
Manifest::Hash hash{};
|
||||||
|
};
|
||||||
|
std::vector<DownloadOp> to_download;
|
||||||
|
|
||||||
|
struct UpdateOp
|
||||||
|
{
|
||||||
|
Manifest::Filename filename;
|
||||||
|
std::optional<Manifest::Hash> old_hash;
|
||||||
|
Manifest::Hash new_hash{};
|
||||||
|
};
|
||||||
|
std::vector<UpdateOp> to_update;
|
||||||
|
|
||||||
|
struct DeleteOp
|
||||||
|
{
|
||||||
|
Manifest::Filename filename;
|
||||||
|
Manifest::Hash old_hash{};
|
||||||
|
};
|
||||||
|
std::vector<DeleteOp> to_delete;
|
||||||
|
|
||||||
|
void Log() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string HexEncode(const u8* buffer, size_t size);
|
||||||
|
Manifest::Hash ComputeHash(const std::string& contents);
|
||||||
bool RunUpdater(std::vector<std::string> args);
|
bool RunUpdater(std::vector<std::string> args);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/HttpRequest.h"
|
#include "Common/HttpRequest.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
|
@ -12,17 +13,106 @@
|
||||||
|
|
||||||
#include "UpdaterCommon/Platform.h"
|
#include "UpdaterCommon/Platform.h"
|
||||||
#include "UpdaterCommon/UI.h"
|
#include "UpdaterCommon/UI.h"
|
||||||
|
#include "UpdaterCommon/UpdaterCommon.h"
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
BuildInfo::BuildInfo(const std::string& content)
|
struct BuildVersion
|
||||||
{
|
{
|
||||||
map = {{"OSMinimumVersionWin10", ""},
|
u32 major{};
|
||||||
{"OSMinimumVersionWin11", ""},
|
u32 minor{};
|
||||||
{"VCToolsVersion", ""},
|
u32 build{};
|
||||||
{"VCToolsUpdateURL", ""}};
|
auto operator<=>(BuildVersion const& rhs) const = default;
|
||||||
Parse(content);
|
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)
|
||||||
|
{
|
||||||
|
map = {{"OSMinimumVersionWin10", ""},
|
||||||
|
{"OSMinimumVersionWin11", ""},
|
||||||
|
{"VCToolsVersion", ""},
|
||||||
|
{"VCToolsUpdateURL", ""}};
|
||||||
|
Parse(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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuildInfos
|
||||||
|
{
|
||||||
|
BuildInfo current;
|
||||||
|
BuildInfo next;
|
||||||
|
};
|
||||||
|
|
||||||
// This default value should be kept in sync with the value of VCToolsUpdateURL in
|
// This default value should be kept in sync with the value of VCToolsUpdateURL in
|
||||||
// build_info.txt.in
|
// build_info.txt.in
|
||||||
|
@ -63,14 +153,13 @@ static std::optional<BuildVersion> GetInstalledVCRuntimeVersion()
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VersionCheckResult VCRuntimeVersionCheck(const BuildInfo& this_build_info,
|
static VersionCheckResult VCRuntimeVersionCheck(const BuildInfos& build_infos)
|
||||||
const BuildInfo& next_build_info)
|
|
||||||
{
|
{
|
||||||
VersionCheckResult result;
|
VersionCheckResult result;
|
||||||
result.current_version = GetInstalledVCRuntimeVersion();
|
result.current_version = GetInstalledVCRuntimeVersion();
|
||||||
result.target_version = next_build_info.GetVersion("VCToolsVersion");
|
result.target_version = build_infos.next.GetVersion("VCToolsVersion");
|
||||||
|
|
||||||
auto existing_version = this_build_info.GetVersion("VCToolsVersion");
|
auto existing_version = build_infos.current.GetVersion("VCToolsVersion");
|
||||||
|
|
||||||
if (!result.target_version.has_value())
|
if (!result.target_version.has_value())
|
||||||
result.status = VersionCheckStatus::UpdateOptional;
|
result.status = VersionCheckStatus::UpdateOptional;
|
||||||
|
@ -155,10 +244,45 @@ static VersionCheckResult OSVersionCheck(const BuildInfo& build_info)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_info)
|
std::optional<BuildInfos> InitBuildInfos(const std::vector<TodoList::UpdateOp>& to_update,
|
||||||
|
const std::string& install_base_path,
|
||||||
|
const std::string& temp_dir, FILE* log_fp)
|
||||||
{
|
{
|
||||||
|
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 {};
|
||||||
|
|
||||||
|
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 {};
|
||||||
|
}
|
||||||
|
BuildInfos build_infos;
|
||||||
|
build_infos.next = Platform::BuildInfo(build_info_content);
|
||||||
|
|
||||||
|
build_info_path = install_base_path + DIR_SEP + "build_info.txt";
|
||||||
|
build_infos.current = 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());
|
||||||
|
build_infos.current = Platform::BuildInfo(build_info_content);
|
||||||
|
}
|
||||||
|
return build_infos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckBuildInfo(const BuildInfos& build_infos)
|
||||||
|
{
|
||||||
|
// The existing BuildInfo may have been modified. Be careful not to overly trust its contents!
|
||||||
|
|
||||||
// If the binary requires more recent OS, inform the user.
|
// If the binary requires more recent OS, inform the user.
|
||||||
auto os_check = OSVersionCheck(next_build_info);
|
auto os_check = OSVersionCheck(build_infos.next);
|
||||||
if (os_check.status == VersionCheckStatus::UpdateRequired)
|
if (os_check.status == VersionCheckStatus::UpdateRequired)
|
||||||
{
|
{
|
||||||
UI::Error("Please update Windows in order to update Dolphin.");
|
UI::Error("Please update Windows in order to update Dolphin.");
|
||||||
|
@ -167,13 +291,13 @@ bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_
|
||||||
|
|
||||||
// Check if application being launched needs more recent version of VC Redist. If so, download
|
// Check if application being launched needs more recent version of VC Redist. If so, download
|
||||||
// latest updater and execute it.
|
// latest updater and execute it.
|
||||||
auto vc_check = VCRuntimeVersionCheck(this_build_info, next_build_info);
|
auto vc_check = VCRuntimeVersionCheck(build_infos);
|
||||||
if (vc_check.status != VersionCheckStatus::NothingToDo)
|
if (vc_check.status != VersionCheckStatus::NothingToDo)
|
||||||
{
|
{
|
||||||
// Don't bother checking status of the install itself, just check if we actually see the new
|
// Don't bother checking status of the install itself, just check if we actually see the new
|
||||||
// version.
|
// version.
|
||||||
VCRuntimeUpdate(next_build_info);
|
VCRuntimeUpdate(build_infos.next);
|
||||||
vc_check = VCRuntimeVersionCheck(this_build_info, next_build_info);
|
vc_check = VCRuntimeVersionCheck(build_infos);
|
||||||
if (vc_check.status == VersionCheckStatus::UpdateRequired)
|
if (vc_check.status == VersionCheckStatus::UpdateRequired)
|
||||||
{
|
{
|
||||||
// The update is required and the install failed for some reason.
|
// The update is required and the install failed for some reason.
|
||||||
|
@ -184,4 +308,17 @@ bool VersionCheck(const BuildInfo& this_build_info, const BuildInfo& next_build_
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VersionCheck(const std::vector<TodoList::UpdateOp>& to_update,
|
||||||
|
const std::string& install_base_path, const std::string& temp_dir, FILE* log_fp)
|
||||||
|
{
|
||||||
|
auto build_infos = InitBuildInfos(to_update, install_base_path, temp_dir, log_fp);
|
||||||
|
// If there's no build info, it means the check should be skipped.
|
||||||
|
if (!build_infos.has_value())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return CheckBuildInfo(build_infos.value());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
Loading…
Reference in New Issue