|
|
//===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose: Filesystem abstraction for CSaveRestore - allows for storing temp save files
// either in memory or on disk.
//
//===========================================================================//
#ifdef _WIN32
#include "winerror.h"
#endif
#include "filesystem_engine.h"
#include "saverestore_filesystem.h"
#include "saverestore_filesystem_passthrough.h"
#include "host_saverestore.h"
#include "host.h"
#include "sys.h"
#include "tier1/utlbuffer.h"
#include "tier1/lzss.h"
#include "tier1/convar.h"
#include "ixboxsystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define MOD_DIR "DEFAULT_WRITE_PATH"
//-----------------------------------------------------------------------------
// Purpose: Implementation to execute traditional save to disk behavior
//-----------------------------------------------------------------------------
CSaveRestoreFileSystemPassthrough::CSaveRestoreFileSystemPassthrough() : m_iContainerOpens( 0 ) {}
bool CSaveRestoreFileSystemPassthrough::FileExists( const char *pFileName, const char *pPathID ) { return g_pFileSystem->FileExists( pFileName, pPathID ); }
void CSaveRestoreFileSystemPassthrough::RemoveFile( char const* pRelativePath, const char *pathID ) { g_pFileSystem->RemoveFile( pRelativePath, pathID ); }
void CSaveRestoreFileSystemPassthrough::RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID ) { g_pFileSystem->RenameFile( pOldPath, pNewPath, pathID ); }
void CSaveRestoreFileSystemPassthrough::AsyncFinishAllWrites( void ) { g_pFileSystem->AsyncFinishAllWrites(); }
FileHandle_t CSaveRestoreFileSystemPassthrough::Open( const char *pFullName, const char *pOptions, const char *pathID ) { return g_pFileSystem->OpenEx( pFullName, pOptions, FSOPEN_NEVERINPACK, pathID ); }
void CSaveRestoreFileSystemPassthrough::Close( FileHandle_t hSaveFile ) { g_pFileSystem->Close( hSaveFile ); }
int CSaveRestoreFileSystemPassthrough::Read( void *pOutput, int size, FileHandle_t hFile ) { return g_pFileSystem->Read( pOutput, size, hFile ); }
int CSaveRestoreFileSystemPassthrough::Write( void const* pInput, int size, FileHandle_t hFile ) { return g_pFileSystem->Write( pInput, size, hFile ); }
FSAsyncStatus_t CSaveRestoreFileSystemPassthrough::AsyncWrite( const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl ) { SaveMsg( "AsyncWrite (%s/%d)...\n", pFileName, nSrcBytes ); return g_pFileSystem->AsyncWrite( pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl ); }
void CSaveRestoreFileSystemPassthrough::Seek( FileHandle_t hFile, int pos, FileSystemSeek_t method ) { g_pFileSystem->Seek( hFile, pos, method ); }
unsigned int CSaveRestoreFileSystemPassthrough::Tell( FileHandle_t hFile ) { return g_pFileSystem->Tell( hFile ); }
unsigned int CSaveRestoreFileSystemPassthrough::Size( FileHandle_t hFile ) { return g_pFileSystem->Size( hFile ); }
unsigned int CSaveRestoreFileSystemPassthrough::Size( const char *pFileName, const char *pPathID ) { return g_pFileSystem->Size( pFileName, pPathID ); }
FSAsyncStatus_t CSaveRestoreFileSystemPassthrough::AsyncFinish( FSAsyncControl_t hControl, bool wait ) { return g_pFileSystem->AsyncFinish( hControl, wait ); }
void CSaveRestoreFileSystemPassthrough::AsyncRelease( FSAsyncControl_t hControl ) { g_pFileSystem->AsyncRelease( hControl ); }
FSAsyncStatus_t CSaveRestoreFileSystemPassthrough::AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl ) { return g_pFileSystem->AsyncAppend( pFileName, pSrc, nSrcBytes, bFreeMemory, pControl ); }
FSAsyncStatus_t CSaveRestoreFileSystemPassthrough::AsyncAppendFile(const char *pDestFileName, const char *pSrcFileName, FSAsyncControl_t *pControl ) { return g_pFileSystem->AsyncAppendFile( pDestFileName, pSrcFileName, pControl ); }
//-----------------------------------------------------------------------------
// Purpose: Copies the contents of the save directory into a single file
//-----------------------------------------------------------------------------
void CSaveRestoreFileSystemPassthrough::DirectoryCopy( const char *pPath, const char *pDestFileName, bool bIsXSave ) { SaveMsg( "DirectoryCopy....\n");
CUtlVector<filelistelem_t> list;
// force the writes to finish before trying to get the size/existence of a file
// @TODO: don't need this if retain sizes for files written earlier in process
SaveMsg( "DirectoryCopy: AsyncFinishAllWrites\n"); g_pFileSystem->AsyncFinishAllWrites();
// build the directory list
char basefindfn[ MAX_PATH ]; const char *findfn = Sys_FindFirstEx(pPath, MOD_DIR, basefindfn, sizeof( basefindfn ) ); while ( findfn ) { int index = list.AddToTail(); memset( list[index].szFileName, 0, sizeof(list[index].szFileName) ); Q_strncpy( list[index].szFileName, findfn, sizeof(list[index].szFileName) );
findfn = Sys_FindNext( basefindfn, sizeof( basefindfn ) ); } Sys_FindClose();
// write the list of files to the save file
char szName[MAX_PATH]; for ( int i = 0; i < list.Count(); i++ ) { if ( !bIsXSave ) { Q_snprintf( szName, sizeof( szName ), "%s%s", saverestore->GetSaveDir(), list[i].szFileName ); } else { PREPARE_XSAVE_FILENAME( XBX_GetPrimaryUserId(), szName ) "%s", list[i].szFileName ); }
Q_FixSlashes( szName );
int fileSize = g_pFileSystem->Size( szName ); if ( fileSize ) { Assert( sizeof(list[i].szFileName) == MAX_PATH );
SaveMsg( "DirectoryCopy: AsyncAppend %s, %s\n", szName, pDestFileName ); g_pFileSystem->AsyncAppend( pDestFileName, memcpy( new char[MAX_PATH], list[i].szFileName, MAX_PATH), MAX_PATH, true ); // Filename can only be as long as a map name + extension
g_pFileSystem->AsyncAppend( pDestFileName, new int(fileSize), sizeof(int), true ); g_pFileSystem->AsyncAppendFile( pDestFileName, szName ); } } }
//-----------------------------------------------------------------------------
// Purpose: Extracts all the files contained within pFile
//-----------------------------------------------------------------------------
bool CSaveRestoreFileSystemPassthrough::DirectoryExtract( FileHandle_t pFile, int fileCount, bool bIsXSave ) { int fileSize; FileHandle_t pCopy; char szName[ MAX_PATH ], fileName[ MAX_PATH ]; bool success = true;
for ( int i = 0; i < fileCount && success; i++ ) { // Filename can only be as long as a map name + extension
if ( g_pSaveRestoreFileSystem->Read( fileName, MAX_PATH, pFile ) != MAX_PATH ) return false;
if ( g_pSaveRestoreFileSystem->Read( &fileSize, sizeof(int), pFile ) != sizeof(int) ) return false;
if ( !fileSize ) return false;
if ( !bIsXSave ) { Q_snprintf( szName, sizeof( szName ), "%s%s", saverestore->GetSaveDir(), fileName ); } else { PREPARE_XSAVE_FILENAME( XBX_GetPrimaryUserId(), szName ) "%s", fileName ); }
Q_FixSlashes( szName ); pCopy = g_pSaveRestoreFileSystem->Open( szName, "wb", MOD_DIR ); if ( !pCopy ) return false; success = FileCopy( pCopy, pFile, fileSize ); g_pSaveRestoreFileSystem->Close( pCopy ); }
return success; }
//-----------------------------------------------------------------------------
// Purpose: returns the number of files in the specified filter
//-----------------------------------------------------------------------------
int CSaveRestoreFileSystemPassthrough::DirectoryCount( const char *pPath ) { int count = 0; const char *findfn = Sys_FindFirstEx( pPath, MOD_DIR, NULL, 0 );
while ( findfn != NULL ) { count++; findfn = Sys_FindNext(NULL, 0 ); } Sys_FindClose();
return count; }
//-----------------------------------------------------------------------------
// Purpose: Clears the save directory of all temporary files (*.hl)
//-----------------------------------------------------------------------------
void CSaveRestoreFileSystemPassthrough::DirectoryClear( const char *pPath, bool bIsXSave ) { char const *findfn; char szPath[ MAX_PATH ];
findfn = Sys_FindFirstEx( pPath, MOD_DIR, NULL, 0 ); while ( findfn != NULL ) { if ( !bIsXSave ) { Q_snprintf( szPath, sizeof( szPath ), "%s%s", saverestore->GetSaveDir(), findfn ); } else { PREPARE_XSAVE_FILENAME( XBX_GetPrimaryUserId(), szPath ) "%s", findfn ); }
// Delete the temporary save file
g_pFileSystem->RemoveFile( szPath, MOD_DIR );
// Any more save files
findfn = Sys_FindNext( NULL, 0 ); } Sys_FindClose(); }
void CSaveRestoreFileSystemPassthrough::AuditFiles( void ) { Msg("Not using save-in-memory path!\n" ); }
bool CSaveRestoreFileSystemPassthrough::LoadFileFromDisk( const char *pFilename ) { Msg("Not using save-in-memory path!\n" ); return true; }
bool CSaveRestoreFileSystemPassthrough::FileCopy( FileHandle_t pOutput, FileHandle_t pInput, int fileSize ) { // allocate a reasonably large file copy buffer, since otherwise write performance under steam suffers
char *buf = (char *)malloc(FILECOPYBUFSIZE); int size; int readSize; bool success = true;
while ( fileSize > 0 ) { if ( fileSize > FILECOPYBUFSIZE ) size = FILECOPYBUFSIZE; else size = fileSize; if ( ( readSize = g_pSaveRestoreFileSystem->Read( buf, size, pInput ) ) < size ) { Warning( "Unexpected end of file expanding save game\n" ); fileSize = 0; success = false; break; } g_pSaveRestoreFileSystem->Write( buf, readSize, pOutput );
fileSize -= size; }
free(buf); return success; }
|