MemoryCard: When converting a file to a folder, simulate the conversion process once before writing the data. This prevents half-converted/corrupted cards by ensuring we crash before any actual writes occur.

This commit is contained in:
Admiral H. Curtiss 2015-07-20 23:53:53 +02:00
parent 39e1de4d13
commit d331d59a9f
3 changed files with 71 additions and 51 deletions

View File

@ -201,9 +201,17 @@ bool Dialogs::ConvertMemoryCardDialog::ConvertToFolder( const wxFileName& source
AppConfig::McdOptions config; AppConfig::McdOptions config;
config.Enabled = true; config.Enabled = true;
config.Type = MemoryCardType::MemoryCard_Folder; config.Type = MemoryCardType::MemoryCard_Folder;
targetFolderMemoryCard.Open( targetPath.GetFullPath(), config, 0, false, L"" );
u32 adr = 0; u32 adr = 0;
for ( int i = 0; i < 2; ++i ) {
// Before writing the data, we first simulate the entire process without actual writes to the file system.
// This ensures that if we crash/fail due to a corrupted memory card file system or similar, we do so during
// the simulation run, and don't actually write out any partial data to the host file system.
bool simulateWrites = i == 0;
targetFolderMemoryCard.Open( targetPath.GetFullPath(), config, 0, false, L"", simulateWrites );
adr = 0;
sourceFile.Seek( 0 );
while ( !sourceFile.Eof() ) { while ( !sourceFile.Eof() ) {
int size = sourceFile.Read( buffer, FolderMemoryCard::PageSizeRaw ); int size = sourceFile.Read( buffer, FolderMemoryCard::PageSizeRaw );
if ( size > 0 ) { if ( size > 0 ) {
@ -212,8 +220,10 @@ bool Dialogs::ConvertMemoryCardDialog::ConvertToFolder( const wxFileName& source
} }
} }
sourceFile.Close();
targetFolderMemoryCard.Close(); targetFolderMemoryCard.Close();
}
sourceFile.Close();
if ( adr != FolderMemoryCard::TotalSizeRaw ) { if ( adr != FolderMemoryCard::TotalSizeRaw ) {
// reset memory card metrics in superblock to the default 8MB, since the converted card was different // reset memory card metrics in superblock to the default 8MB, since the converted card was different

View File

@ -44,6 +44,7 @@ void FolderMemoryCard::InitializeInternalData() {
m_isEnabled = false; m_isEnabled = false;
m_framesUntilFlush = 0; m_framesUntilFlush = 0;
m_lastAccessedFile.Close(); m_lastAccessedFile.Close();
m_performFileWrites = true;
} }
bool FolderMemoryCard::IsFormatted() const { bool FolderMemoryCard::IsFormatted() const {
@ -52,11 +53,12 @@ bool FolderMemoryCard::IsFormatted() const {
} }
void FolderMemoryCard::Open( const bool enableFiltering, const wxString& filter ) { void FolderMemoryCard::Open( const bool enableFiltering, const wxString& filter ) {
Open( g_Conf->FullpathToMcd( m_slot ), g_Conf->Mcd[m_slot], 0, enableFiltering, filter ); Open( g_Conf->FullpathToMcd( m_slot ), g_Conf->Mcd[m_slot], 0, enableFiltering, filter, false );
} }
void FolderMemoryCard::Open( const wxString& fullPath, const AppConfig::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, const wxString& filter ) { void FolderMemoryCard::Open( const wxString& fullPath, const AppConfig::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, const wxString& filter, bool simulateFileWrites ) {
InitializeInternalData(); InitializeInternalData();
m_performFileWrites = !simulateFileWrites;
wxFileName configuredFileName( fullPath ); wxFileName configuredFileName( fullPath );
m_folderName = wxFileName( configuredFileName.GetFullPath() + L"/" ); m_folderName = wxFileName( configuredFileName.GetFullPath() + L"/" );
@ -74,7 +76,7 @@ void FolderMemoryCard::Open( const wxString& fullPath, const AppConfig::McdOptio
} }
// if nothing exists at a valid location, create a directory for the memory card // if nothing exists at a valid location, create a directory for the memory card
if ( !disabled && !m_folderName.DirExists() ) { if ( !disabled && m_performFileWrites && !m_folderName.DirExists() ) {
if ( !m_folderName.Mkdir() ) { if ( !m_folderName.Mkdir() ) {
str = L"[couldn't create folder]"; str = L"[couldn't create folder]";
disabled = true; disabled = true;
@ -910,7 +912,7 @@ bool FolderMemoryCard::FlushBlock( const u32 block ) {
} }
void FolderMemoryCard::FlushSuperBlock() { void FolderMemoryCard::FlushSuperBlock() {
if ( FlushBlock( 0 ) ) { if ( FlushBlock( 0 ) && m_performFileWrites ) {
wxFileName superBlockFileName( m_folderName.GetPath(), L"_pcsx2_superblock" ); wxFileName superBlockFileName( m_folderName.GetPath(), L"_pcsx2_superblock" );
wxFFile superBlockFile( superBlockFileName.GetFullPath().c_str(), L"wb" ); wxFFile superBlockFile( superBlockFileName.GetFullPath().c_str(), L"wb" );
if ( superBlockFile.IsOpened() ) { if ( superBlockFile.IsOpened() ) {
@ -946,6 +948,7 @@ void FolderMemoryCard::FlushFileEntries( const u32 dirCluster, const u32 remaini
const wxString subDirName = wxString::FromAscii( (const char*)cleanName ); const wxString subDirName = wxString::FromAscii( (const char*)cleanName );
const wxString subDirPath = dirPath + L"/" + subDirName; const wxString subDirPath = dirPath + L"/" + subDirName;
if ( m_performFileWrites ) {
// if this directory has nonstandard metadata, write that to the file system // if this directory has nonstandard metadata, write that to the file system
wxFileName metaFileName( m_folderName.GetFullPath() + subDirPath + L"/_pcsx2_meta_directory" ); wxFileName metaFileName( m_folderName.GetFullPath() + subDirPath + L"/_pcsx2_meta_directory" );
if ( filenameCleaned || entry->entry.data.mode != MemoryCardFileEntry::DefaultDirMode || entry->entry.data.attr != 0 ) { if ( filenameCleaned || entry->entry.data.mode != MemoryCardFileEntry::DefaultDirMode || entry->entry.data.attr != 0 ) {
@ -963,6 +966,7 @@ void FolderMemoryCard::FlushFileEntries( const u32 dirCluster, const u32 remaini
wxRemoveFile( metaFileName.GetFullPath() ); wxRemoveFile( metaFileName.GetFullPath() );
} }
} }
}
MemoryCardFileMetadataReference* dirRef = AddDirEntryToMetadataQuickAccess( entry, parent ); MemoryCardFileMetadataReference* dirRef = AddDirEntryToMetadataQuickAccess( entry, parent );
@ -1105,6 +1109,8 @@ bool FolderMemoryCard::WriteToFile( const u8* src, u32 adr, u32 dataLength ) {
if ( it != m_fileMetadataQuickAccess.end() ) { if ( it != m_fileMetadataQuickAccess.end() ) {
const MemoryCardFileEntry* const entry = it->second.entry; const MemoryCardFileEntry* const entry = it->second.entry;
const u32 clusterNumber = it->second.consecutiveCluster; const u32 clusterNumber = it->second.consecutiveCluster;
if ( m_performFileWrites ) {
wxFFile* file = m_lastAccessedFile.ReOpen( m_folderName, &it->second, L"r+b", true ); wxFFile* file = m_lastAccessedFile.ReOpen( m_folderName, &it->second, L"r+b", true );
if ( file->IsOpened() ) { if ( file->IsOpened() ) {
const u32 clusterOffset = ( page % 2 ) * PageSize + offset; const u32 clusterOffset = ( page % 2 ) * PageSize + offset;
@ -1133,6 +1139,7 @@ bool FolderMemoryCard::WriteToFile( const u8* src, u32 adr, u32 dataLength ) {
} else { } else {
return false; return false;
} }
}
return true; return true;
} }

View File

@ -283,6 +283,9 @@ protected:
bool m_isEnabled; bool m_isEnabled;
// if set to false, nothing is actually written to the file system while flushing, and data is discarded instead
bool m_performFileWrites;
public: public:
FolderMemoryCard(); FolderMemoryCard();
virtual ~FolderMemoryCard() throw() {} virtual ~FolderMemoryCard() throw() {}
@ -293,7 +296,7 @@ public:
// Initialize & Load Memory Card with values configured in the Memory Card Manager // Initialize & Load Memory Card with values configured in the Memory Card Manager
void Open( const bool enableFiltering, const wxString& filter ); void Open( const bool enableFiltering, const wxString& filter );
// Initialize & Load Memory Card with provided custom values // Initialize & Load Memory Card with provided custom values
void Open( const wxString& fullPath, const AppConfig::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, const wxString& filter ); void Open( const wxString& fullPath, const AppConfig::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, const wxString& filter, bool simulateFileWrites = false );
// Close the memory card and flush changes to the file system. Set flush to false to not store changes. // Close the memory card and flush changes to the file system. Set flush to false to not store changes.
void Close( bool flush = true ); void Close( bool flush = true );