DiscScrubber: fail gracefully on corrupt images

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3272 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman 2009-05-22 07:14:34 +00:00
parent 6a8da15f51
commit 32691cfad7
2 changed files with 74 additions and 52 deletions

View File

@ -169,7 +169,10 @@ bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
if (sub_type == 1) if (sub_type == 1)
{ {
if (!DiscScrubber::Scrub(infile, callback, arg)) if (!DiscScrubber::Scrub(infile, callback, arg))
{
PanicAlert("%s failed to be scrubbed. Probably the image is corrupt.", infile);
return false; return false;
}
} }
FILE* inf = fopen(infile, "rb"); FILE* inf = fopen(infile, "rb");

View File

@ -82,8 +82,8 @@ void ReadFromDisc(u64 _Offset, u64 _Length, u32& _Buffer);
void ReadFromDisc(u64 _Offset, u64 _Length, u64& _Buffer); void ReadFromDisc(u64 _Offset, u64 _Length, u64& _Buffer);
void ReadFromVolume(u64 _Offset, u64 _Length, u32& _Buffer); void ReadFromVolume(u64 _Offset, u64 _Length, u32& _Buffer);
void ReadFromVolume(u64 _Offset, u64 _Length, u64& _Buffer); void ReadFromVolume(u64 _Offset, u64 _Length, u64& _Buffer);
void ParseDisc(); bool ParseDisc();
void ParsePartitionData(SPartition& _rPartition); bool ParsePartitionData(SPartition& _rPartition);
u32 GetDOLSize(u64 _DOLOffset); u32 GetDOLSize(u64 _DOLOffset);
@ -138,7 +138,8 @@ bool Scrub(const char* filename, CompressCB callback, void* arg)
// Fill out table of free blocks // Fill out table of free blocks
callback("DiscScrubber: Parsing...", 0, arg); callback("DiscScrubber: Parsing...", 0, arg);
ParseDisc(); if (!ParseDisc())
success = false;
// Done with it; need it closed for the next part // Done with it; need it closed for the next part
delete m_Disc; delete m_Disc;
m_Disc = NULL; m_Disc = NULL;
@ -149,9 +150,12 @@ bool Scrub(const char* filename, CompressCB callback, void* arg)
{ {
ERROR_LOG(DISCIO, "DiscScrubber failed to open %s", filename); ERROR_LOG(DISCIO, "DiscScrubber failed to open %s", filename);
success = false; success = false;
return success;
} }
// Let's not touch the file if we've failed up to here :p
if (!success)
goto cleanup;
// Modify file, obeying the table of free blocks // Modify file, obeying the table of free blocks
NOTICE_LOG(DISCIO, "Removing garbage data...go get some coffee :)"); NOTICE_LOG(DISCIO, "Removing garbage data...go get some coffee :)");
for (u64 i = 0; i < numClusters; i++) for (u64 i = 0; i < numClusters; i++)
@ -186,15 +190,15 @@ bool Scrub(const char* filename, CompressCB callback, void* arg)
} }
NOTICE_LOG(DISCIO, "Done removing garbage data"); NOTICE_LOG(DISCIO, "Done removing garbage data");
fclose(pFile);
delete m_Sector1;
delete m_FreeTable;
if (success) if (success)
if (!MarkAsScrubbed(filename)) if (!MarkAsScrubbed(filename))
ERROR_LOG(DISCIO, "Really weird - failed to mark scrubbed disk as scrubbed :s"); ERROR_LOG(DISCIO, "Really weird - failed to mark scrubbed disk as scrubbed :s");
cleanup:
fclose(pFile);
delete m_Sector1;
delete m_FreeTable;
return success; return success;
} }
@ -270,7 +274,7 @@ void ReadFromVolume(u64 _Offset, u64 _Length, u64& _Buffer)
_Buffer <<= 2; _Buffer <<= 2;
} }
void ParseDisc() bool ParseDisc()
{ {
// Mark the header as used - it's mostly 0s anyways // Mark the header as used - it's mostly 0s anyways
MarkAsUsed(0, 0x50000); MarkAsUsed(0, 0x50000);
@ -317,14 +321,19 @@ void ParseDisc()
//MarkAsUsed(rPartition.Offset + rHeader.DataOffset, rHeader.DataSize); //MarkAsUsed(rPartition.Offset + rHeader.DataOffset, rHeader.DataSize);
// Parse Data! This is where the big gain is // Parse Data! This is where the big gain is
ParsePartitionData(rPartition); if (!ParsePartitionData(rPartition))
return false;
} }
} }
return true;
} }
// Operations dealing with encrypted space are done here - the volume is swapped to allow this // Operations dealing with encrypted space are done here - the volume is swapped to allow this
void ParsePartitionData(SPartition& _rPartition) bool ParsePartitionData(SPartition& _rPartition)
{ {
bool ParsedOK = true;
// Switch out the main volume temporarily // Switch out the main volume temporarily
IVolume *OldVolume = m_Disc; IVolume *OldVolume = m_Disc;
@ -332,49 +341,57 @@ void ParsePartitionData(SPartition& _rPartition)
m_Disc = CreateVolumeFromFilename(m_Filename.c_str(), _rPartition.GroupNumber, _rPartition.Number); m_Disc = CreateVolumeFromFilename(m_Filename.c_str(), _rPartition.GroupNumber, _rPartition.Number);
IFileSystem *FileSystem = CreateFileSystem(m_Disc); IFileSystem *FileSystem = CreateFileSystem(m_Disc);
std::vector<const SFileInfo *> Files; if (!FileSystem)
size_t numFiles = FileSystem->GetFileList(Files);
// Mark things as used which are not in the filesystem
// Header, Header Information, Apploader
ReadFromVolume(0x2440 + 0x14, 4, _rPartition.Header.ApploaderSize);
ReadFromVolume(0x2440 + 0x18, 4, _rPartition.Header.ApploaderTrailerSize);
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset
, 0
, 0x2440
+ _rPartition.Header.ApploaderSize
+ _rPartition.Header.ApploaderTrailerSize);
// DOL
ReadFromVolume(0x420, 4, _rPartition.Header.DOLOffset);
_rPartition.Header.DOLSize = GetDOLSize(_rPartition.Header.DOLOffset);
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset
, _rPartition.Header.DOLOffset
, _rPartition.Header.DOLSize);
// FST
ReadFromVolume(0x424, 4, _rPartition.Header.FSTOffset);
ReadFromVolume(0x428, 4, _rPartition.Header.FSTSize);
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset
, _rPartition.Header.FSTOffset
, _rPartition.Header.FSTSize);
// Go through the filesystem and mark entries as used
for (size_t currentFile = 0; currentFile < numFiles; currentFile++)
{ {
DEBUG_LOG(DISCIO, "%s", (*Files.at(currentFile)).m_FullPath); ERROR_LOG(DISCIO, "Failed to create filesystem for group %d partition %u", _rPartition.GroupNumber, _rPartition.Number)
// Just 1byte for directory? - it will end up reserving a cluster this way ParsedOK = false;
if ((*Files.at(currentFile)).m_NameOffset & 0x1000000) }
MarkAsUsedE(_rPartition.Offset else
{
std::vector<const SFileInfo *> Files;
size_t numFiles = FileSystem->GetFileList(Files);
// Mark things as used which are not in the filesystem
// Header, Header Information, Apploader
ReadFromVolume(0x2440 + 0x14, 4, _rPartition.Header.ApploaderSize);
ReadFromVolume(0x2440 + 0x18, 4, _rPartition.Header.ApploaderTrailerSize);
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset + _rPartition.Header.DataOffset
, (*Files.at(currentFile)).m_Offset, 1); , 0
else , 0x2440
MarkAsUsedE(_rPartition.Offset + _rPartition.Header.ApploaderSize
+ _rPartition.Header.ApploaderTrailerSize);
// DOL
ReadFromVolume(0x420, 4, _rPartition.Header.DOLOffset);
_rPartition.Header.DOLSize = GetDOLSize(_rPartition.Header.DOLOffset);
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset + _rPartition.Header.DataOffset
, (*Files.at(currentFile)).m_Offset, (*Files.at(currentFile)).m_FileSize); , _rPartition.Header.DOLOffset
, _rPartition.Header.DOLSize);
// FST
ReadFromVolume(0x424, 4, _rPartition.Header.FSTOffset);
ReadFromVolume(0x428, 4, _rPartition.Header.FSTSize);
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset
, _rPartition.Header.FSTOffset
, _rPartition.Header.FSTSize);
// Go through the filesystem and mark entries as used
for (size_t currentFile = 0; currentFile < numFiles; currentFile++)
{
DEBUG_LOG(DISCIO, "%s", (*Files.at(currentFile)).m_FullPath);
// Just 1byte for directory? - it will end up reserving a cluster this way
if ((*Files.at(currentFile)).m_NameOffset & 0x1000000)
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset
, (*Files.at(currentFile)).m_Offset, 1);
else
MarkAsUsedE(_rPartition.Offset
+ _rPartition.Header.DataOffset
, (*Files.at(currentFile)).m_Offset, (*Files.at(currentFile)).m_FileSize);
}
} }
delete FileSystem; delete FileSystem;
@ -382,6 +399,8 @@ void ParsePartitionData(SPartition& _rPartition)
// Swap back // Swap back
delete m_Disc; delete m_Disc;
m_Disc = OldVolume; m_Disc = OldVolume;
return ParsedOK;
} }
u32 GetDOLSize(u64 _DOLOffset) u32 GetDOLSize(u64 _DOLOffset)