Tweak how IVFC validation is done

This commit is contained in:
Alex Barney 2018-10-18 16:10:51 -05:00
parent da5eec1b3d
commit f8e7c00ef4
2 changed files with 48 additions and 28 deletions

View file

@ -39,31 +39,33 @@ namespace LibHac
} }
/// <summary> /// <summary>
/// Checks the hashes of any unchecked blocks and returns the <see cref="Validity"/> of the hash level. /// Checks the hashes of any unchecked blocks and returns the <see cref="Validity"/> of the data.
/// </summary> /// </summary>
/// <param name="level">The level of hierarchical hashes to check.</param>
/// <param name="returnOnError">If <see langword="true"/>, return as soon as an invalid block is found.</param> /// <param name="returnOnError">If <see langword="true"/>, return as soon as an invalid block is found.</param>
/// <param name="logger">An optional <see cref="IProgressReport"/> for reporting progress.</param> /// <param name="logger">An optional <see cref="IProgressReport"/> for reporting progress.</param>
/// <returns>The <see cref="Validity"/> of the data of the specified hash level.</returns> /// <returns>The <see cref="Validity"/> of the data of the specified hash level.</returns>
public Validity ValidateLevel(int level, bool returnOnError, IProgressReport logger = null) public Validity Validate(bool returnOnError, IProgressReport logger = null)
{ {
Validity[] validities = LevelValidities[level]; Validity[] validities = LevelValidities[LevelValidities.Length - 1];
IntegrityVerificationStream levelStream = IntegrityStreams[level]; IntegrityVerificationStream stream = IntegrityStreams[IntegrityStreams.Length - 1];
// The original position of the stream must be restored when we're done validating // Restore the original position of the stream when we're done validating
long initialPosition = levelStream.Position; long initialPosition = stream.Position;
var buffer = new byte[levelStream.SectorSize]; long blockSize = stream.SectorSize;
int blockCount = (int)Util.DivideByRoundUp(Length, blockSize);
var buffer = new byte[blockSize];
var result = Validity.Valid; var result = Validity.Valid;
logger?.SetTotal(levelStream.SectorCount); logger?.SetTotal(blockCount);
for (int i = 0; i < levelStream.SectorCount; i++) for (int i = 0; i < blockCount; i++)
{ {
if (validities[i] == Validity.Unchecked) if (validities[i] == Validity.Unchecked)
{ {
levelStream.Position = (long)levelStream.SectorSize * i; stream.Position = blockSize * i;
levelStream.Read(buffer, 0, buffer.Length, IntegrityCheckLevel.IgnoreOnInvalid); stream.Read(buffer, 0, buffer.Length, IntegrityCheckLevel.IgnoreOnInvalid);
} }
if (validities[i] == Validity.Invalid) if (validities[i] == Validity.Invalid)
@ -76,7 +78,7 @@ namespace LibHac
} }
logger?.SetTotal(0); logger?.SetTotal(0);
levelStream.Position = initialPosition; stream.Position = initialPosition;
return result; return result;
} }

View file

@ -489,25 +489,43 @@ namespace LibHac
if (stream == null) return Validity.Unchecked; if (stream == null) return Validity.Unchecked;
if (!quiet) logger?.LogMessage($"Verifying section {index}..."); if (!quiet) logger?.LogMessage($"Verifying section {index}...");
Validity validity = stream.Validate(true, logger);
for (int i = 0; i < stream.Levels.Length - 1; i++) if (hashType == NcaHashType.Ivfc)
{ {
if (!quiet) logger?.LogMessage($" Verifying Hash Level {i}..."); SetIvfcLevelValidities(stream, sect.Header.IvfcInfo);
Validity levelValidity = stream.ValidateLevel(i, true, logger); }
else if (hashType == NcaHashType.Sha256)
if (hashType == NcaHashType.Ivfc) {
{ sect.Header.Sha256Info.HashValidity = validity;
sect.Header.IvfcInfo.LevelHeaders[i].HashValidity = levelValidity;
}
else if (hashType == NcaHashType.Sha256 && i == stream.Levels.Length - 2)
{
sect.Header.Sha256Info.HashValidity = levelValidity;
}
if (levelValidity == Validity.Invalid) return Validity.Invalid;
} }
return Validity.Valid; return validity;
}
private static void SetIvfcLevelValidities(HierarchicalIntegrityVerificationStream stream, IvfcHeader header)
{
for (int i = 0; i < stream.Levels.Length - 1; i++)
{
Validity[] level = stream.LevelValidities[i];
var levelValidity = Validity.Valid;
foreach (Validity block in level)
{
if (block == Validity.Invalid)
{
levelValidity = Validity.Invalid;
break;
}
if (block == Validity.Unchecked && levelValidity != Validity.Invalid)
{
levelValidity = Validity.Unchecked;
}
}
header.LevelHeaders[i].HashValidity = levelValidity;
}
} }
} }
} }