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:
parent
6a8da15f51
commit
32691cfad7
|
@ -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");
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue