summaryrefslogtreecommitdiff
path: root/Source/Core/DiscIO/VolumeVerifier.cpp
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2019-03-26 17:22:18 +0100
committerJosJuice <josjuice@gmail.com>2019-04-09 14:18:45 +0200
commit4fd2d8e8c4db14cf01576ab228964b80c8ec37ad (patch)
treeb157a3b7936814fd6aff6fba0f1b54b61c20e1f6 /Source/Core/DiscIO/VolumeVerifier.cpp
parent84cbd5150f62bd5dd4a8d621fd0ccf7623ca4e2c (diff)
VolumeVerifier: Check hashes in Wii partitions
Diffstat (limited to 'Source/Core/DiscIO/VolumeVerifier.cpp')
-rw-r--r--Source/Core/DiscIO/VolumeVerifier.cpp95
1 files changed, 82 insertions, 13 deletions
diff --git a/Source/Core/DiscIO/VolumeVerifier.cpp b/Source/Core/DiscIO/VolumeVerifier.cpp
index 7d3eba4c8f..2201784d1c 100644
--- a/Source/Core/DiscIO/VolumeVerifier.cpp
+++ b/Source/Core/DiscIO/VolumeVerifier.cpp
@@ -14,6 +14,7 @@
#include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
+#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Common/Swap.h"
@@ -62,6 +63,9 @@ void VolumeVerifier::Start()
CheckCorrectlySigned(PARTITION_NONE, GetStringT("This title is not correctly signed."));
CheckDiscSize();
CheckMisc();
+
+ std::sort(m_blocks.begin(), m_blocks.end(),
+ [](const BlockToVerify& b1, const BlockToVerify& b2) { return b1.offset < b2.offset; });
}
void VolumeVerifier::CheckPartitions()
@@ -164,18 +168,7 @@ bool VolumeVerifier::CheckPartition(const Partition& partition)
else if (*type == PARTITION_UPDATE)
severity = Severity::Low;
- std::string name = NameForPartitionType(*type, false);
- if (ShouldHaveMasterpiecePartitions() && *type > 0xFF)
- {
- // i18n: This string is referring to a game mode in Super Smash Bros. Brawl called Masterpieces
- // where you play demos of NES/SNES/N64 games. This string is referring to a specific such demo
- // rather than the game mode as a whole, so please use the singular form. Official translations:
- // 名作トライアル (Japanese), Masterpieces (English), Meisterstücke (German), Chefs-d'œuvre
- // (French), Clásicos (Spanish), Capolavori (Italian), 클래식 게임 체험판 (Korean).
- // If your language is not one of the languages above, consider leaving the string untranslated
- // so that people will recognize it as the name of the game mode.
- name = StringFromFormat(GetStringT("%s (Masterpiece)").c_str(), name.c_str());
- }
+ const std::string name = GetPartitionName(type);
if (partition.offset % VolumeWii::BLOCK_TOTAL_SIZE != 0 ||
m_volume.PartitionOffsetToRawOffset(0, partition) % VolumeWii::BLOCK_TOTAL_SIZE != 0)
@@ -189,6 +182,13 @@ bool VolumeVerifier::CheckPartition(const Partition& partition)
partition, StringFromFormat(GetStringT("The %s partition is not correctly signed.").c_str(),
name.c_str()));
+ if (m_volume.SupportsIntegrityCheck() && !m_volume.CheckH3TableIntegrity(partition))
+ {
+ const std::string text = StringFromFormat(
+ GetStringT("The H3 hash table for the %s partition is not correct.").c_str(), name.c_str());
+ AddProblem(Severity::Low, text);
+ }
+
bool invalid_disc_header = false;
std::vector<u8> disc_header(0x80);
constexpr u32 WII_MAGIC = 0x5D1C9EA3;
@@ -262,9 +262,43 @@ bool VolumeVerifier::CheckPartition(const Partition& partition)
}
}
+ // Prepare for hash verification in the Process step
+ if (m_volume.SupportsIntegrityCheck())
+ {
+ u64 offset = m_volume.PartitionOffsetToRawOffset(0, partition);
+ const std::optional<u64> size =
+ m_volume.ReadSwappedAndShifted(partition.offset + 0x2bc, PARTITION_NONE);
+ const u64 end_offset = offset + size.value_or(0);
+
+ for (size_t i = 0; offset < end_offset; ++i, offset += VolumeWii::BLOCK_TOTAL_SIZE)
+ m_blocks.emplace_back(BlockToVerify{partition, offset, i});
+
+ m_block_errors.emplace(partition, 0);
+ }
+
return true;
}
+std::string VolumeVerifier::GetPartitionName(std::optional<u32> type) const
+{
+ if (!type)
+ return "???";
+
+ std::string name = NameForPartitionType(*type, false);
+ if (ShouldHaveMasterpiecePartitions() && *type > 0xFF)
+ {
+ // i18n: This string is referring to a game mode in Super Smash Bros. Brawl called Masterpieces
+ // where you play demos of NES/SNES/N64 games. This string is referring to a specific such demo
+ // rather than the game mode as a whole, so please use the singular form. Official translations:
+ // 名作トライアル (Japanese), Masterpieces (English), Meisterstücke (German), Chefs-d'œuvre
+ // (French), Clásicos (Spanish), Capolavori (Italian), 클래식 게임 체험판 (Korean).
+ // If your language is not one of the languages above, consider leaving the string untranslated
+ // so that people will recognize it as the name of the game mode.
+ name = StringFromFormat(GetStringT("%s (Masterpiece)").c_str(), name.c_str());
+ }
+ return name;
+}
+
void VolumeVerifier::CheckCorrectlySigned(const Partition& partition, const std::string& error_text)
{
IOS::HLE::Kernel ios;
@@ -596,7 +630,30 @@ void VolumeVerifier::Process()
if (m_progress == m_max_progress)
return;
- m_progress += std::min(m_max_progress - m_progress, BLOCK_SIZE);
+ u64 bytes_to_read = BLOCK_SIZE;
+ if (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset == m_progress)
+ {
+ bytes_to_read = VolumeWii::BLOCK_TOTAL_SIZE;
+ }
+ else if (m_block_index + 1 < m_blocks.size() && m_blocks[m_block_index + 1].offset > m_progress)
+ {
+ bytes_to_read = std::min(bytes_to_read, m_blocks[m_block_index + 1].offset - m_progress);
+ }
+ bytes_to_read = std::min(bytes_to_read, m_max_progress - m_progress);
+
+ m_progress += bytes_to_read;
+
+ while (m_block_index < m_blocks.size() && m_blocks[m_block_index].offset < m_progress)
+ {
+ if (!m_volume.CheckBlockIntegrity(m_blocks[m_block_index].block_index,
+ m_blocks[m_block_index].partition))
+ {
+ WARN_LOG(DISCIO, "Integrity check failed for block at 0x%" PRIx64,
+ m_blocks[m_block_index].offset);
+ m_block_errors[m_blocks[m_block_index].partition]++;
+ }
+ m_block_index++;
+ }
}
u64 VolumeVerifier::GetBytesProcessed() const
@@ -615,6 +672,18 @@ void VolumeVerifier::Finish()
return;
m_done = true;
+ for (auto pair : m_block_errors)
+ {
+ if (pair.second > 0)
+ {
+ const std::string name = GetPartitionName(m_volume.GetPartitionType(pair.first));
+ AddProblem(Severity::Medium,
+ StringFromFormat(
+ GetStringT("Errors were found in %zu blocks in the %s partition.").c_str(),
+ pair.second, name.c_str()));
+ }
+ }
+
// Show the most serious problems at the top
std::stable_sort(m_result.problems.begin(), m_result.problems.end(),
[](const Problem& p1, const Problem& p2) { return p1.severity > p2.severity; });