Skip to content
Permalink
Browse files

Merge pull request #7922 from JosJuice/verify-disc

Add a Verify tab to game properties
  • Loading branch information...
JosJuice committed Apr 11, 2019
2 parents 372b855 + 8709b21 commit d5ed3cbd88b9cd473b4de5fbbf576ab18db2ab37
Showing with 1,610 additions and 259 deletions.
  1. +21 −20 Source/Core/Core/IOS/ES/ES.h
  2. +5 −0 Source/Core/Core/IOS/ES/Formats.cpp
  3. +1 −0 Source/Core/Core/IOS/ES/Formats.h
  4. +1 −0 Source/Core/DiscIO/Blob.h
  5. +1 −0 Source/Core/DiscIO/CISOBlob.h
  6. +1 −0 Source/Core/DiscIO/CMakeLists.txt
  7. +4 −1 Source/Core/DiscIO/CompressedBlob.cpp
  8. +2 −1 Source/Core/DiscIO/CompressedBlob.h
  9. +1 −0 Source/Core/DiscIO/DirectoryBlob.h
  10. +11 −6 Source/Core/DiscIO/DiscExtractor.cpp
  11. +6 −1 Source/Core/DiscIO/DiscExtractor.h
  12. +2 −0 Source/Core/DiscIO/DiscIO.vcxproj
  13. +6 −0 Source/Core/DiscIO/DiscIO.vcxproj.filters
  14. +11 −14 Source/Core/DiscIO/DiscScrubber.cpp
  15. +3 −4 Source/Core/DiscIO/DiscScrubber.h
  16. +2 −1 Source/Core/DiscIO/DriveBlob.h
  17. +39 −11 Source/Core/DiscIO/Enums.cpp
  18. +5 −2 Source/Core/DiscIO/Enums.h
  19. +2 −1 Source/Core/DiscIO/FileBlob.h
  20. +2 −1 Source/Core/DiscIO/TGCBlob.h
  21. +1 −0 Source/Core/DiscIO/Volume.cpp
  22. +13 −2 Source/Core/DiscIO/Volume.h
  23. +2 −1 Source/Core/DiscIO/VolumeFileBlobReader.h
  24. +8 −2 Source/Core/DiscIO/VolumeGC.cpp
  25. +1 −0 Source/Core/DiscIO/VolumeGC.h
  26. +912 −0 Source/Core/DiscIO/VolumeVerifier.cpp
  27. +134 −0 Source/Core/DiscIO/VolumeVerifier.h
  28. +48 −10 Source/Core/DiscIO/VolumeWad.cpp
  29. +13 −3 Source/Core/DiscIO/VolumeWad.h
  30. +101 −60 Source/Core/DiscIO/VolumeWii.cpp
  31. +16 −9 Source/Core/DiscIO/VolumeWii.h
  32. +2 −1 Source/Core/DiscIO/WbfsBlob.h
  33. +1 −0 Source/Core/DolphinQt/CMakeLists.txt
  34. +3 −42 Source/Core/DolphinQt/Config/FilesystemWidget.cpp
  35. +2 −6 Source/Core/DolphinQt/Config/FilesystemWidget.h
  36. +0 −53 Source/Core/DolphinQt/Config/InfoWidget.cpp
  37. +0 −3 Source/Core/DolphinQt/Config/InfoWidget.h
  38. +19 −4 Source/Core/DolphinQt/Config/PropertiesDialog.cpp
  39. +156 −0 Source/Core/DolphinQt/Config/VerifyWidget.cpp
  40. +49 −0 Source/Core/DolphinQt/Config/VerifyWidget.h
  41. +3 −0 Source/Core/DolphinQt/DolphinQt.vcxproj
@@ -140,6 +140,27 @@ class ES final : public Device

bool CreateTitleDirectories(u64 title_id, u16 group_id) const;

enum class VerifyContainerType
{
TMD,
Ticket,
Device,
};
enum class VerifyMode
{
// Whether or not new certificates should be added to the certificate store (/sys/cert.sys).
DoNotUpdateCertStore,
UpdateCertStore,
};
// On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it.
// The caller is responsible for using IOSC_DeleteObject.
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::SignedBlobReader& signed_blob,
const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::CertReader& certificate,
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);

private:
enum
{
@@ -308,29 +329,9 @@ class ES final : public Device
ReturnCode CheckStreamKeyPermissions(u32 uid, const u8* ticket_view,
const IOS::ES::TMDReader& tmd) const;

enum class VerifyContainerType
{
TMD,
Ticket,
Device,
};
enum class VerifyMode
{
// Whether or not new certificates should be added to the certificate store (/sys/cert.sys).
DoNotUpdateCertStore,
UpdateCertStore,
};
bool IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& issuer_cert) const;
ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
ReturnCode WriteNewCertToStore(const IOS::ES::CertReader& cert);
// On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it.
// The caller is responsible for using IOSC_DeleteObject.
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::SignedBlobReader& signed_blob,
const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::CertReader& certificate,
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);

// Start a title import.
bool InitImport(const IOS::ES::TMDReader& tmd);
@@ -441,6 +441,11 @@ u64 TicketReader::GetTitleId() const
return Common::swap64(m_bytes.data() + offsetof(Ticket, title_id));
}

u8 TicketReader::GetCommonKeyIndex() const
{
return m_bytes[offsetof(Ticket, common_key_index)];
}

std::array<u8, 16> TicketReader::GetTitleKey(const HLE::IOSC& iosc) const
{
u8 iv[16] = {};
@@ -240,6 +240,7 @@ class TicketReader final : public SignedBlobReader

u32 GetDeviceId() const;
u64 GetTitleId() const;
u8 GetCommonKeyIndex() const;
// Get the decrypted title key.
std::array<u8, 16> GetTitleKey(const HLE::IOSC& iosc) const;
// Same as the above version, but guesses the console type depending on the issuer
@@ -44,6 +44,7 @@ class BlobReader
virtual BlobType GetBlobType() const = 0;
virtual u64 GetRawSize() const = 0;
virtual u64 GetDataSize() const = 0;
virtual bool IsDataSizeAccurate() const = 0;

// NOT thread-safe - can't call this from multiple threads.
virtual bool Read(u64 offset, u64 size, u8* out_ptr) = 0;
@@ -40,6 +40,7 @@ class CISOFileReader : public BlobReader
// The CISO format does not save the original file size.
// This function returns an upper bound.
u64 GetDataSize() const override;
bool IsDataSizeAccurate() const override { return false; }

u64 GetRawSize() const override;
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
@@ -16,6 +16,7 @@ add_library(discio
Volume.cpp
VolumeFileBlobReader.cpp
VolumeGC.cpp
VolumeVerifier.cpp
VolumeWad.cpp
VolumeWii.cpp
WiiSaveBanner.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> 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());
@@ -49,8 +49,9 @@ class CompressedBlobReader : public SectorReader
~CompressedBlobReader();
const CompressedBlobHeader& GetHeader() const { return m_header; }
BlobType GetBlobType() const override { return BlobType::GCZ; }
u64 GetDataSize() const override { return m_header.data_size; }
u64 GetRawSize() const override { return m_file_size; }
u64 GetDataSize() const override { return m_header.data_size; }
bool IsDataSizeAccurate() const override { return true; }
u64 GetBlockCompressedSize(u64 block_num) const;
bool GetBlock(u64 block_num, u8* out_ptr) override;

@@ -146,6 +146,7 @@ class DirectoryBlobReader : public BlobReader
BlobType GetBlobType() const override;
u64 GetRawSize() const override;
u64 GetDataSize() const override;
bool IsDataSizeAccurate() const override { return true; }

private:
struct PartitionWithType
@@ -19,16 +19,21 @@

namespace DiscIO
{
std::string DirectoryNameForPartitionType(u32 partition_type)
std::string NameForPartitionType(u32 partition_type, bool include_prefix)
{
switch (partition_type)
{
case 0:
case PARTITION_DATA:
return "DATA";
case 1:
case PARTITION_UPDATE:
return "UPDATE";
case 2:
case PARTITION_CHANNEL:
return "CHANNEL";
case PARTITION_INSTALL:
// wit doesn't recognize the name "INSTALL", so we can't use it when naming partition folders
if (!include_prefix)
return "INSTALL";
// [[fallthrough]]
default:
const std::string type_as_game_id{static_cast<char>((partition_type >> 24) & 0xFF),
static_cast<char>((partition_type >> 16) & 0xFF),
@@ -37,10 +42,10 @@ std::string DirectoryNameForPartitionType(u32 partition_type)
if (std::all_of(type_as_game_id.cbegin(), type_as_game_id.cend(),
[](char c) { return std::isalnum(c, std::locale::classic()); }))
{
return "P-" + type_as_game_id;
return include_prefix ? "P-" + type_as_game_id : type_as_game_id;
}

return StringFromFormat("P%u", partition_type);
return StringFromFormat(include_prefix ? "P%u" : "%u", partition_type);
}
}

@@ -15,7 +15,12 @@ class FileInfo;
struct Partition;
class Volume;

std::string DirectoryNameForPartitionType(u32 partition_type);
constexpr u32 PARTITION_DATA = 0;
constexpr u32 PARTITION_UPDATE = 1;
constexpr u32 PARTITION_CHANNEL = 2; // Mario Kart Wii, Wii Fit, Wii Fit Plus, Rabbids Go Home
constexpr u32 PARTITION_INSTALL = 3; // Dragon Quest X only

std::string NameForPartitionType(u32 partition_type, bool include_prefix);

u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0);
@@ -52,6 +52,7 @@
<ClCompile Include="Volume.cpp" />
<ClCompile Include="VolumeFileBlobReader.cpp" />
<ClCompile Include="VolumeGC.cpp" />
<ClCompile Include="VolumeVerifier.cpp" />
<ClCompile Include="VolumeWad.cpp" />
<ClCompile Include="VolumeWii.cpp" />
<ClCompile Include="WbfsBlob.cpp" />
@@ -75,6 +76,7 @@
<ClInclude Include="Volume.h" />
<ClInclude Include="VolumeFileBlobReader.h" />
<ClInclude Include="VolumeGC.h" />
<ClInclude Include="VolumeVerifier.h" />
<ClInclude Include="VolumeWad.h" />
<ClInclude Include="VolumeWii.h" />
<ClInclude Include="WbfsBlob.h" />
@@ -84,6 +84,9 @@
<ClCompile Include="WiiSaveBanner.cpp">
<Filter>NAND</Filter>
</ClCompile>
<ClCompile Include="VolumeVerifier.cpp">
<Filter>Volume</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DiscScrubber.h">
@@ -149,6 +152,9 @@
<ClInclude Include="WiiSaveBanner.h">
<Filter>NAND</Filter>
</ClInclude>
<ClInclude Include="VolumeVerifier.h">
<Filter>Volume</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
@@ -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,29 +42,20 @@ 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<size_t>(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);

// 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;
@@ -13,7 +13,6 @@
#pragma once

#include <array>
#include <memory>
#include <string>
#include <vector>
#include "Common/CommonTypes.h"
@@ -35,8 +34,9 @@ class DiscScrubber final
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 @@ class DiscScrubber final
bool ParsePartitionData(const Partition& partition, PartitionHeader* header);
void ParseFileSystemData(u64 partition_data_offset, const FileInfo& directory);

std::string m_filename;
std::unique_ptr<Volume> m_disc;
const Volume* m_disc;

std::vector<u8> m_free_table;
u64 m_file_size = 0;
@@ -24,8 +24,9 @@ class DriveReader : public SectorReader
static std::unique_ptr<DriveReader> Create(const std::string& drive);
~DriveReader();
BlobType GetBlobType() const override { return BlobType::DRIVE; }
u64 GetDataSize() const override { return m_size; }
u64 GetRawSize() const override { return m_size; }
u64 GetDataSize() const override { return m_size; }
bool IsDataSizeAccurate() const override { return true; }

private:
DriveReader(const std::string& drive);

0 comments on commit d5ed3cb

Please sign in to comment.
You can’t perform that action at this time.