299 lines
10 KiB
C++
299 lines
10 KiB
C++
//===== Copyright © 1996-2011, Valve Corporation, All rights reserved. ======//
|
|
|
|
#include "ps3_saveutil_v2.h"
|
|
#include "memdbgon.h"
|
|
#include <vjobs/jobparams_shared.h>
|
|
#include <vjobs/root.h>
|
|
#include <ps3/vjobutils.h>
|
|
|
|
|
|
class CSaveUtilV2Job_Load : public ISaveUtilV2Job
|
|
{
|
|
public: // Job entry point
|
|
virtual JobStatus_t DoExecute();
|
|
|
|
public: // Data passed from main thread
|
|
char m_chFileName[VALVE_CONTAINER_FILENAME_LEN];
|
|
char m_chFullPathOut[MAX_PATH];
|
|
bool m_bForCloud;
|
|
|
|
public: // Data resolved from the main thread
|
|
CSaveUtilV2ContainerTOC::TocEntry_t *m_pTocEntry;
|
|
int m_nSubFileIndex;
|
|
job_zlibinflate::JobDescriptor_t * m_pJobInflate;
|
|
|
|
protected: // Data used for loading file contents
|
|
CUtlBuffer m_bufScratch;
|
|
int WriteFile( char const *szFile );
|
|
|
|
protected: // Stat callback
|
|
virtual void DoDataStatCallback( SONY_SAVEUTIL_STAT_PARAMS );
|
|
|
|
protected: // Load and write to disk
|
|
void DoDataFile_LoadToBuffer( SONY_SAVEUTIL_FILE_PARAMS );
|
|
void DoDataFile_WriteToDisk( SONY_SAVEUTIL_FILE_PARAMS );
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void SaveUtilV2_Load( CPS3SaveRestoreAsyncStatus *pAsync, const char *pFilename, const char *pDestFullPath )
|
|
{
|
|
if ( !SaveUtilV2_CanStartJob() )
|
|
return;
|
|
|
|
// Find the file that the caller wants
|
|
int nSubFileIndex = -1;
|
|
int k = g_SaveUtilV2TOC.FindByEmbeddedFileName( pFilename, &nSubFileIndex );
|
|
if ( ( nSubFileIndex < 0 ) || ( k < 0 ) || ( k >= g_SaveUtilV2TOC.m_arrEntries.Count() ) )
|
|
{
|
|
pAsync->m_nSonyRetValue = CELL_SAVEDATA_ERROR_FAILURE;
|
|
pAsync->m_bDone = 1;
|
|
Warning( "ERROR: SaveUtilV2_Load: attempted to load file '%s' which doesn't exist in container!\n", pFilename );
|
|
return;
|
|
}
|
|
|
|
// Start the job
|
|
CSaveUtilV2Job_Load *pJob = new CSaveUtilV2Job_Load;
|
|
V_strncpy( pJob->m_chFileName, pFilename, sizeof( pJob->m_chFileName ) );
|
|
|
|
pJob->m_bForCloud = false;
|
|
switch ( pDestFullPath[0] )
|
|
{
|
|
case '@':
|
|
pJob->m_bForCloud = true;
|
|
++ pDestFullPath;
|
|
break;
|
|
}
|
|
|
|
V_strncpy( pJob->m_chFullPathOut, pDestFullPath, sizeof( pJob->m_chFullPathOut ) );
|
|
pJob->m_pTocEntry = &g_SaveUtilV2TOC.m_arrEntries[k].m_entry;
|
|
pJob->m_nSubFileIndex = nSubFileIndex;
|
|
|
|
SaveUtilV2_EnqueueJob( pAsync, pJob );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
JobStatus_t CSaveUtilV2Job_Load::DoExecute()
|
|
{
|
|
float flTimeStamp = Plat_FloatTime();
|
|
Msg( "CSaveUtilV2Job_Load @%.3f\n", flTimeStamp );
|
|
|
|
// Allocate required buffer
|
|
if ( m_bForCloud )
|
|
{
|
|
int numBytesRequired = sizeof( CSaveUtilV2ContainerTOC::TocStorageReserved_t );
|
|
for ( int iPart = 0; iPart < VALVE_CONTAINER_FPARTS; ++ iPart )
|
|
numBytesRequired += m_pTocEntry->m_numBytesFile[iPart];
|
|
m_bufScratch.EnsureCapacity( numBytesRequired );
|
|
}
|
|
else
|
|
{
|
|
m_bufScratch.EnsureCapacity( m_pTocEntry->m_numBytesFile[m_nSubFileIndex] + m_pTocEntry->m_numBytesDecompressedFile[m_nSubFileIndex] );
|
|
}
|
|
|
|
m_pJobInflate = NewJob128( *g_saveUtilVjobInstance.m_pRoot->m_pJobZlibInflate );
|
|
m_pJobInflate->header.sizeScratch = ( 16 * 1024 ) / 16 ;
|
|
|
|
// Call saveutil
|
|
int retv = cellSaveDataAutoSave2(
|
|
CELL_SAVEDATA_VERSION_CURRENT,
|
|
g_pszSaveUtilContainerName,
|
|
CELL_SAVEDATA_ERRDIALOG_NONE,
|
|
&m_SaveDirInfo,
|
|
csDataStatCallback,
|
|
csDataFileCallback,
|
|
SYS_MEMORY_CONTAINER_ID_INVALID,
|
|
this );
|
|
|
|
DeleteJob( m_pJobInflate );
|
|
|
|
float flEndTimeStamp = Plat_FloatTime();
|
|
Msg( "CSaveUtilV2Job_Load: cellSaveDataAutoSave2 returned %x @%.3f ( total time = %.3f sec )\n", retv, flEndTimeStamp, flEndTimeStamp - flTimeStamp );
|
|
|
|
return SaveUtilV2_JobDone( retv );
|
|
}
|
|
|
|
void CSaveUtilV2Job_Load::DoDataStatCallback( SONY_SAVEUTIL_STAT_PARAMS )
|
|
{
|
|
Msg( "CSaveUtilV2Job_Load::DoDataStatCallback @%.3f\n", Plat_FloatTime() );
|
|
|
|
SetDataFileCallback( &CSaveUtilV2Job_Load::DoDataFile_LoadToBuffer );
|
|
cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
|
|
}
|
|
|
|
void CSaveUtilV2Job_Load::DoDataFile_LoadToBuffer( SONY_SAVEUTIL_FILE_PARAMS )
|
|
{
|
|
Msg( "CSaveUtilV2Job_Load::DoDataFile_LoadToBuffer @%.3f\n", Plat_FloatTime() );
|
|
|
|
// Load the file contents
|
|
set->fileOperation = CELL_SAVEDATA_FILEOP_READ;
|
|
set->fileName = m_pTocEntry->m_chContainerName;
|
|
set->fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE;
|
|
memcpy( set->secureFileId, g_pszSaveUtilSecureFileId, CELL_SAVEDATA_SECUREFILEID_SIZE );
|
|
set->reserved = NULL;
|
|
|
|
set->fileOffset = CSaveUtilV2ContainerTOC::kStorageCapacity;
|
|
if ( m_bForCloud )
|
|
{
|
|
set->fileSize = 0;
|
|
for ( int iPart = 0; iPart < VALVE_CONTAINER_FPARTS; ++ iPart )
|
|
set->fileSize += m_pTocEntry->m_numBytesFile[iPart];
|
|
m_bufScratch.SeekPut( CUtlBuffer::SEEK_HEAD, sizeof( CSaveUtilV2ContainerTOC::TocStorageReserved_t ) + set->fileSize );
|
|
set->fileBuf = ( ( uint8 * ) m_bufScratch.Base() ) + sizeof( CSaveUtilV2ContainerTOC::TocStorageReserved_t );
|
|
set->fileBufSize = m_bufScratch.Size() - sizeof( CSaveUtilV2ContainerTOC::TocStorageReserved_t );
|
|
}
|
|
else
|
|
{
|
|
for ( int k = 0; k < m_nSubFileIndex; ++ k )
|
|
set->fileOffset += m_pTocEntry->m_numBytesFile[k];
|
|
set->fileSize = m_pTocEntry->m_numBytesFile[m_nSubFileIndex];
|
|
m_bufScratch.SeekPut( CUtlBuffer::SEEK_HEAD, set->fileSize );
|
|
set->fileBuf = m_bufScratch.Base();
|
|
set->fileBufSize = m_bufScratch.Size();
|
|
}
|
|
|
|
// keep reading
|
|
SetDataFileCallback( &CSaveUtilV2Job_Load::DoDataFile_WriteToDisk );
|
|
cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
|
|
|
|
Msg( "CSaveUtilV2Job_Load::DoDataFile_LoadToBuffer will load %u bytes of '%s' from '%s'...\n", set->fileSize, m_chFileName, set->fileName );
|
|
}
|
|
|
|
void CSaveUtilV2Job_Load::DoDataFile_WriteToDisk( SONY_SAVEUTIL_FILE_PARAMS )
|
|
{
|
|
Msg( "CSaveUtilV2Job_Load::DoDataFile_WriteToDisk '%s' @%.3f\n", m_chFileName, Plat_FloatTime() );
|
|
|
|
int ret = WriteFile( m_chFullPathOut );
|
|
if ( ret < 0 )
|
|
{
|
|
Msg( "ERROR: CSaveUtilV2Job_Load::DoDataFile_WriteToDisk failed to write file to disk!\n" );
|
|
g_pSaveUtilAsyncStatus->m_nSonyRetValue = CELL_SAVEDATA_ERROR_FAILURE;
|
|
cbResult->result = CELL_SAVEDATA_CBRESULT_ERR_FAILURE;
|
|
return;
|
|
}
|
|
|
|
cbResult->result = CELL_SAVEDATA_CBRESULT_OK_LAST;
|
|
}
|
|
|
|
int CSaveUtilV2Job_Load::WriteFile( char const *szFile )
|
|
{
|
|
if ( !szFile || !*szFile )
|
|
return 0;
|
|
|
|
float flTimeStamp = Plat_FloatTime();
|
|
Msg( "CSaveUtilV2Job_Load::WriteFile : %s @%.3f\n", szFile, flTimeStamp );
|
|
|
|
unsigned char *pWriteData = ( unsigned char * ) m_bufScratch.Base();
|
|
unsigned int numBytesWrite = m_pTocEntry->m_numBytesFile[m_nSubFileIndex]; // the compressed size
|
|
if ( m_bForCloud )
|
|
{
|
|
numBytesWrite = m_bufScratch.TellPut();
|
|
V_memcpy( pWriteData, m_pTocEntry, sizeof( CSaveUtilV2ContainerTOC::TocStorageReserved_t ) );
|
|
|
|
//
|
|
// Signature
|
|
//
|
|
|
|
// Generate sult into filename field
|
|
CSaveUtilV2ContainerTOC::TocEntry_t *pSignature = ( CSaveUtilV2ContainerTOC::TocEntry_t * ) pWriteData;
|
|
for ( int isult = 0; isult < sizeof( pSignature->m_chFile[0] ); ++ isult )
|
|
pSignature->m_chFile[0][isult] = ( 1 + rand() ) % 220;
|
|
|
|
// Put the version of our save header
|
|
V_memset( pSignature->m_chContainerName, 0, sizeof( pSignature->m_chContainerName ) );
|
|
pSignature->m_chContainerName[0] = 'S';
|
|
pSignature->m_chContainerName[1] = 'A';
|
|
pSignature->m_chContainerName[2] = 'V';
|
|
pSignature->m_chContainerName[3] = '1';
|
|
|
|
// Temporarily put our cryptokey in place of hash
|
|
V_memcpy( pWriteData + 8, &g_uiSteamCloudCryptoKey, sizeof( g_uiSteamCloudCryptoKey ) );
|
|
uint32 uiHash = SaveUtilV2_ComputeBufferHash( pWriteData, numBytesWrite );
|
|
|
|
// Store the hash
|
|
for ( int isult = 0; isult < sizeof( g_uiSteamCloudCryptoKey ) - sizeof( uiHash ); ++ isult )
|
|
pWriteData[8 + isult] = ( 1 + rand() ) % 220;
|
|
V_memcpy( pWriteData + 8 + sizeof( g_uiSteamCloudCryptoKey ) - sizeof( uiHash ), &uiHash, sizeof( uiHash ) );
|
|
}
|
|
else if ( m_pTocEntry->m_numBytesDecompressedFile[m_nSubFileIndex] )
|
|
{
|
|
// The file is actually compressed
|
|
|
|
if( g_saveUtilVjobInstance.m_pRoot )
|
|
{
|
|
double flStartInflateJob = Plat_FloatTime();
|
|
|
|
job_zlibinflate::JobParams_t * pJobParams = job_zlibinflate::GetJobParams( m_pJobInflate );
|
|
|
|
pJobParams->m_eaUncompressedOutput = pWriteData + numBytesWrite;
|
|
pJobParams->m_eaCompressed = pWriteData;
|
|
pJobParams->m_nCompressedSize = numBytesWrite;
|
|
pJobParams->m_nExpectedUncompressedSize = m_pTocEntry->m_numBytesDecompressedFile[m_nSubFileIndex];
|
|
|
|
int nError = g_saveUtilVjobInstance.m_pRoot->m_queuePortSound.pushJob( &m_pJobInflate->header, sizeof( *m_pJobInflate ), 0, CELL_SPURS_JOBQUEUE_FLAG_SYNC_JOB );
|
|
if( nError != CELL_OK )
|
|
{
|
|
Warning("job_zlibinflate failed to push through port, error 0x%X\n", nError );
|
|
return -1;
|
|
}
|
|
|
|
while( !pJobParams->IsDone() )
|
|
{
|
|
ThreadSleep( 1 );
|
|
}
|
|
|
|
double flEndInflateJob = Plat_FloatTime();
|
|
|
|
if( pJobParams->m_nError != 0 )
|
|
{
|
|
Warning( "CSaveUtilV2Job_Load::WriteFile failed to uncompress!\n" );
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
Msg( "job_zlibInflate took %.3f sec : %u -> %u KiB (%.2f MiB/s)\n", flEndInflateJob - flStartInflateJob, pJobParams->m_nCompressedSize/1024, pJobParams->m_nExpectedUncompressedSize/1024, pJobParams->m_nExpectedUncompressedSize / ( 1024 * 1024 * ( flEndInflateJob - flStartInflateJob ) ) );
|
|
|
|
pWriteData += numBytesWrite;
|
|
numBytesWrite = m_pTocEntry->m_numBytesDecompressedFile[m_nSubFileIndex];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int ret;
|
|
int fd;
|
|
|
|
ret = cellFsOpen( szFile, CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_WRONLY, &fd, NULL, 0 );
|
|
if ( ret < 0 )
|
|
{
|
|
Msg( "ERROR: CSaveUtilV2Job_Load::DoDataFile_WriteToDisk : %s : cellFsOpen failed : %d\n", szFile, ret );
|
|
return ret;
|
|
}
|
|
|
|
uint64_t numBytesActuallyWritten = 0;
|
|
ret = cellFsWrite( fd, pWriteData, numBytesWrite, &numBytesActuallyWritten );
|
|
cellFsClose( fd );
|
|
if ( ret < 0 )
|
|
{
|
|
Msg( "ERROR: CSaveUtilV2Job_Load::DoDataFile_WriteToDisk : %s : cellFsWrite failed : %d\n", szFile, ret );
|
|
return ret;
|
|
}
|
|
if ( numBytesActuallyWritten != numBytesWrite )
|
|
{
|
|
Msg( "ERROR: CSaveUtilV2Job_Load::DoDataFile_WriteToDisk : %s : cellFsWrite wrote incorrect file : %ull bytes written, %d bytes expected\n",
|
|
szFile, numBytesActuallyWritten, numBytesWrite );
|
|
return -1;
|
|
}
|
|
|
|
float flEndTimeStamp = Plat_FloatTime();
|
|
Msg( "CSaveUtilV2Job_Load::WriteFile finished writing %s @%.3f (%.3f sec)\n", szFile, flEndTimeStamp, flEndTimeStamp - flTimeStamp );
|
|
return 0;
|
|
}
|
|
|
|
|
|
|