diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp index 916773b90a..3dc9f86709 100644 --- a/Source/Core/DiscIO/CompressedBlob.cpp +++ b/Source/Core/DiscIO/CompressedBlob.cpp @@ -27,6 +27,7 @@ #include "DiscIO/Blob.h" #include "DiscIO/CompressedBlob.h" #include "DiscIO/DiscScrubber.h" +#include "DiscIO/Volume.h" namespace DiscIO { @@ -181,9 +182,11 @@ bool CompressFileToBlob(const std::string& infile_path, const std::string& outfi } DiscScrubber disc_scrubber; + std::unique_ptr volume; if (sub_type == 1) { - if (!disc_scrubber.SetupScrub(infile_path, block_size)) + volume = CreateVolumeFromFilename(infile_path); + if (!volume || !disc_scrubber.SetupScrub(volume.get(), block_size)) { PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.", infile_path.c_str()); diff --git a/Source/Core/DiscIO/DiscScrubber.cpp b/Source/Core/DiscIO/DiscScrubber.cpp index dc3c9bf590..0c944a782a 100644 --- a/Source/Core/DiscIO/DiscScrubber.cpp +++ b/Source/Core/DiscIO/DiscScrubber.cpp @@ -28,9 +28,11 @@ constexpr size_t CLUSTER_SIZE = 0x8000; DiscScrubber::DiscScrubber() = default; DiscScrubber::~DiscScrubber() = default; -bool DiscScrubber::SetupScrub(const std::string& filename, int block_size) +bool DiscScrubber::SetupScrub(const Volume* disc, int block_size) { - m_filename = filename; + if (!disc) + return false; + m_disc = disc; m_block_size = block_size; if (CLUSTER_SIZE % m_block_size != 0) @@ -40,20 +42,13 @@ bool DiscScrubber::SetupScrub(const std::string& filename, int block_size) return false; } - m_disc = CreateVolumeFromFilename(filename); - if (!m_disc) - return false; - m_file_size = m_disc->GetSize(); const size_t num_clusters = static_cast(m_file_size / CLUSTER_SIZE); // Warn if not DVD5 or DVD9 size if (num_clusters != 0x23048 && num_clusters != 0x46090) - { - WARN_LOG(DISCIO, "%s is not a standard sized Wii disc! (%zx blocks)", filename.c_str(), - num_clusters); - } + WARN_LOG(DISCIO, "Not a standard sized Wii disc! (%zx blocks)", num_clusters); // Table of free blocks m_free_table.resize(num_clusters, 1); @@ -61,8 +56,6 @@ bool DiscScrubber::SetupScrub(const std::string& filename, int block_size) // Fill out table of free blocks const bool success = ParseDisc(); - // Done with it; need it closed for the next part - m_disc.reset(); m_block_count = 0; m_is_scrubbing = success; @@ -72,10 +65,9 @@ bool DiscScrubber::SetupScrub(const std::string& filename, int block_size) size_t DiscScrubber::GetNextBlock(File::IOFile& in, u8* buffer) { const u64 current_offset = m_block_count * m_block_size; - const u64 i = current_offset / CLUSTER_SIZE; size_t read_bytes = 0; - if (m_is_scrubbing && m_free_table[i]) + if (CanBlockBeScrubbed(current_offset)) { DEBUG_LOG(DISCIO, "Freeing 0x%016" PRIx64, current_offset); std::fill(buffer, buffer + m_block_size, 0x00); @@ -92,6 +84,11 @@ size_t DiscScrubber::GetNextBlock(File::IOFile& in, u8* buffer) return read_bytes; } +bool DiscScrubber::CanBlockBeScrubbed(u64 offset) const +{ + return m_is_scrubbing && m_free_table[offset / CLUSTER_SIZE]; +} + void DiscScrubber::MarkAsUsed(u64 offset, u64 size) { u64 current_offset = offset; diff --git a/Source/Core/DiscIO/DiscScrubber.h b/Source/Core/DiscIO/DiscScrubber.h index 29af40c73f..15e0cda7f7 100644 --- a/Source/Core/DiscIO/DiscScrubber.h +++ b/Source/Core/DiscIO/DiscScrubber.h @@ -13,7 +13,6 @@ #pragma once #include -#include #include #include #include "Common/CommonTypes.h" @@ -35,8 +34,9 @@ public: DiscScrubber(); ~DiscScrubber(); - bool SetupScrub(const std::string& filename, int block_size); + bool SetupScrub(const Volume* disc, int block_size); size_t GetNextBlock(File::IOFile& in, u8* buffer); + bool CanBlockBeScrubbed(u64 offset) const; private: struct PartitionHeader final @@ -68,8 +68,7 @@ private: bool ParsePartitionData(const Partition& partition, PartitionHeader* header); void ParseFileSystemData(u64 partition_data_offset, const FileInfo& directory); - std::string m_filename; - std::unique_ptr m_disc; + const Volume* m_disc; std::vector m_free_table; u64 m_file_size = 0; diff --git a/Source/Core/DiscIO/VolumeVerifier.cpp b/Source/Core/DiscIO/VolumeVerifier.cpp index ac2f06cc15..74612656fa 100644 --- a/Source/Core/DiscIO/VolumeVerifier.cpp +++ b/Source/Core/DiscIO/VolumeVerifier.cpp @@ -29,6 +29,7 @@ #include "Core/IOS/IOSC.h" #include "DiscIO/Blob.h" #include "DiscIO/DiscExtractor.h" +#include "DiscIO/DiscScrubber.h" #include "DiscIO/Enums.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -629,6 +630,12 @@ void VolumeVerifier::CheckMisc() void VolumeVerifier::SetUpHashing() { + if (m_volume.GetVolumeType() == Platform::WiiDisc) + { + // Set up a DiscScrubber for checking whether blocks with errors are unused + m_scrubber.SetupScrub(&m_volume, VolumeWii::BLOCK_TOTAL_SIZE); + } + std::sort(m_blocks.begin(), m_blocks.end(), [](const BlockToVerify& b1, const BlockToVerify& b2) { return b1.offset < b2.offset; }); @@ -698,9 +705,17 @@ void VolumeVerifier::Process() 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]++; + const u64 offset = m_blocks[m_block_index].offset; + if (m_scrubber.CanBlockBeScrubbed(offset)) + { + WARN_LOG(DISCIO, "Integrity check failed for unused block at 0x%" PRIx64, offset); + m_unused_block_errors[m_blocks[m_block_index].partition]++; + } + else + { + WARN_LOG(DISCIO, "Integrity check failed for block at 0x%" PRIx64, offset); + m_block_errors[m_blocks[m_block_index].partition]++; + } } m_block_index++; } @@ -750,10 +765,22 @@ void VolumeVerifier::Finish() 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())); + const std::string text = StringFromFormat( + GetStringT("Errors were found in %zu blocks in the %s partition.").c_str(), pair.second, + name.c_str()); + AddProblem(Severity::Medium, text); + } + } + + for (auto pair : m_unused_block_errors) + { + if (pair.second > 0) + { + const std::string name = GetPartitionName(m_volume.GetPartitionType(pair.first)); + const std::string text = StringFromFormat( + GetStringT("Errors were found in %zu unused blocks in the %s partition.").c_str(), + pair.second, name.c_str()); + AddProblem(Severity::Low, text); } } diff --git a/Source/Core/DiscIO/VolumeVerifier.h b/Source/Core/DiscIO/VolumeVerifier.h index 4337fdce46..263ef65ff3 100644 --- a/Source/Core/DiscIO/VolumeVerifier.h +++ b/Source/Core/DiscIO/VolumeVerifier.h @@ -13,6 +13,7 @@ #include #include "Common/CommonTypes.h" +#include "DiscIO/DiscScrubber.h" #include "DiscIO/Volume.h" // To be used as follows: @@ -114,9 +115,11 @@ private: mbedtls_md5_context m_md5_context; mbedtls_sha1_context m_sha1_context; + DiscScrubber m_scrubber; std::vector m_blocks; size_t m_block_index = 0; // Index in m_blocks, not index in a specific partition std::map m_block_errors; + std::map m_unused_block_errors; bool m_started; bool m_done;