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:
Glenn Maynard
2005-09-29 00:33:22 +00:00
parent 14ab43b2aa
commit 87ddfb4c41
4 changed files with 26 additions and 10 deletions
+19 -4
View File
@@ -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 );
}