//===== Copyright © 1996-2011, Valve Corporation, All rights reserved. ======// #include "ps3_saveutil_v2.h" #include "fmtstr.h" #include "checksum_crc.h" #include "memdbgon.h" CON_COMMAND( ps3_saveutil_showtoc, "" ) { AUTO_LOCK( g_SaveUtilV2TOC.m_mtx ); int numTocEntries = g_SaveUtilV2TOC.m_arrEntries.Count(); Msg( "--------- SAVEUTILTOC -----------\n" ); for ( int k = 0; k < numTocEntries; ++ k ) { CSaveUtilV2ContainerTOC::TocEntry_t &e = g_SaveUtilV2TOC.m_arrEntries[k].m_entry; Msg( "%02d : %016llx %s\n" " '%s' %u/%u\n" " '%s' %u/%u\n" " %s\n", k + 1, e.m_timeModification, e.m_chContainerName, e.m_chFile[0], e.m_numBytesFile[0], e.m_numBytesDecompressedFile[0], e.m_chFile[1], e.m_numBytesFile[1], e.m_numBytesDecompressedFile[1], e.m_chComment ); } Msg( "--------- %02d ENTRIES -----------\n", numTocEntries ); } void SaveUtilV2_GetFileInfoSync( CUtlVector< IPS3SaveRestoreToUI::PS3SaveGameInfo_t > &saveGameInfos, bool bFindAll ) { // This can be called after starting a save op but before it completes, so this will return old data in that case. // The caller should be aware that if SaveUtil is busy then it can check the operation TAG and know what is in // progress and whether it can affect the TOC after it's finished. // Currently only UI queries the TOC and ensures that writes of savegames are completed before queries. AUTO_LOCK( g_SaveUtilV2TOC.m_mtx ); if ( !g_SaveUtilV2TOC.m_arrEntries.Count() ) { saveGameInfos.RemoveAll(); return; } int numTocEntries = bFindAll ? g_SaveUtilV2TOC.m_arrEntries.Count() : 1; saveGameInfos.SetCount( numTocEntries ); for ( int k = 0; k < numTocEntries; ++ k ) { saveGameInfos[k].m_InternalName = CFmtStr( "!%s", g_SaveUtilV2TOC.m_arrEntries[k].m_entry.m_chContainerName ); saveGameInfos[k].m_Comment = g_SaveUtilV2TOC.m_arrEntries[k].m_entry.m_chComment; saveGameInfos[k].m_Filename = g_SaveUtilV2TOC.m_arrEntries[k].m_entry.m_chFile[0]; saveGameInfos[k].m_ScreenshotFilename = g_SaveUtilV2TOC.m_arrEntries[k].m_entry.m_chFile[1]; saveGameInfos[k].m_nFileTime = g_SaveUtilV2TOC.m_arrEntries[k].m_entry.m_timeModification; } } ////////////////////////////////////////////////////////////////////////// bool SaveUtilV2_CanStartJob() { bool bResult = ( g_pSaveUtilThreadPool && !g_pSaveUtilAsyncStatus ); if ( !bResult ) { Warning( "SaveUtilV2_CanStartJob : cannot start job now! Invalid usage!\n" ); Assert( 0 ); } return bResult; } void SaveUtilV2_EnqueueJob( CPS3SaveRestoreAsyncStatus *pAsync, ISaveUtilV2Job *pJob ) { if ( g_pSaveUtilAsyncStatus ) Error( "SaveUtilV2_EnqueueJob while job already running ( %p running, %p attempted )!\n", g_pSaveUtilAsyncStatus, pAsync ); g_pSaveUtilAsyncStatus = pAsync; // Prepare for saveutil operation const int numContainers = VALVE_CONTAINER_COUNT; pJob->m_bufSaveDirList.EnsureCapacity( numContainers * MAX( sizeof( CellSaveDataFileStat ), sizeof( CellSaveDataDirList ) ) ); // Prepare save dir info memset( &pJob->m_SaveDirInfo, 0, sizeof(CellSaveDataSetBuf) ); pJob->m_SaveDirInfo.dirListMax = numContainers; pJob->m_SaveDirInfo.fileListMax = numContainers; pJob->m_SaveDirInfo.bufSize = pJob->m_bufSaveDirList.Size(); pJob->m_SaveDirInfo.buf = pJob->m_bufSaveDirList.Base(); // Mark the job as pending g_pSaveUtilAsyncStatus->m_nSonyRetValue = CELL_SAVEDATA_ERROR_NOTSUPPORTED; g_pSaveUtilAsyncStatus->m_bDone = 0; // Let's notify the file system that a save is starting, that way the file system can try to reduce HDD accesses and use BluRay instead g_pFullFileSystem->OnSaveStateChanged( true ); // Add the job to thread pool pJob->SetFlags( JF_SERIAL | JF_QUEUE ); g_pSaveUtilThreadPool->AddJob( pJob ); pJob->Release(); } JobStatus_t SaveUtilV2_JobDone( int nErrorCode ) { // Let's notify the file system that a save is finished, that way the file system can restart using the HDD g_pFullFileSystem->OnSaveStateChanged( false ); // Set the job error code and set that the job is done if ( nErrorCode != CELL_SAVEDATA_ERROR_CBRESULT ) g_pSaveUtilAsyncStatus->m_nSonyRetValue = nErrorCode; else if ( g_pSaveUtilAsyncStatus->m_nSonyRetValue >= 0 ) g_pSaveUtilAsyncStatus->m_nSonyRetValue = CELL_SAVEDATA_ERROR_FAILURE; CPS3SaveRestoreAsyncStatus *pAsync = g_pSaveUtilAsyncStatus; g_pSaveUtilAsyncStatus = NULL; pAsync->m_bDone = 1; return JOB_OK; } uint32 SaveUtilV2_ComputeBufferHash( void const *pvData, uint32 numBytes ) { return CRC32_ProcessSingleBuffer( pvData, numBytes ); } ////////////////////////////////////////////////////////////////////////// void ISaveUtilV2Job::csDataStatCallback( SONY_SAVEUTIL_STAT_PARAMS ) { ISaveUtilV2Job *pSelf = static_cast( cbResult->userdata ); pSelf->DoDataStatCallback( SONY_SAVEUTIL_PARAMS ); } void ISaveUtilV2Job::csDataFileCallback( SONY_SAVEUTIL_FILE_PARAMS ) { ISaveUtilV2Job *pSelf = static_cast( cbResult->userdata ); if ( pSelf->m_pfnDoDataFileCallback ) { (pSelf->*(pSelf->m_pfnDoDataFileCallback))( SONY_SAVEUTIL_PARAMS ); } else { Msg( "ISaveUtilV2Job::csDataFileCallback finalizing save operation @%.3f\n", Plat_FloatTime() ); cbResult->result = CELL_SAVEDATA_CBRESULT_OK_LAST; } } ////////////////////////////////////////////////////////////////////////// void CSaveUtilV2ContainerTOC::SerializeIntoTocBuffer( void *pvBuffer ) { uint32 *pui32 = (uint32*) pvBuffer; *( pui32 ++ ) = m_idxNewSaveName; *( pui32 ++ ) = m_arrEntries.Count(); V_memcpy( pui32, m_arrEntries.Base(), m_arrEntries.Count() * sizeof( TocStorageReserved_t ) ); } void CSaveUtilV2ContainerTOC::SerializeFromTocBuffer( void *pvBuffer ) { uint32 *pui32 = (uint32*) pvBuffer; m_idxNewSaveName = *( pui32 ++ ); uint32 uiEntriesCount = *( pui32 ++ ); uiEntriesCount = MIN( uiEntriesCount, VALVE_CONTAINER_COUNT ); m_arrEntries.AddMultipleToTail( uiEntriesCount, reinterpret_cast< TocStorageReserved_t * >( pui32 ) ); } void CSaveUtilV2ContainerTOC::CopyInto( CSaveUtilV2ContainerTOC *pOther ) { pOther->m_idxNewSaveName = m_idxNewSaveName; pOther->m_arrEntries.RemoveAll(); pOther->m_arrEntries.AddMultipleToTail( m_arrEntries.Count(), m_arrEntries.Base() ); } int CSaveUtilV2ContainerTOC::FindByEmbeddedFileName( char const *szFilename, int *pnPartIndex ) { for ( int k = 0; k < m_arrEntries.Count(); ++ k ) { if ( szFilename[0] == '!' ) { if ( V_stricmp( m_arrEntries[k].m_entry.m_chContainerName, szFilename + 1 ) ) continue; if ( pnPartIndex ) *pnPartIndex = 0; return k; } for ( int iPart = 0; iPart < VALVE_CONTAINER_FPARTS; ++ iPart ) { if ( !V_stricmp( m_arrEntries[k].m_entry.m_chFile[iPart], szFilename ) ) { if ( pnPartIndex ) *pnPartIndex = iPart; return k; } } } if ( pnPartIndex ) *pnPartIndex = -1; return -1; }