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:
+19
-12
@@ -563,11 +563,8 @@ void Profile::IncrementCategoryPlayCount( StepsType st, RankingCategory rc )
|
||||
XNode* X = xml.GetChild(#X); \
|
||||
if( X==NULL ) LOG->Warn("Failed to read section " #X); \
|
||||
else Load##X##FromNode(X); }
|
||||
int g_iOnceCtr;
|
||||
#define FOR_ONCE for(g_iOnceCtr=0;g_iOnceCtr<1;g_iOnceCtr++)
|
||||
|
||||
|
||||
bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
Profile::LoadResult Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
{
|
||||
CHECKPOINT;
|
||||
|
||||
@@ -581,7 +578,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
// Check for the existance of stats.xml
|
||||
CString fn = sDir + STATS_XML;
|
||||
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.
|
||||
@@ -592,7 +589,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
if( iBytes > MAX_PLAYER_STATS_XML_SIZE_BYTES )
|
||||
{
|
||||
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) )
|
||||
{
|
||||
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." );
|
||||
|
||||
@@ -615,7 +612,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
if( !CryptManager::VerifyFileWithFile(fn, sStatsXmlSigFile) )
|
||||
{
|
||||
LOG->Warn( "The signature check for '%s' failed. Data will be ignored.", fn.c_str() );
|
||||
return false; // error
|
||||
return failed_tampered;
|
||||
}
|
||||
LOG->Trace( "Done." );
|
||||
}
|
||||
@@ -625,19 +622,19 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
if( !xml.LoadFromFile( fn ) )
|
||||
{
|
||||
LOG->Warn( "Couldn't open file '%s' for reading.", fn.c_str() );
|
||||
return false; // error
|
||||
return failed_tampered;
|
||||
}
|
||||
LOG->Trace( "Done." );
|
||||
|
||||
/* The placeholder stats.xml file has an <html> tag. Don't load it, but don't
|
||||
* warn about it. */
|
||||
if( xml.name == "html" )
|
||||
return true; // success
|
||||
return failed_no_profile;
|
||||
|
||||
if( xml.name != "Stats" )
|
||||
{
|
||||
WARN_M( xml.name );
|
||||
return false; // error
|
||||
return failed_tampered;
|
||||
}
|
||||
|
||||
LOAD_NODE( GeneralData );
|
||||
@@ -649,7 +646,7 @@ bool Profile::LoadAllFromDir( CString sDir, bool bRequireSignature )
|
||||
LOAD_NODE( RecentSongScores );
|
||||
LOAD_NODE( RecentCourseScores );
|
||||
|
||||
return true; // success
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Profile::SaveAllToDir( CString sDir, bool bSignData ) const
|
||||
@@ -1578,11 +1575,21 @@ XNode* Profile::SaveCoinDataCreateNode() const
|
||||
|
||||
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+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND );
|
||||
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
|
||||
* All rights reserved.
|
||||
|
||||
@@ -260,7 +260,8 @@ public:
|
||||
//
|
||||
// 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;
|
||||
|
||||
void LoadEditableDataFromDir( CString sDir );
|
||||
@@ -289,6 +290,7 @@ public:
|
||||
void SaveStatsWebPageToDir( CString sDir ) const;
|
||||
void SaveMachinePublicKeyToDir( CString sDir ) const;
|
||||
|
||||
static bool CreateNewProfile( CString sProfileDir, CString sName );
|
||||
static void BackupToDir( CString sFromDir, CString sToDir );
|
||||
|
||||
private:
|
||||
|
||||
@@ -28,7 +28,7 @@ ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our
|
||||
#define NEW_MEM_CARD_NAME ""
|
||||
#define USER_PROFILES_DIR "Data/LocalProfiles/"
|
||||
#define MACHINE_PROFILE_DIR "Data/MachineProfile/"
|
||||
|
||||
const CString LAST_GOOD_DIR = "LastGood/";
|
||||
|
||||
ProfileManager::ProfileManager()
|
||||
{
|
||||
@@ -44,6 +44,7 @@ void ProfileManager::Init()
|
||||
{
|
||||
m_bWasLoadedFromMemoryCard[p] = false;
|
||||
m_bLastLoadWasTamperedOrCorrupt[p] = false;
|
||||
m_bLastLoadWasFromLastGood[p] = false;
|
||||
}
|
||||
|
||||
LoadMachineProfile();
|
||||
@@ -77,44 +78,37 @@ bool ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIs
|
||||
ASSERT( !sProfileDir.empty() );
|
||||
ASSERT( sProfileDir.Right(1) == "/" );
|
||||
|
||||
if( bIsMemCard )
|
||||
MEMCARDMAN->PauseMountingThread();
|
||||
|
||||
m_sProfileDir[pn] = sProfileDir;
|
||||
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 );
|
||||
|
||||
CString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_DIR;
|
||||
|
||||
// Save a backup of the 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( bSuccess )
|
||||
// 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 == Profile::success )
|
||||
{
|
||||
CString sBackupDir = m_sProfileDir[pn] + "LastGood/";
|
||||
Profile::BackupToDir( m_sProfileDir[pn], sBackupDir );
|
||||
}
|
||||
|
||||
if( bIsMemCard )
|
||||
MEMCARDMAN->UnPauseMountingThread();
|
||||
m_bLastLoadWasTamperedOrCorrupt[pn] = lr == Profile::failed_tampered;
|
||||
|
||||
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 )
|
||||
{
|
||||
bool bResult;
|
||||
|
||||
Profile pro;
|
||||
pro.m_sDisplayName = sName;
|
||||
bResult = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
|
||||
if( !bResult )
|
||||
return false;
|
||||
|
||||
FlushDirCache();
|
||||
return true;
|
||||
return lr == Profile::success;
|
||||
}
|
||||
|
||||
bool ProfileManager::LoadLocalProfileFromMachine( PlayerNumber pn )
|
||||
@@ -138,43 +132,25 @@ bool ProfileManager::LoadProfileFromMemoryCard( PlayerNumber pn )
|
||||
// mount slot
|
||||
if( MEMCARDMAN->GetCardState(pn) == MEMORY_CARD_STATE_READY )
|
||||
{
|
||||
|
||||
CString sDir = MEM_CARD_MOUNT_POINT[pn];
|
||||
|
||||
// tack on a subdirectory so that we don't write everything to the root
|
||||
sDir += PREFSMAN->m_sMemoryCardProfileSubdir;
|
||||
sDir += '/';
|
||||
|
||||
bool bResult;
|
||||
bResult = LoadProfile( pn, sDir, true );
|
||||
if( bResult )
|
||||
return true;
|
||||
|
||||
CreateMemoryCardProfile( pn );
|
||||
|
||||
bResult = LoadProfile( pn, sDir, true );
|
||||
return bResult;
|
||||
MEMCARDMAN->PauseMountingThread();
|
||||
bool bSuccess;
|
||||
bSuccess = LoadProfile( pn, sDir, true );
|
||||
|
||||
MEMCARDMAN->UnPauseMountingThread();
|
||||
|
||||
return true; // If a card is inserted, we want to use the memory card to save - even if the Profile load failed.
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
if( LoadProfileFromMemoryCard(pn) )
|
||||
@@ -192,7 +168,7 @@ void ProfileManager::SaveAllProfiles() const
|
||||
|
||||
FOREACH_HumanPlayer( pn )
|
||||
{
|
||||
if( !this->IsUsingProfile(pn) )
|
||||
if( !IsUsingProfile(pn) )
|
||||
continue;
|
||||
|
||||
this->SaveProfile( pn );
|
||||
@@ -220,6 +196,7 @@ void ProfileManager::UnloadProfile( PlayerNumber pn )
|
||||
m_sProfileDir[pn] = "";
|
||||
m_bWasLoadedFromMemoryCard[pn] = false;
|
||||
m_bLastLoadWasTamperedOrCorrupt[pn] = false;
|
||||
m_bLastLoadWasFromLastGood[pn] = false;
|
||||
m_Profile[pn].InitAll();
|
||||
}
|
||||
|
||||
@@ -261,7 +238,7 @@ bool ProfileManager::CreateLocalProfile( CString sName )
|
||||
return false;
|
||||
sProfileDir += "/";
|
||||
|
||||
return CreateProfile( sProfileDir, sName );
|
||||
return Profile::CreateNewProfile( sProfileDir, sName );
|
||||
}
|
||||
|
||||
bool ProfileManager::RenameLocalProfile( CString sProfileID, CString sNewName )
|
||||
@@ -271,13 +248,14 @@ bool ProfileManager::RenameLocalProfile( CString sProfileID, CString sNewName )
|
||||
CString sProfileDir = USER_PROFILES_DIR + sProfileID;
|
||||
|
||||
Profile pro;
|
||||
bool bResult;
|
||||
bResult = pro.LoadAllFromDir( sProfileDir, PREFSMAN->m_bSignProfileData );
|
||||
if( !bResult )
|
||||
Profile::LoadResult lr;
|
||||
lr = pro.LoadAllFromDir( sProfileDir, PREFSMAN->m_bSignProfileData );
|
||||
if( lr != Profile::success )
|
||||
return false;
|
||||
pro.m_sDisplayName = sNewName;
|
||||
bResult = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
|
||||
if( !bResult )
|
||||
bool bSuccess;
|
||||
bSuccess = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
|
||||
if( !bSuccess )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -314,14 +292,12 @@ void ProfileManager::SaveMachineProfile() const
|
||||
m_MachineProfile.SaveAllToDir( MACHINE_PROFILE_DIR, false ); /* don't sign machine profiles */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -339,6 +315,11 @@ bool ProfileManager::LastLoadWasTamperedOrCorrupt( PlayerNumber pn ) const
|
||||
return GetProfile(pn) && m_bLastLoadWasTamperedOrCorrupt[pn];
|
||||
}
|
||||
|
||||
bool ProfileManager::LastLoadWasFromLastGood( PlayerNumber pn ) const
|
||||
{
|
||||
return GetProfile(pn) && m_bLastLoadWasFromLastGood[pn];
|
||||
}
|
||||
|
||||
CString ProfileManager::GetProfileDir( ProfileSlot slot ) const
|
||||
{
|
||||
switch( slot )
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
CString GetPlayerName( PlayerNumber pn ) const;
|
||||
bool ProfileWasLoadedFromMemoryCard( PlayerNumber pn ) const;
|
||||
bool LastLoadWasTamperedOrCorrupt( PlayerNumber pn ) const;
|
||||
bool LastLoadWasFromLastGood( PlayerNumber pn ) const;
|
||||
|
||||
|
||||
//
|
||||
@@ -84,9 +85,7 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
bool CreateMemoryCardProfile( PlayerNumber pn );
|
||||
bool LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIsMemCard );
|
||||
bool CreateProfile( CString sProfileDir, CString sName );
|
||||
|
||||
// Directory that contains the profile. Either on local machine or
|
||||
// on a memory card.
|
||||
@@ -94,6 +93,7 @@ private:
|
||||
|
||||
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_bLastLoadWasFromLastGood[NUM_PLAYERS];
|
||||
|
||||
// actual loaded profile data
|
||||
Profile m_Profile[NUM_PLAYERS];
|
||||
|
||||
@@ -53,6 +53,7 @@ ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our p
|
||||
#define CREDITS_CREDITS THEME->GetMetric ("ScreenSystemLayer","CreditsCredits")
|
||||
#define CREDITS_NOT_PRESENT THEME->GetMetric ("ScreenSystemLayer","CreditsNotPresent")
|
||||
#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")
|
||||
|
||||
const int NUM_SKIPS_TO_SHOW = 5;
|
||||
@@ -196,7 +197,13 @@ void ScreenSystemLayer::RefreshCreditsMessages()
|
||||
switch( mcs )
|
||||
{
|
||||
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();
|
||||
else if( GAMESTATE->PlayersCanJoin() )
|
||||
sCredits = CREDITS_INSERT_CARD;
|
||||
@@ -210,7 +217,9 @@ void ScreenSystemLayer::RefreshCreditsMessages()
|
||||
sCredits = CREDITS_CARD_TOO_LATE;
|
||||
break;
|
||||
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;
|
||||
// Prefer the name of the profile over the name of the card.
|
||||
else if( pProfile )
|
||||
|
||||
Reference in New Issue
Block a user