mirror of
https://github.com/libretro/pcsx2.git
synced 2024-12-12 03:56:26 +00:00
Merge pull request #980 from AdmiralCurtiss/ff12mcdfix
FolderMemoryCard: Fix issue #976: Corrupted FF12 saves when overwriting data.
This commit is contained in:
commit
d3ec74be2b
@ -109,8 +109,8 @@ void FolderMemoryCard::Close( bool flush ) {
|
|||||||
|
|
||||||
m_cache.clear();
|
m_cache.clear();
|
||||||
m_oldDataCache.clear();
|
m_oldDataCache.clear();
|
||||||
m_fileMetadataQuickAccess.clear();
|
|
||||||
m_lastAccessedFile.CloseAll();
|
m_lastAccessedFile.CloseAll();
|
||||||
|
m_fileMetadataQuickAccess.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderMemoryCard::LoadMemoryCardData( const u32 sizeInClusters, const bool enableFiltering, const wxString& filter ) {
|
void FolderMemoryCard::LoadMemoryCardData( const u32 sizeInClusters, const bool enableFiltering, const wxString& filter ) {
|
||||||
@ -142,6 +142,10 @@ void FolderMemoryCard::LoadMemoryCardData( const u32 sizeInClusters, const bool
|
|||||||
CreateRootDir();
|
CreateRootDir();
|
||||||
MemoryCardFileEntry* const rootDirEntry = &m_fileEntryDict[m_superBlock.data.rootdir_cluster].entries[0];
|
MemoryCardFileEntry* const rootDirEntry = &m_fileEntryDict[m_superBlock.data.rootdir_cluster].entries[0];
|
||||||
AddFolder( rootDirEntry, m_folderName.GetPath(), nullptr, enableFiltering, filter );
|
AddFolder( rootDirEntry, m_folderName.GetPath(), nullptr, enableFiltering, filter );
|
||||||
|
|
||||||
|
#ifdef DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE
|
||||||
|
WriteToFile( m_folderName.GetFullPath().RemoveLast() + L"-debug_" + wxDateTime::Now().Format( L"%Y-%m-%d-%H-%M-%S" ) + L"_load.ps2" );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -842,6 +846,10 @@ void FolderMemoryCard::NextFrame() {
|
|||||||
void FolderMemoryCard::Flush() {
|
void FolderMemoryCard::Flush() {
|
||||||
if ( m_cache.empty() ) { return; }
|
if ( m_cache.empty() ) { return; }
|
||||||
|
|
||||||
|
#ifdef DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE
|
||||||
|
WriteToFile( m_folderName.GetFullPath().RemoveLast() + L"-debug_" + wxDateTime::Now().Format( L"%Y-%m-%d-%H-%M-%S" ) + L"_pre-flush.ps2" );
|
||||||
|
#endif
|
||||||
|
|
||||||
Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system...", m_slot );
|
Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system...", m_slot );
|
||||||
const u64 timeFlushStart = wxGetLocalTimeMillis().GetValue();
|
const u64 timeFlushStart = wxGetLocalTimeMillis().GetValue();
|
||||||
|
|
||||||
@ -896,10 +904,15 @@ void FolderMemoryCard::Flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_lastAccessedFile.FlushAll();
|
m_lastAccessedFile.FlushAll();
|
||||||
|
m_lastAccessedFile.ClearMetadataWriteState();
|
||||||
m_oldDataCache.clear();
|
m_oldDataCache.clear();
|
||||||
|
|
||||||
const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue();
|
const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue();
|
||||||
Console.WriteLn( L"(FolderMcd) Done! Took %u ms.", timeFlushEnd - timeFlushStart );
|
Console.WriteLn( L"(FolderMcd) Done! Took %u ms.", timeFlushEnd - timeFlushStart );
|
||||||
|
|
||||||
|
#ifdef DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE
|
||||||
|
WriteToFile( m_folderName.GetFullPath().RemoveLast() + L"-debug_" + wxDateTime::Now().Format( L"%Y-%m-%d-%H-%M-%S" ) + L"_post-flush.ps2" );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FolderMemoryCard::FlushPage( const u32 page ) {
|
bool FolderMemoryCard::FlushPage( const u32 page ) {
|
||||||
@ -1344,6 +1357,20 @@ void FolderMemoryCard::CalculateECC( u8* ecc, const u8* data ) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FolderMemoryCard::WriteToFile( const wxString& filename ) {
|
||||||
|
wxFFile targetFile( filename, L"wb" );
|
||||||
|
|
||||||
|
u8 buffer[FolderMemoryCard::PageSizeRaw];
|
||||||
|
u32 adr = 0;
|
||||||
|
while ( adr < GetSizeInClusters() * FolderMemoryCard::ClusterSizeRaw ) {
|
||||||
|
Read( buffer, adr, FolderMemoryCard::PageSizeRaw );
|
||||||
|
targetFile.Write( buffer, FolderMemoryCard::PageSizeRaw );
|
||||||
|
adr += FolderMemoryCard::PageSizeRaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetFile.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FileAccessHelper::FileAccessHelper() {
|
FileAccessHelper::FileAccessHelper() {
|
||||||
m_files.clear();
|
m_files.clear();
|
||||||
@ -1370,7 +1397,13 @@ wxFFile* FileAccessHelper::Open( const wxFileName& folderName, MemoryCardFileMet
|
|||||||
|
|
||||||
const MemoryCardFileEntry* const entry = fileRef->entry;
|
const MemoryCardFileEntry* const entry = fileRef->entry;
|
||||||
wxFFile* file = new wxFFile( filename, L"r+b" );
|
wxFFile* file = new wxFFile( filename, L"r+b" );
|
||||||
m_files.emplace( entry, file );
|
|
||||||
|
std::string internalPath;
|
||||||
|
fileRef->GetInternalPath( &internalPath );
|
||||||
|
MemoryCardFileHandleStructure handleStruct;
|
||||||
|
handleStruct.fileHandle = file;
|
||||||
|
handleStruct.fileRef = fileRef;
|
||||||
|
m_files.emplace( internalPath, handleStruct );
|
||||||
|
|
||||||
if ( writeMetadata ) {
|
if ( writeMetadata ) {
|
||||||
fn.AppendDir( L"_pcsx2_meta" );
|
fn.AppendDir( L"_pcsx2_meta" );
|
||||||
@ -1418,7 +1451,9 @@ void FileAccessHelper::WriteMetadata( bool metadataIsNonstandard, wxFileName& me
|
|||||||
}
|
}
|
||||||
|
|
||||||
wxFFile* FileAccessHelper::ReOpen( const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata ) {
|
wxFFile* FileAccessHelper::ReOpen( const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata ) {
|
||||||
auto it = m_files.find( fileRef->entry );
|
std::string internalPath;
|
||||||
|
fileRef->GetInternalPath( &internalPath );
|
||||||
|
auto it = m_files.find( internalPath );
|
||||||
if ( it != m_files.end() ) {
|
if ( it != m_files.end() ) {
|
||||||
// we already have a handle to this file
|
// we already have a handle to this file
|
||||||
|
|
||||||
@ -1434,7 +1469,10 @@ wxFFile* FileAccessHelper::ReOpen( const wxFileName& folderName, MemoryCardFileM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return it->second;
|
// update the fileRef in the map since it might have been modified or deleted
|
||||||
|
it->second.fileRef = fileRef;
|
||||||
|
|
||||||
|
return it->second.fileHandle;
|
||||||
} else {
|
} else {
|
||||||
return this->Open( folderName, fileRef, writeMetadata );
|
return this->Open( folderName, fileRef, writeMetadata );
|
||||||
}
|
}
|
||||||
@ -1458,9 +1496,9 @@ void FileAccessHelper::CloseMatching( const wxString& path ) {
|
|||||||
fn.Normalize();
|
fn.Normalize();
|
||||||
wxString pathNormalized = fn.GetFullPath();
|
wxString pathNormalized = fn.GetFullPath();
|
||||||
for ( auto it = m_files.begin(); it != m_files.end(); ) {
|
for ( auto it = m_files.begin(); it != m_files.end(); ) {
|
||||||
wxString openPath = it->second->GetName();
|
wxString openPath = it->second.fileHandle->GetName();
|
||||||
if ( openPath.StartsWith( pathNormalized ) ) {
|
if ( openPath.StartsWith( pathNormalized ) ) {
|
||||||
CloseFileHandle( it->second, it->first );
|
CloseFileHandle( it->second.fileHandle, it->second.fileRef->entry );
|
||||||
it = m_files.erase( it );
|
it = m_files.erase( it );
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@ -1470,17 +1508,21 @@ void FileAccessHelper::CloseMatching( const wxString& path ) {
|
|||||||
|
|
||||||
void FileAccessHelper::CloseAll() {
|
void FileAccessHelper::CloseAll() {
|
||||||
for ( auto it = m_files.begin(); it != m_files.end(); ++it ) {
|
for ( auto it = m_files.begin(); it != m_files.end(); ++it ) {
|
||||||
CloseFileHandle( it->second, it->first );
|
CloseFileHandle( it->second.fileHandle, it->second.fileRef->entry );
|
||||||
}
|
}
|
||||||
m_files.clear();
|
m_files.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileAccessHelper::FlushAll() {
|
void FileAccessHelper::FlushAll() {
|
||||||
for ( auto it = m_files.begin(); it != m_files.end(); ++it ) {
|
for ( auto it = m_files.begin(); it != m_files.end(); ++it ) {
|
||||||
it->second->Flush();
|
it->second.fileHandle->Flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileAccessHelper::ClearMetadataWriteState() {
|
||||||
|
m_lastWrittenFileRef = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool FileAccessHelper::CleanMemcardFilename( char* name ) {
|
bool FileAccessHelper::CleanMemcardFilename( char* name ) {
|
||||||
// invalid characters for filenames in the PS2 file system: { '/', '?', '*' }
|
// invalid characters for filenames in the PS2 file system: { '/', '?', '*' }
|
||||||
// the following characters are valid in a PS2 memcard file system but invalid in Windows
|
// the following characters are valid in a PS2 memcard file system but invalid in Windows
|
||||||
@ -1521,6 +1563,17 @@ bool MemoryCardFileMetadataReference::GetPath( wxFileName* fileName ) const {
|
|||||||
return parentCleaned || localCleaned;
|
return parentCleaned || localCleaned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryCardFileMetadataReference::GetInternalPath( std::string* fileName ) const {
|
||||||
|
if ( parent ) {
|
||||||
|
parent->GetInternalPath( fileName );
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName->append( (const char*)entry->entry.data.name );
|
||||||
|
|
||||||
|
if ( entry->IsDir() ) {
|
||||||
|
fileName->append( "/" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FolderMemoryCardAggregator::FolderMemoryCardAggregator() {
|
FolderMemoryCardAggregator::FolderMemoryCardAggregator() {
|
||||||
for ( uint i = 0; i < TotalCardSlots; ++i ) {
|
for ( uint i = 0; i < TotalCardSlots; ++i ) {
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "PluginCallbacks.h"
|
#include "PluginCallbacks.h"
|
||||||
#include "AppConfig.h"
|
#include "AppConfig.h"
|
||||||
|
|
||||||
|
//#define DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Superblock Header Struct
|
// Superblock Header Struct
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
@ -195,6 +197,14 @@ struct MemoryCardFileMetadataReference {
|
|||||||
|
|
||||||
// returns true if filename was modified and metadata containing the actual filename should be written
|
// returns true if filename was modified and metadata containing the actual filename should be written
|
||||||
bool GetPath( wxFileName* fileName ) const;
|
bool GetPath( wxFileName* fileName ) const;
|
||||||
|
|
||||||
|
// gives the internal memory card file system path, not to be used for writes to the host file system
|
||||||
|
void GetInternalPath( std::string* fileName ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemoryCardFileHandleStructure {
|
||||||
|
MemoryCardFileMetadataReference* fileRef;
|
||||||
|
wxFFile* fileHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
@ -203,7 +213,7 @@ struct MemoryCardFileMetadataReference {
|
|||||||
// Small helper class to keep memory card files opened between calls to Read()/Save()
|
// Small helper class to keep memory card files opened between calls to Read()/Save()
|
||||||
class FileAccessHelper {
|
class FileAccessHelper {
|
||||||
protected:
|
protected:
|
||||||
std::map<const MemoryCardFileEntry* const, wxFFile*> m_files;
|
std::map<std::string, MemoryCardFileHandleStructure> m_files;
|
||||||
MemoryCardFileMetadataReference* m_lastWrittenFileRef; // we remember this to reduce redundant metadata checks/writes
|
MemoryCardFileMetadataReference* m_lastWrittenFileRef; // we remember this to reduce redundant metadata checks/writes
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -219,6 +229,9 @@ public:
|
|||||||
// Flush the written data of all open files to the file system
|
// Flush the written data of all open files to the file system
|
||||||
void FlushAll();
|
void FlushAll();
|
||||||
|
|
||||||
|
// Force metadata to be written on next file access, not sure if this is necessary but it can't hurt.
|
||||||
|
void ClearMetadataWriteState();
|
||||||
|
|
||||||
// removes characters from a PS2 file name that would be illegal in a Windows file system
|
// removes characters from a PS2 file name that would be illegal in a Windows file system
|
||||||
// returns true if any changes were made
|
// returns true if any changes were made
|
||||||
static bool CleanMemcardFilename( char* name );
|
static bool CleanMemcardFilename( char* name );
|
||||||
@ -348,6 +361,8 @@ public:
|
|||||||
|
|
||||||
static void CalculateECC( u8* ecc, const u8* data );
|
static void CalculateECC( u8* ecc, const u8* data );
|
||||||
|
|
||||||
|
void WriteToFile( const wxString& filename );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// initializes memory card data, as if it was fresh from the factory
|
// initializes memory card data, as if it was fresh from the factory
|
||||||
void InitializeInternalData();
|
void InitializeInternalData();
|
||||||
|
Loading…
Reference in New Issue
Block a user