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
+5 -5
View File
@@ -1924,12 +1924,12 @@ XNode* Profile::SaveCoinDataCreateNode() const
return pNode; return pNode;
} }
void Profile::BackupToDir( CString sFromDir, CString sToDir ) void Profile::MoveBackupToDir( CString sFromDir, CString sToDir )
{ {
FileCopy( sFromDir+EDITABLE_INI, sToDir+EDITABLE_INI ); FILEMAN->MoveFile( sFromDir+EDITABLE_INI, sToDir+EDITABLE_INI );
FileCopy( sFromDir+STATS_XML, sToDir+STATS_XML ); FILEMAN->MoveFile( sFromDir+STATS_XML, sToDir+STATS_XML );
FileCopy( sFromDir+STATS_XML+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND ); FILEMAN->MoveFile( sFromDir+STATS_XML+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND );
FileCopy( sFromDir+DONT_SHARE_SIG, sToDir+DONT_SHARE_SIG ); FILEMAN->MoveFile( sFromDir+DONT_SHARE_SIG, sToDir+DONT_SHARE_SIG );
} }
// lua start // lua start
+1 -1
View File
@@ -332,7 +332,7 @@ public:
void SaveStatsWebPageToDir( CString sDir ) const; void SaveStatsWebPageToDir( CString sDir ) const;
void SaveMachinePublicKeyToDir( CString sDir ) const; void SaveMachinePublicKeyToDir( CString sDir ) const;
static void BackupToDir( CString sFromDir, CString sToDir ); static void MoveBackupToDir( CString sFromDir, CString sToDir );
// Lua // Lua
void PushSelf( lua_State *L ); void PushSelf( lua_State *L );
+19 -4
View File
@@ -75,6 +75,7 @@ void ProfileManager::Init()
m_bWasLoadedFromMemoryCard[p] = false; m_bWasLoadedFromMemoryCard[p] = false;
m_bLastLoadWasTamperedOrCorrupt[p] = false; m_bLastLoadWasTamperedOrCorrupt[p] = false;
m_bLastLoadWasFromLastGood[p] = false; m_bLastLoadWasFromLastGood[p] = false;
m_bNeedToBackUpLastLoad[p] = false;
} }
LoadMachineProfile(); LoadMachineProfile();
@@ -119,18 +120,17 @@ ProfileLoadResult ProfileManager::LoadProfile( PlayerNumber pn, CString sProfile
m_sProfileDir[pn] = sProfileDir; m_sProfileDir[pn] = sProfileDir;
m_bWasLoadedFromMemoryCard[pn] = bIsMemCard; m_bWasLoadedFromMemoryCard[pn] = bIsMemCard;
m_bLastLoadWasFromLastGood[pn] = false; m_bLastLoadWasFromLastGood[pn] = false;
m_bNeedToBackUpLastLoad[pn] = false;
// Try to load the original, non-backup data. // Try to load the original, non-backup data.
ProfileLoadResult lr = GetProfile(pn)->LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData ); ProfileLoadResult lr = GetProfile(pn)->LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
CString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_SUBDIR; 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 ) 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; m_bLastLoadWasTamperedOrCorrupt[pn] = lr == ProfileLoadResult_FailedTampered;
@@ -297,6 +297,20 @@ bool ProfileManager::SaveProfile( PlayerNumber pn ) const
if( m_sProfileDir[pn].empty() ) if( m_sProfileDir[pn].empty() )
return false; 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 ); bool b = GetProfile(pn)->SaveAllToDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
return b; return b;
@@ -318,6 +332,7 @@ void ProfileManager::UnloadProfile( PlayerNumber pn )
m_bWasLoadedFromMemoryCard[pn] = false; m_bWasLoadedFromMemoryCard[pn] = false;
m_bLastLoadWasTamperedOrCorrupt[pn] = false; m_bLastLoadWasTamperedOrCorrupt[pn] = false;
m_bLastLoadWasFromLastGood[pn] = false; m_bLastLoadWasFromLastGood[pn] = false;
m_bNeedToBackUpLastLoad[pn] = false;
m_pMemoryCardProfile[pn]->InitAll(); m_pMemoryCardProfile[pn]->InitAll();
SONGMAN->FreeAllLoadedFromProfile( (ProfileSlot) pn ); SONGMAN->FreeAllLoadedFromProfile( (ProfileSlot) pn );
} }
+1
View File
@@ -125,6 +125,7 @@ private:
bool m_bWasLoadedFromMemoryCard[NUM_PLAYERS]; bool m_bWasLoadedFromMemoryCard[NUM_PLAYERS];
bool m_bLastLoadWasTamperedOrCorrupt[NUM_PLAYERS]; // true if Stats.xml was present, but failed to load (probably because of a signature failure) bool m_bLastLoadWasTamperedOrCorrupt[NUM_PLAYERS]; // true if Stats.xml was present, but failed to load (probably because of a signature failure)
bool m_bLastLoadWasFromLastGood[NUM_PLAYERS]; // if true, then m_bLastLoadWasTamperedOrCorrupt is also true bool m_bLastLoadWasFromLastGood[NUM_PLAYERS]; // if true, then m_bLastLoadWasTamperedOrCorrupt is also true
mutable bool m_bNeedToBackUpLastLoad[NUM_PLAYERS]; // if true, back up profile on next save
Profile *m_pMemoryCardProfile[NUM_PLAYERS]; // holds Profile for the currently inserted card Profile *m_pMemoryCardProfile[NUM_PLAYERS]; // holds Profile for the currently inserted card
Profile *m_pMachineProfile; Profile *m_pMachineProfile;