FolderMemoryCard: Keep handles to all accessed files while a memory card is open. This prevents users from modifying card contents while the emulator is running.

This commit is contained in:
Admiral H. Curtiss 2015-08-09 14:44:23 +02:00
parent 30eb292b48
commit 879d0c601f
2 changed files with 60 additions and 29 deletions

View File

@ -43,7 +43,7 @@ void FolderMemoryCard::InitializeInternalData() {
m_timeLastWritten = 0;
m_isEnabled = false;
m_framesUntilFlush = 0;
m_lastAccessedFile.Close();
m_lastAccessedFile.CloseAll();
m_performFileWrites = true;
}
@ -107,7 +107,7 @@ void FolderMemoryCard::Close( bool flush ) {
m_cache.clear();
m_oldDataCache.clear();
m_fileMetadataQuickAccess.clear();
m_lastAccessedFile.Close();
m_lastAccessedFile.CloseAll();
}
void FolderMemoryCard::LoadMemoryCardData( const u32 sizeInClusters, const bool enableFiltering, const wxString& filter ) {
@ -455,7 +455,11 @@ bool FolderMemoryCard::AddFile( MemoryCardFileEntry* const dirEntry, const wxStr
file.Close();
AddFileEntryToMetadataQuickAccess( newFileEntry, parent );
MemoryCardFileMetadataReference* fileRef = AddFileEntryToMetadataQuickAccess( newFileEntry, parent );
if ( fileRef != nullptr ) {
// acquire a handle on the file so nothing else can change the file contents while the memory card is open
m_lastAccessedFile.ReOpen( m_folderName, fileRef );
}
// and finally, increase file count in the directory entry
dirEntry->entry.data.length++;
@ -508,12 +512,13 @@ MemoryCardFileMetadataReference* FolderMemoryCard::AddDirEntryToMetadataQuickAcc
return ref;
}
void FolderMemoryCard::AddFileEntryToMetadataQuickAccess( MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent ) {
u32 fileCluster = entry->entry.data.cluster;
MemoryCardFileMetadataReference* FolderMemoryCard::AddFileEntryToMetadataQuickAccess( MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent ) {
const u32 firstFileCluster = entry->entry.data.cluster;
u32 fileCluster = firstFileCluster;
// zero-length files have no file clusters
if ( fileCluster == 0xFFFFFFFFu ) {
return;
return nullptr;
}
u32 clusterNumber = 0;
@ -524,6 +529,8 @@ void FolderMemoryCard::AddFileEntryToMetadataQuickAccess( MemoryCardFileEntry* c
ref->consecutiveCluster = clusterNumber;
++clusterNumber;
} while ( ( fileCluster = m_fat.data[0][0][fileCluster] ) != ( LastDataCluster | DataClusterInUseMask ) );
return &m_fileMetadataQuickAccess[firstFileCluster & NextDataClusterMask];
}
s32 FolderMemoryCard::IsPresent() const {
@ -821,7 +828,6 @@ void FolderMemoryCard::NextFrame() {
}
void FolderMemoryCard::Flush() {
m_lastAccessedFile.Close();
if ( m_cache.empty() ) { return; }
Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system...", m_slot );
@ -877,7 +883,7 @@ void FolderMemoryCard::Flush() {
FlushPage( i );
}
m_lastAccessedFile.Close();
m_lastAccessedFile.FlushAll();
m_oldDataCache.clear();
const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue();
@ -1005,6 +1011,7 @@ void FolderMemoryCard::FlushDeletedFilesAndRemoveUnchangedDataFromCache( const s
FileAccessHelper::CleanMemcardFilename( cleanName );
const wxString fileName = wxString::FromAscii( cleanName );
const wxString filePath = m_folderName.GetFullPath() + dirPath + L"/" + fileName;
m_lastAccessedFile.CloseMatching( filePath );
const wxString newFilePath = m_folderName.GetFullPath() + dirPath + L"/_pcsx2_deleted_" + fileName;
if ( wxFileName::DirExists( newFilePath ) ) {
// wxRenameFile doesn't overwrite directories, so we have to remove the old one first
@ -1309,16 +1316,14 @@ void FolderMemoryCard::CalculateECC( u8* ecc, const u8* data ) {
FileAccessHelper::FileAccessHelper() {
m_file = nullptr;
m_files.clear();
}
FileAccessHelper::~FileAccessHelper() {
this->Close();
this->CloseAll();
}
wxFFile* FileAccessHelper::Open( const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata ) {
this->Close();
wxFileName fn( folderName );
bool cleanedFilename = fileRef->GetPath( &fn );
wxString filename( fn.GetFullPath() );
@ -1331,12 +1336,11 @@ wxFFile* FileAccessHelper::Open( const wxFileName& folderName, MemoryCardFileMet
createEmptyFile.Close();
}
m_file = new wxFFile( filename, L"r+b" );
m_entry = fileRef->entry;
const MemoryCardFileEntry* const entry = fileRef->entry;
wxFFile* file = new wxFFile( filename, L"r+b" );
m_files.emplace( entry, file );
if ( writeMetadata ) {
const MemoryCardFileEntry* const entry = fileRef->entry;
// write metadata of file if it's nonstandard
fn.AppendDir( L"_pcsx2_meta" );
if ( cleanedFilename || entry->entry.data.mode != MemoryCardFileEntry::DefaultFileMode || entry->entry.data.attr != 0 ) {
@ -1362,22 +1366,45 @@ wxFFile* FileAccessHelper::Open( const wxFileName& folderName, MemoryCardFileMet
}
}
return m_file;
return file;
}
wxFFile* FileAccessHelper::ReOpen( const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata ) {
if ( m_file && fileRef->entry == m_entry ) {
return m_file;
auto it = m_files.find( fileRef->entry );
if ( it != m_files.end() ) {
return it->second;
} else {
return this->Open( folderName, fileRef, writeMetadata );
}
}
void FileAccessHelper::Close() {
if ( m_file ) {
m_file->Close();
delete m_file;
m_file = nullptr;
void FileAccessHelper::CloseMatching( const wxString& path ) {
wxFileName fn( path );
fn.Normalize();
wxString pathNormalized = fn.GetFullPath();
for ( auto it = m_files.begin(); it != m_files.end(); ) {
wxString openPath = it->second->GetName();
if ( openPath.StartsWith( pathNormalized ) ) {
it->second->Close();
delete it->second;
it = m_files.erase( it );
} else {
++it;
}
}
}
void FileAccessHelper::CloseAll() {
for ( auto it = m_files.begin(); it != m_files.end(); ++it ) {
it->second->Close();
delete it->second;
}
m_files.clear();
}
void FileAccessHelper::FlushAll() {
for ( auto it = m_files.begin(); it != m_files.end(); ++it ) {
it->second->Flush();
}
}

View File

@ -187,8 +187,7 @@ struct MemoryCardFileMetadataReference {
// Small helper class to keep memory card files opened between calls to Read()/Save()
class FileAccessHelper {
protected:
wxFFile* m_file;
const MemoryCardFileEntry* m_entry;
std::map<const MemoryCardFileEntry* const, wxFFile*> m_files;
public:
FileAccessHelper();
@ -196,8 +195,12 @@ public:
// Get an already opened file if possible, or open a new one and remember it
wxFFile* ReOpen( const wxFileName& folderName, MemoryCardFileMetadataReference* fileRef, bool writeMetadata = false );
// Close an open file, if any
void Close();
// Close all open files that start with the given path, so either a file if a filename is given or all files in a directory and its subdirectories when a directory is given
void CloseMatching( const wxString& path );
// Close all open files
void CloseAll();
// Flush the written data of all open files to the file system
void FlushAll();
// removes characters from a PS2 file name that would be illegal in a Windows file system
// returns true if any changes were made
@ -413,7 +416,8 @@ protected:
// adds a file to the quick-access dictionary, so it can be accessed more efficiently (ie, without searching through the entire file system) later
void AddFileEntryToMetadataQuickAccess( MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent );
// returns the MemoryCardFileMetadataReference of the first file cluster, or nullptr if the file is zero-length
MemoryCardFileMetadataReference* AddFileEntryToMetadataQuickAccess( MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent );
// creates a reference to a directory entry, so it can be passed as parent to other files/directories
MemoryCardFileMetadataReference* AddDirEntryToMetadataQuickAccess( MemoryCardFileEntry* const entry, MemoryCardFileMetadataReference* const parent );