diff options
| author | Shawn Hoffman <godisgovernment@gmail.com> | 2022-10-27 13:24:36 -0700 |
|---|---|---|
| committer | Shawn Hoffman <godisgovernment@gmail.com> | 2022-10-30 12:04:57 -0700 |
| commit | 089886a6f869992f7566ee9543e136e136b168aa (patch) | |
| tree | 85a80d8e46df5707cc17db53e99122a435f4856d /Source/Core/WinUpdater | |
| parent | 68875dc06b8c9aa72cd2bc87d3b2d4eda73e020c (diff) | |
MacUpdater: check os version
Diffstat (limited to 'Source/Core/WinUpdater')
| -rw-r--r-- | Source/Core/WinUpdater/Platform.cpp | 169 |
1 files changed, 153 insertions, 16 deletions
diff --git a/Source/Core/WinUpdater/Platform.cpp b/Source/Core/WinUpdater/Platform.cpp index 8c79479560..565d53c413 100644 --- a/Source/Core/WinUpdater/Platform.cpp +++ b/Source/Core/WinUpdater/Platform.cpp @@ -4,6 +4,7 @@ #include <map> #include <optional> +#include "Common/CommonPaths.h" #include "Common/FileUtil.h" #include "Common/HttpRequest.h" #include "Common/IOFile.h" @@ -12,17 +13,106 @@ #include "UpdaterCommon/Platform.h" #include "UpdaterCommon/UI.h" +#include "UpdaterCommon/UpdaterCommon.h" namespace Platform { -BuildInfo::BuildInfo(const std::string& content) +struct BuildVersion { - map = {{"OSMinimumVersionWin10", ""}, - {"OSMinimumVersionWin11", ""}, - {"VCToolsVersion", ""}, - {"VCToolsUpdateURL", ""}}; - Parse(content); -} + 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) + { + 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 // build_info.txt.in @@ -63,14 +153,13 @@ static std::optional<BuildVersion> GetInstalledVCRuntimeVersion() return version; } -static VersionCheckResult VCRuntimeVersionCheck(const BuildInfo& this_build_info, - const BuildInfo& next_build_info) +static VersionCheckResult VCRuntimeVersionCheck(const BuildInfos& build_infos) { VersionCheckResult result; 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()) result.status = VersionCheckStatus::UpdateOptional; @@ -155,10 +244,45 @@ static VersionCheckResult OSVersionCheck(const BuildInfo& build_info) 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. - auto os_check = OSVersionCheck(next_build_info); + auto os_check = OSVersionCheck(build_infos.next); if (os_check.status == VersionCheckStatus::UpdateRequired) { 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 // 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) { // Don't bother checking status of the install itself, just check if we actually see the new // version. - VCRuntimeUpdate(next_build_info); - vc_check = VCRuntimeVersionCheck(this_build_info, next_build_info); + VCRuntimeUpdate(build_infos.next); + vc_check = VCRuntimeVersionCheck(build_infos); if (vc_check.status == VersionCheckStatus::UpdateRequired) { // 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; } + +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 |
