Load from LastGood if the main profile is tampered/corrupt.

Don't write new data on a load fail - it doesn't give the user a change to correct the load failure.
This commit is contained in:
Chris Danford
2004-10-07 19:57:51 +00:00
parent c47b7fb124
commit 5c5ac50b82
5 changed files with 81 additions and 82 deletions
+19 -12
View File
@@ -563,11 +563,8 @@ void Profile::IncrementCategoryPlayCount( StepsType st, RankingCategory rc )
XNode* X = xml.GetChild(#X); \ XNode* X = xml.GetChild(#X); \
if( X==NULL ) LOG->Warn("Failed to read section " #X); \ if( X==NULL ) LOG->Warn("Failed to read section " #X); \
else Load##X##FromNode(X); } else Load##X##FromNode(X); }
int g_iOnceCtr;
#define FOR_ONCE for(g_iOnceCtr=0;g_iOnceCtr<1;g_iOnceCtr++)
Profile::LoadResult Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
{ {
CHECKPOINT; CHECKPOINT;
@@ -581,7 +578,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
// Check for the existance of stats.xml // Check for the existance of stats.xml
CString fn = sDir + STATS_XML; CString fn = sDir + STATS_XML;
if( !IsAFile(fn) ) if( !IsAFile(fn) )
return true; // This is a common case and not a load error, so return success. return failed_no_profile;
// //
// Don't unreasonably large stats.xml files. // Don't unreasonably large stats.xml files.
@@ -592,7 +589,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
if( iBytes > MAX_PLAYER_STATS_XML_SIZE_BYTES ) if( iBytes > MAX_PLAYER_STATS_XML_SIZE_BYTES )
{ {
LOG->Warn( "The file '%s' is unreasonably large. It won't be loaded.", fn.c_str() ); LOG->Warn( "The file '%s' is unreasonably large. It won't be loaded.", fn.c_str() );
return false; // error return failed_tampered;
} }
} }
@@ -606,7 +603,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
if( !CryptManager::VerifyFileWithFile(sStatsXmlSigFile, sDontShareFile) ) if( !CryptManager::VerifyFileWithFile(sStatsXmlSigFile, sDontShareFile) )
{ {
LOG->Warn( "The don't share check for '%s' failed. Data will be ignored.", sStatsXmlSigFile.c_str() ); LOG->Warn( "The don't share check for '%s' failed. Data will be ignored.", sStatsXmlSigFile.c_str() );
return false; // error return failed_tampered;
} }
LOG->Trace( "Done." ); LOG->Trace( "Done." );
@@ -615,7 +612,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
if( !CryptManager::VerifyFileWithFile(fn, sStatsXmlSigFile) ) if( !CryptManager::VerifyFileWithFile(fn, sStatsXmlSigFile) )
{ {
LOG->Warn( "The signature check for '%s' failed. Data will be ignored.", fn.c_str() ); LOG->Warn( "The signature check for '%s' failed. Data will be ignored.", fn.c_str() );
return false; // error return failed_tampered;
} }
LOG->Trace( "Done." ); LOG->Trace( "Done." );
} }
@@ -625,19 +622,19 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
if( !xml.LoadFromFile( fn ) ) if( !xml.LoadFromFile( fn ) )
{ {
LOG->Warn( "Couldn't open file '%s' for reading.", fn.c_str() ); LOG->Warn( "Couldn't open file '%s' for reading.", fn.c_str() );
return false; // error return failed_tampered;
} }
LOG->Trace( "Done." ); LOG->Trace( "Done." );
/* The placeholder stats.xml file has an <html> tag. Don't load it, but don't /* The placeholder stats.xml file has an <html> tag. Don't load it, but don't
* warn about it. */ * warn about it. */
if( xml.name == "html" ) if( xml.name == "html" )
return true; // success return failed_no_profile;
if( xml.name != "Stats" ) if( xml.name != "Stats" )
{ {
WARN_M( xml.name ); WARN_M( xml.name );
return false; // error return failed_tampered;
} }
LOAD_NODE( GeneralData ); LOAD_NODE( GeneralData );
@@ -649,7 +646,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
LOAD_NODE( RecentSongScores ); LOAD_NODE( RecentSongScores );
LOAD_NODE( RecentCourseScores ); LOAD_NODE( RecentCourseScores );
return true; // success return success;
} }
bool Profile::SaveAllToDir( CString sDir, bool bSignData ) const bool Profile::SaveAllToDir( CString sDir, bool bSignData ) const
@@ -1578,11 +1575,21 @@ XNode* Profile::SaveCoinDataCreateNode() const
void Profile::BackupToDir( CString sFromDir, CString sToDir ) void Profile::BackupToDir( CString sFromDir, CString sToDir )
{ {
FileCopy( sFromDir+EDITABLE_INI, sToDir+EDITABLE_INI );
FileCopy( sFromDir+STATS_XML, sToDir+STATS_XML ); FileCopy( sFromDir+STATS_XML, sToDir+STATS_XML );
FileCopy( sFromDir+STATS_XML+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND ); FileCopy( sFromDir+STATS_XML+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND );
FileCopy( sFromDir+DONT_SHARE_SIG, sToDir+DONT_SHARE_SIG ); FileCopy( sFromDir+DONT_SHARE_SIG, sToDir+DONT_SHARE_SIG );
} }
bool Profile::CreateNewProfile( CString sProfileDir, CString sName )
{
Profile pro;
pro.m_sDisplayName = sName;
bool bResult = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
FlushDirCache();
return bResult;
}
/* /*
* (c) 2001-2004 Chris Danford * (c) 2001-2004 Chris Danford
* All rights reserved. * All rights reserved.
+3 -1
View File
@@ -260,7 +260,8 @@ public:
// //
// Loading and saving // Loading and saving
// //
bool LoadAllFromDir( CString sDir, bool bRequireSignature ); // return false on a tamper or corruption error enum LoadResult { success, failed_no_profile, failed_tampered };
LoadResult LoadAllFromDir( CString sDir, bool bRequireSignature );
bool SaveAllToDir( CString sDir, bool bSignData ) const; bool SaveAllToDir( CString sDir, bool bSignData ) const;
void LoadEditableDataFromDir( CString sDir ); void LoadEditableDataFromDir( CString sDir );
@@ -289,6 +290,7 @@ public:
void SaveStatsWebPageToDir( CString sDir ) const; void SaveStatsWebPageToDir( CString sDir ) const;
void SaveMachinePublicKeyToDir( CString sDir ) const; void SaveMachinePublicKeyToDir( CString sDir ) const;
static bool CreateNewProfile( CString sProfileDir, CString sName );
static void BackupToDir( CString sFromDir, CString sToDir ); static void BackupToDir( CString sFromDir, CString sToDir );
private: private:
+44 -63
View File
@@ -28,7 +28,7 @@ ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our
#define NEW_MEM_CARD_NAME "" #define NEW_MEM_CARD_NAME ""
#define USER_PROFILES_DIR "Data/LocalProfiles/" #define USER_PROFILES_DIR "Data/LocalProfiles/"
#define MACHINE_PROFILE_DIR "Data/MachineProfile/" #define MACHINE_PROFILE_DIR "Data/MachineProfile/"
const CString LAST_GOOD_DIR = "LastGood/";
ProfileManager::ProfileManager() ProfileManager::ProfileManager()
{ {
@@ -44,6 +44,7 @@ void ProfileManager::Init()
{ {
m_bWasLoadedFromMemoryCard[p] = false; m_bWasLoadedFromMemoryCard[p] = false;
m_bLastLoadWasTamperedOrCorrupt[p] = false; m_bLastLoadWasTamperedOrCorrupt[p] = false;
m_bLastLoadWasFromLastGood[p] = false;
} }
LoadMachineProfile(); LoadMachineProfile();
@@ -77,44 +78,37 @@ bool ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIs
ASSERT( !sProfileDir.empty() ); ASSERT( !sProfileDir.empty() );
ASSERT( sProfileDir.Right(1) == "/" ); ASSERT( sProfileDir.Right(1) == "/" );
if( bIsMemCard )
MEMCARDMAN->PauseMountingThread();
m_sProfileDir[pn] = sProfileDir; m_sProfileDir[pn] = sProfileDir;
m_bWasLoadedFromMemoryCard[pn] = bIsMemCard; m_bWasLoadedFromMemoryCard[pn] = bIsMemCard;
bool bSuccess = m_Profile[pn].LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData ); m_bLastLoadWasFromLastGood[pn] = false;
m_bLastLoadWasTamperedOrCorrupt[pn] = !bSuccess; // Try to load the original, non-backup data.
Profile::LoadResult lr = m_Profile[pn].LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
// Save a backup of the profile now that we've loaded it and know it's good. CString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_DIR;
// This should be reasonably fast because we're only saving Stats.xml and
// signatures - not all of the files in the Profile. // Save a backup of the non-backup profile now that we've loaded it and know
if( bSuccess ) // 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 == Profile::success )
{ {
CString sBackupDir = m_sProfileDir[pn] + "LastGood/";
Profile::BackupToDir( m_sProfileDir[pn], sBackupDir ); Profile::BackupToDir( m_sProfileDir[pn], sBackupDir );
} }
if( bIsMemCard ) m_bLastLoadWasTamperedOrCorrupt[pn] = lr == Profile::failed_tampered;
MEMCARDMAN->UnPauseMountingThread();
LOG->Trace( "Done loading profile." ); // Try to load from the backup if the original data fails to load
//
if( lr == Profile::failed_tampered )
{
lr = m_Profile[pn].LoadAllFromDir( sBackupDir, PREFSMAN->m_bSignProfileData );
m_bLastLoadWasFromLastGood[pn] = lr == Profile::success;
}
return true; LOG->Trace( "Done loading profile - result %d", lr );
}
bool ProfileManager::CreateProfile( CString sProfileDir, CString sName ) return lr == Profile::success;
{
bool bResult;
Profile pro;
pro.m_sDisplayName = sName;
bResult = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
if( !bResult )
return false;
FlushDirCache();
return true;
} }
bool ProfileManager::LoadLocalProfileFromMachine( PlayerNumber pn ) bool ProfileManager::LoadLocalProfileFromMachine( PlayerNumber pn )
@@ -138,43 +132,25 @@ bool ProfileManager::LoadProfileFromMemoryCard( PlayerNumber pn )
// mount slot // mount slot
if( MEMCARDMAN->GetCardState(pn) == MEMORY_CARD_STATE_READY ) if( MEMCARDMAN->GetCardState(pn) == MEMORY_CARD_STATE_READY )
{ {
CString sDir = MEM_CARD_MOUNT_POINT[pn]; CString sDir = MEM_CARD_MOUNT_POINT[pn];
// tack on a subdirectory so that we don't write everything to the root // tack on a subdirectory so that we don't write everything to the root
sDir += PREFSMAN->m_sMemoryCardProfileSubdir; sDir += PREFSMAN->m_sMemoryCardProfileSubdir;
sDir += '/'; sDir += '/';
bool bResult; MEMCARDMAN->PauseMountingThread();
bResult = LoadProfile( pn, sDir, true ); bool bSuccess;
if( bResult ) bSuccess = LoadProfile( pn, sDir, true );
return true;
CreateMemoryCardProfile( pn ); MEMCARDMAN->UnPauseMountingThread();
bResult = LoadProfile( pn, sDir, true ); return true; // If a card is inserted, we want to use the memory card to save - even if the Profile load failed.
return bResult;
} }
return false; return false;
} }
bool ProfileManager::CreateMemoryCardProfile( PlayerNumber pn )
{
// CString sDir = MEM_CARD_DIR[pn];
ASSERT( MEMCARDMAN->GetCardState(pn) == MEMORY_CARD_STATE_READY );
CString sDir = MEM_CARD_MOUNT_POINT[pn];
DEBUG_ASSERT( FILEMAN->IsMounted(sDir) ); // should be called only if we've already mounted
// tack on a subdirectory so that we don't write everything to the root
sDir += PREFSMAN->m_sMemoryCardProfileSubdir;
sDir += '/';
return CreateProfile( sDir, NEW_MEM_CARD_NAME );
}
bool ProfileManager::LoadFirstAvailableProfile( PlayerNumber pn ) bool ProfileManager::LoadFirstAvailableProfile( PlayerNumber pn )
{ {
if( LoadProfileFromMemoryCard(pn) ) if( LoadProfileFromMemoryCard(pn) )
@@ -192,7 +168,7 @@ void ProfileManager::SaveAllProfiles() const
FOREACH_HumanPlayer( pn ) FOREACH_HumanPlayer( pn )
{ {
if( !this->IsUsingProfile(pn) ) if( !IsUsingProfile(pn) )
continue; continue;
this->SaveProfile( pn ); this->SaveProfile( pn );
@@ -220,6 +196,7 @@ void ProfileManager::UnloadProfile( PlayerNumber pn )
m_sProfileDir[pn] = ""; m_sProfileDir[pn] = "";
m_bWasLoadedFromMemoryCard[pn] = false; m_bWasLoadedFromMemoryCard[pn] = false;
m_bLastLoadWasTamperedOrCorrupt[pn] = false; m_bLastLoadWasTamperedOrCorrupt[pn] = false;
m_bLastLoadWasFromLastGood[pn] = false;
m_Profile[pn].InitAll(); m_Profile[pn].InitAll();
} }
@@ -261,7 +238,7 @@ bool ProfileManager::CreateLocalProfile( CString sName )
return false; return false;
sProfileDir += "/"; sProfileDir += "/";
return CreateProfile( sProfileDir, sName ); return Profile::CreateNewProfile( sProfileDir, sName );
} }
bool ProfileManager::RenameLocalProfile( CString sProfileID, CString sNewName ) bool ProfileManager::RenameLocalProfile( CString sProfileID, CString sNewName )
@@ -271,13 +248,14 @@ bool ProfileManager::RenameLocalProfile( CString sProfileID, CString sNewName )
CString sProfileDir = USER_PROFILES_DIR + sProfileID; CString sProfileDir = USER_PROFILES_DIR + sProfileID;
Profile pro; Profile pro;
bool bResult; Profile::LoadResult lr;
bResult = pro.LoadAllFromDir( sProfileDir, PREFSMAN->m_bSignProfileData ); lr = pro.LoadAllFromDir( sProfileDir, PREFSMAN->m_bSignProfileData );
if( !bResult ) if( lr != Profile::success )
return false; return false;
pro.m_sDisplayName = sNewName; pro.m_sDisplayName = sNewName;
bResult = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData ); bool bSuccess;
if( !bResult ) bSuccess = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
if( !bSuccess )
return false; return false;
return true; return true;
@@ -314,14 +292,12 @@ void ProfileManager::SaveMachineProfile() const
m_MachineProfile.SaveAllToDir( MACHINE_PROFILE_DIR, false ); /* don't sign machine profiles */ m_MachineProfile.SaveAllToDir( MACHINE_PROFILE_DIR, false ); /* don't sign machine profiles */
} }
void ProfileManager::LoadMachineProfile() void ProfileManager::LoadMachineProfile()
{ {
if( !m_MachineProfile.LoadAllFromDir(MACHINE_PROFILE_DIR, false) ) Profile::LoadResult lr = m_MachineProfile.LoadAllFromDir(MACHINE_PROFILE_DIR, false);
if( lr == Profile::failed_no_profile )
{ {
CreateProfile(MACHINE_PROFILE_DIR, "Machine"); Profile::CreateNewProfile(MACHINE_PROFILE_DIR, "Machine");
m_MachineProfile.LoadAllFromDir( MACHINE_PROFILE_DIR, false ); m_MachineProfile.LoadAllFromDir( MACHINE_PROFILE_DIR, false );
} }
@@ -339,6 +315,11 @@ bool ProfileManager::LastLoadWasTamperedOrCorrupt( PlayerNumber pn ) const
return GetProfile(pn) && m_bLastLoadWasTamperedOrCorrupt[pn]; return GetProfile(pn) && m_bLastLoadWasTamperedOrCorrupt[pn];
} }
bool ProfileManager::LastLoadWasFromLastGood( PlayerNumber pn ) const
{
return GetProfile(pn) && m_bLastLoadWasFromLastGood[pn];
}
CString ProfileManager::GetProfileDir( ProfileSlot slot ) const CString ProfileManager::GetProfileDir( ProfileSlot slot ) const
{ {
switch( slot ) switch( slot )
+2 -2
View File
@@ -58,6 +58,7 @@ public:
CString GetPlayerName( PlayerNumber pn ) const; CString GetPlayerName( PlayerNumber pn ) const;
bool ProfileWasLoadedFromMemoryCard( PlayerNumber pn ) const; bool ProfileWasLoadedFromMemoryCard( PlayerNumber pn ) const;
bool LastLoadWasTamperedOrCorrupt( PlayerNumber pn ) const; bool LastLoadWasTamperedOrCorrupt( PlayerNumber pn ) const;
bool LastLoadWasFromLastGood( PlayerNumber pn ) const;
// //
@@ -84,9 +85,7 @@ public:
private: private:
bool CreateMemoryCardProfile( PlayerNumber pn );
bool LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIsMemCard ); bool LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIsMemCard );
bool CreateProfile( CString sProfileDir, CString sName );
// Directory that contains the profile. Either on local machine or // Directory that contains the profile. Either on local machine or
// on a memory card. // on a memory card.
@@ -94,6 +93,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];
// actual loaded profile data // actual loaded profile data
Profile m_Profile[NUM_PLAYERS]; Profile m_Profile[NUM_PLAYERS];
+11 -2
View File
@@ -53,6 +53,7 @@ ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our p
#define CREDITS_CREDITS THEME->GetMetric ("ScreenSystemLayer","CreditsCredits") #define CREDITS_CREDITS THEME->GetMetric ("ScreenSystemLayer","CreditsCredits")
#define CREDITS_NOT_PRESENT THEME->GetMetric ("ScreenSystemLayer","CreditsNotPresent") #define CREDITS_NOT_PRESENT THEME->GetMetric ("ScreenSystemLayer","CreditsNotPresent")
#define CREDITS_LOAD_FAILED THEME->GetMetric ("ScreenSystemLayer","CreditsLoadFailed") #define CREDITS_LOAD_FAILED THEME->GetMetric ("ScreenSystemLayer","CreditsLoadFailed")
#define CREDITS_LOADED_FROM_LAST_GOOD_APPEND THEME->GetMetric ("ScreenSystemLayer","CreditsLoadedFromLastGoodAppend")
#define CREDITS_JOIN_ONLY THEME->GetMetricB("ScreenSystemLayer","CreditsJoinOnly") #define CREDITS_JOIN_ONLY THEME->GetMetricB("ScreenSystemLayer","CreditsJoinOnly")
const int NUM_SKIPS_TO_SHOW = 5; const int NUM_SKIPS_TO_SHOW = 5;
@@ -196,7 +197,13 @@ void ScreenSystemLayer::RefreshCreditsMessages()
switch( mcs ) switch( mcs )
{ {
case MEMORY_CARD_STATE_NO_CARD: case MEMORY_CARD_STATE_NO_CARD:
if( pProfile ) // this is a local machine profile // this is a local machine profile
if( PROFILEMAN->LastLoadWasFromLastGood(p) && pProfile )
sCredits = pProfile->GetDisplayName() + CREDITS_LOADED_FROM_LAST_GOOD_APPEND;
else if( PROFILEMAN->LastLoadWasTamperedOrCorrupt(p) )
sCredits = CREDITS_LOAD_FAILED;
// Prefer the name of the profile over the name of the card.
else if( pProfile )
sCredits = pProfile->GetDisplayName(); sCredits = pProfile->GetDisplayName();
else if( GAMESTATE->PlayersCanJoin() ) else if( GAMESTATE->PlayersCanJoin() )
sCredits = CREDITS_INSERT_CARD; sCredits = CREDITS_INSERT_CARD;
@@ -210,7 +217,9 @@ void ScreenSystemLayer::RefreshCreditsMessages()
sCredits = CREDITS_CARD_TOO_LATE; sCredits = CREDITS_CARD_TOO_LATE;
break; break;
case MEMORY_CARD_STATE_READY: case MEMORY_CARD_STATE_READY:
if( PROFILEMAN->LastLoadWasTamperedOrCorrupt(p) ) if( PROFILEMAN->LastLoadWasFromLastGood(p) && pProfile )
sCredits = pProfile->GetDisplayName() + CREDITS_LOADED_FROM_LAST_GOOD_APPEND;
else if( PROFILEMAN->LastLoadWasTamperedOrCorrupt(p) )
sCredits = CREDITS_LOAD_FAILED; sCredits = CREDITS_LOAD_FAILED;
// Prefer the name of the profile over the name of the card. // Prefer the name of the profile over the name of the card.
else if( pProfile ) else if( pProfile )