Up until now, we've been backing up profile data by copying it to the
backup directory immediately after a successful load. This ensures that the data we're copying is valid, so after a successful copy, the backup is valid, too. This has a couple problems: - Copying takes a while. It's much faster to move data. - Data shouldn't be written during a profile read. Players should be able to assume that it's safe to remove the memory card at any time except when the game is explicitly saving. - Copying good data from one place to another is just as prone to error as initially writing it. It's at least as easy for the backup copy to fail and result in a bad backup as it is for a save to fail in the first place. Instead, when we successfully load profile data (and not from a backup), set a flag. Later, when we save over that data, we'll clear the flag and move the data we're about to overwrite to the backup.
This commit is contained in:
@@ -75,6 +75,7 @@ void ProfileManager::Init()
|
||||
m_bWasLoadedFromMemoryCard[p] = false;
|
||||
m_bLastLoadWasTamperedOrCorrupt[p] = false;
|
||||
m_bLastLoadWasFromLastGood[p] = false;
|
||||
m_bNeedToBackUpLastLoad[p] = false;
|
||||
}
|
||||
|
||||
LoadMachineProfile();
|
||||
@@ -119,18 +120,17 @@ ProfileLoadResult ProfileManager::LoadProfile( PlayerNumber pn, CString sProfile
|
||||
m_sProfileDir[pn] = sProfileDir;
|
||||
m_bWasLoadedFromMemoryCard[pn] = bIsMemCard;
|
||||
m_bLastLoadWasFromLastGood[pn] = false;
|
||||
m_bNeedToBackUpLastLoad[pn] = false;
|
||||
|
||||
// Try to load the original, non-backup data.
|
||||
ProfileLoadResult lr = GetProfile(pn)->LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
|
||||
|
||||
CString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_SUBDIR;
|
||||
|
||||
// Save a backup of the non-backup profile now that we've loaded it and know
|
||||
// it's good. This should be reasonably fast because we're only saving Stats.xml
|
||||
// and signatures - not all of the files in the Profile.
|
||||
if( lr == ProfileLoadResult_Success )
|
||||
{
|
||||
Profile::BackupToDir( m_sProfileDir[pn], sBackupDir );
|
||||
/* Next time the profile is written, move this good profile into LastGood. */
|
||||
m_bNeedToBackUpLastLoad[pn] = true;
|
||||
}
|
||||
|
||||
m_bLastLoadWasTamperedOrCorrupt[pn] = lr == ProfileLoadResult_FailedTampered;
|
||||
@@ -297,6 +297,20 @@ bool ProfileManager::SaveProfile( PlayerNumber pn ) const
|
||||
if( m_sProfileDir[pn].empty() )
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the profile we're writing was loaded from the primary (non-backup)
|
||||
* data, then we've validated it and know it's good. Before writing our
|
||||
* new data, move the old, good data to the backup. (Only do this once;
|
||||
* if we save the profile more than once, we havn't re-validated the
|
||||
* newly written data.)
|
||||
*/
|
||||
if( m_bNeedToBackUpLastLoad[pn] )
|
||||
{
|
||||
m_bNeedToBackUpLastLoad[pn] = false;
|
||||
CString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_DIR;
|
||||
Profile::MoveBackupToDir( m_sProfileDir[pn], sBackupDir );
|
||||
}
|
||||
|
||||
bool b = GetProfile(pn)->SaveAllToDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
|
||||
|
||||
return b;
|
||||
@@ -318,6 +332,7 @@ void ProfileManager::UnloadProfile( PlayerNumber pn )
|
||||
m_bWasLoadedFromMemoryCard[pn] = false;
|
||||
m_bLastLoadWasTamperedOrCorrupt[pn] = false;
|
||||
m_bLastLoadWasFromLastGood[pn] = false;
|
||||
m_bNeedToBackUpLastLoad[pn] = false;
|
||||
m_pMemoryCardProfile[pn]->InitAll();
|
||||
SONGMAN->FreeAllLoadedFromProfile( (ProfileSlot) pn );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user