diff --git a/pcsx2/gui/MemoryCardFolder.cpp b/pcsx2/gui/MemoryCardFolder.cpp index 2f6885af4..6278036ae 100644 --- a/pcsx2/gui/MemoryCardFolder.cpp +++ b/pcsx2/gui/MemoryCardFolder.cpp @@ -109,8 +109,8 @@ void FolderMemoryCard::Close( bool flush ) { m_cache.clear(); m_oldDataCache.clear(); - m_fileMetadataQuickAccess.clear(); m_lastAccessedFile.CloseAll(); + m_fileMetadataQuickAccess.clear(); } 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(); MemoryCardFileEntry* const rootDirEntry = &m_fileEntryDict[m_superBlock.data.rootdir_cluster].entries[0]; 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() { 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 ); const u64 timeFlushStart = wxGetLocalTimeMillis().GetValue(); @@ -896,10 +904,15 @@ void FolderMemoryCard::Flush() { } m_lastAccessedFile.FlushAll(); + m_lastAccessedFile.ClearMetadataWriteState(); m_oldDataCache.clear(); const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue(); 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 ) { @@ -1344,6 +1357,20 @@ void FolderMemoryCard::CalculateECC( u8* ecc, const u8* data ) { 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() { m_files.clear(); @@ -1370,7 +1397,13 @@ wxFFile* FileAccessHelper::Open( const wxFileName& folderName, MemoryCardFileMet const MemoryCardFileEntry* const entry = fileRef->entry; 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 ) { 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 ) { - auto it = m_files.find( fileRef->entry ); + std::string internalPath; + fileRef->GetInternalPath( &internalPath ); + auto it = m_files.find( internalPath ); if ( it != m_files.end() ) { // 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 { return this->Open( folderName, fileRef, writeMetadata ); } @@ -1458,9 +1496,9 @@ void FileAccessHelper::CloseMatching( const wxString& path ) { fn.Normalize(); wxString pathNormalized = fn.GetFullPath(); 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 ) ) { - CloseFileHandle( it->second, it->first ); + CloseFileHandle( it->second.fileHandle, it->second.fileRef->entry ); it = m_files.erase( it ); } else { ++it; @@ -1470,17 +1508,21 @@ void FileAccessHelper::CloseMatching( const wxString& path ) { void FileAccessHelper::CloseAll() { 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(); } void FileAccessHelper::FlushAll() { 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 ) { // invalid characters for filenames in the PS2 file system: { '/', '?', '*' } // 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; } +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() { for ( uint i = 0; i < TotalCardSlots; ++i ) { diff --git a/pcsx2/gui/MemoryCardFolder.h b/pcsx2/gui/MemoryCardFolder.h index feded636a..740893418 100644 --- a/pcsx2/gui/MemoryCardFolder.h +++ b/pcsx2/gui/MemoryCardFolder.h @@ -24,6 +24,8 @@ #include "PluginCallbacks.h" #include "AppConfig.h" +//#define DEBUG_WRITE_FOLDER_CARD_IN_MEMORY_TO_FILE_ON_CHANGE + // -------------------------------------------------------------------------------------- // Superblock Header Struct // -------------------------------------------------------------------------------------- @@ -195,6 +197,14 @@ struct MemoryCardFileMetadataReference { // returns true if filename was modified and metadata containing the actual filename should be written 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() class FileAccessHelper { protected: - std::map m_files; + std::map m_files; MemoryCardFileMetadataReference* m_lastWrittenFileRef; // we remember this to reduce redundant metadata checks/writes public: @@ -219,6 +229,9 @@ public: // Flush the written data of all open files to the file system 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 // returns true if any changes were made static bool CleanMemcardFilename( char* name ); @@ -348,6 +361,8 @@ public: static void CalculateECC( u8* ecc, const u8* data ); + void WriteToFile( const wxString& filename ); + protected: // initializes memory card data, as if it was fresh from the factory void InitializeInternalData();