Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

649 lines
22 KiB

  1. //===== Copyright � 1996-2011, Valve Corporation, All rights reserved. ======//
  2. #include "ps3_saveutil_v2.h"
  3. #include "vgui/ILocalize.h"
  4. #include "vstdlib/vstrtools.h"
  5. #include "memdbgon.h"
  6. //////////////////////////////////////////////////////////////////////////
  7. CPS3SaveRestoreAsyncStatus *g_pSaveUtilAsyncStatus = NULL;
  8. IPS3SaveSteamInfoProvider *g_pSteamInfoProvider = NULL;
  9. IThreadPool *g_pSaveUtilThreadPool = NULL;
  10. CSaveUtilVjobInstance g_saveUtilVjobInstance;
  11. static char g_chSaveUtilContainerName[64];
  12. char const *g_pszSaveUtilContainerName = g_chSaveUtilContainerName;
  13. CSaveUtilV2ContainerTOC g_SaveUtilV2TOC;
  14. uint32 g_SaveUtilV2TOCVersion;
  15. extern IVJobs * g_pVJobs;
  16. // this is our "SECURE FILE ID"
  17. static const char s_SaveUtilSecureFileId[CELL_SAVEDATA_SECUREFILEID_SIZE] =
  18. { 0xDD, 0xE3, 0x80, 0x72, 0xC7, 0x9F, 0xAF, 0x2A, 0x2B, 0x68, 0xAF, 0xC9, 0x6D, 0x6A, 0xED, 0xC1 } ;
  19. char const *g_pszSaveUtilSecureFileId = s_SaveUtilSecureFileId;
  20. uint64 g_uiSteamCloudCryptoKey = 0ull;
  21. ASSERT_INVARIANT( sizeof( CSaveUtilV2ContainerTOC::TocEntry_t ) < sizeof( CSaveUtilV2ContainerTOC::TocStorageReserved_t ) );
  22. //////////////////////////////////////////////////////////////////////////
  23. class CSaveUtilV2Job_Initialize : public ISaveUtilV2Job
  24. {
  25. public: // Job entry point
  26. virtual JobStatus_t DoExecute();
  27. public: // Caller passes data from main thread
  28. int m_nKBRequired;
  29. protected: // Our buffer for interacting with filesystem
  30. CUtlBuffer m_bufScratch;
  31. CSaveUtilV2ContainerTOC m_newTOC;
  32. CUtlVector< CellSaveDataFileStat > m_arrFilesInContainer;
  33. protected: // Stat callback
  34. virtual void DoDataStatCallback( SONY_SAVEUTIL_STAT_PARAMS );
  35. bool DoDataStat_ValidateFreeSpace( SONY_SAVEUTIL_STAT_PARAMS );
  36. void DoDataStat_NewContainer( SONY_SAVEUTIL_STAT_PARAMS );
  37. protected: // When Steam file exists we load it first
  38. CellSaveDataFileStat m_LoadSteamFileStat;
  39. void DoDataFile_LoadSteam( SONY_SAVEUTIL_FILE_PARAMS );
  40. protected: // When container exists we load TOC
  41. CellSaveDataFileStat m_LoadTocFileStat;
  42. void DoDataFile_LoadToc( SONY_SAVEUTIL_FILE_PARAMS );
  43. void DoDataFile_DisplayToc( SONY_SAVEUTIL_FILE_PARAMS );
  44. protected: // TOC post-processing
  45. bool PostProcessToc_DeletedFiles();
  46. bool PostProcessToc_Validate();
  47. protected: // When container is newly created we write initial data
  48. void DoDataFile_WriteEmptySteamFile( SONY_SAVEUTIL_FILE_PARAMS );
  49. void DoDataFile_WriteIcon0png( SONY_SAVEUTIL_FILE_PARAMS );
  50. void DoDataFile_WriteIcon1pam( SONY_SAVEUTIL_FILE_PARAMS );
  51. void DoDataFile_WritePic1png( SONY_SAVEUTIL_FILE_PARAMS );
  52. };
  53. //////////////////////////////////////////////////////////////////////////
  54. static void SaveUtilV2_InitAndClearSaveShadow()
  55. {
  56. char const *pszSaveDir = g_pPS3PathInfo->SaveShadowPath();
  57. g_pFullFileSystem->CreateDirHierarchy( pszSaveDir );
  58. // delete any files that are in the save dir already
  59. FileFindHandle_t handle;
  60. const char *pfname;
  61. char searchpath[255];
  62. V_snprintf( searchpath, sizeof(searchpath), "%s*", pszSaveDir );
  63. char deletepath[255];
  64. const int dirnamelen = V_strlen( pszSaveDir );
  65. Assert(dirnamelen < 255);
  66. memcpy(deletepath, pszSaveDir, dirnamelen);
  67. for ( pfname = g_pFullFileSystem->FindFirst( searchpath, &handle ) ;
  68. pfname ;
  69. pfname = g_pFullFileSystem->FindNext( handle ) )
  70. {
  71. V_strncpy( deletepath + dirnamelen, pfname, sizeof(deletepath) - dirnamelen );
  72. Msg( "Removing %s\n", deletepath );
  73. g_pFullFileSystem->RemoveFile( deletepath, NULL );
  74. }
  75. }
  76. void SaveUtilV2_Initialize( CPS3SaveRestoreAsyncStatus *pAsync, IPS3SaveSteamInfoProvider *pSteamInfoProvider, int nKBRequired )
  77. {
  78. if ( g_pSaveUtilThreadPool )
  79. return;
  80. // Initialize SPU jobs instance
  81. g_saveUtilVjobInstance.Init();
  82. // Indicate that we are running V2
  83. V_snprintf( g_chSaveUtilContainerName, 32, "%s-%s", g_pPS3PathInfo->GetWWMASTER_TitleID(), "PORTAL2-AUTOSAVE3" );
  84. SaveUtilV2_InitAndClearSaveShadow();
  85. // First of all start our thread pool
  86. ThreadPoolStartParams_t params;
  87. params.nThreads = 1;
  88. params.nStackSize = 64*1024;
  89. params.fDistribute = TRS_FALSE;
  90. g_pSaveUtilThreadPool = CreateNewThreadPool();
  91. g_pSaveUtilThreadPool->Start( params, "SaveUtilV2" );
  92. // Remember launch parameters
  93. g_pSteamInfoProvider = pSteamInfoProvider;
  94. // Start the job
  95. CSaveUtilV2Job_Initialize *pJob = new CSaveUtilV2Job_Initialize;
  96. pJob->m_nKBRequired = nKBRequired;
  97. SaveUtilV2_EnqueueJob( pAsync, pJob );
  98. }
  99. void SaveUtilV2_Shutdown()
  100. {
  101. if ( !g_pSaveUtilThreadPool )
  102. return;
  103. g_pSaveUtilThreadPool->Stop();
  104. DestroyThreadPool( g_pSaveUtilThreadPool );
  105. g_pSaveUtilThreadPool = NULL;
  106. // Shutdown jobs instance after thread pool has been
  107. // stopped which ensures that jobs were finished and released
  108. g_saveUtilVjobInstance.Shutdown();
  109. }
  110. bool SaveUtilV2_CanShutdown()
  111. {
  112. if ( !g_pSaveUtilThreadPool )
  113. return true;
  114. if ( g_pSaveUtilAsyncStatus )
  115. // job in progress
  116. return false;
  117. return true;
  118. }
  119. //////////////////////////////////////////////////////////////////////////
  120. JobStatus_t CSaveUtilV2Job_Initialize::DoExecute()
  121. {
  122. float flTimeStamp = Plat_FloatTime();
  123. Msg( "CSaveUtilV2Job_Initialize( %d KB ) @%.3f\n", m_nKBRequired, flTimeStamp );
  124. // Prepare data for calling saveutil (we cannot allocate memory in the callbacks!)
  125. m_bufScratch.EnsureCapacity( 5 * 1024 * 1024 ); // we always have 5 MB on startup
  126. m_newTOC.m_arrEntries.EnsureCapacity( VALVE_CONTAINER_COUNT );
  127. m_arrFilesInContainer.EnsureCapacity( VALVE_CONTAINER_COUNT );
  128. // Call saveutil
  129. int retv = cellSaveDataAutoSave2(
  130. CELL_SAVEDATA_VERSION_CURRENT,
  131. g_pszSaveUtilContainerName,
  132. CELL_SAVEDATA_ERRDIALOG_NONE,
  133. &m_SaveDirInfo,
  134. csDataStatCallback,
  135. csDataFileCallback,
  136. SYS_MEMORY_CONTAINER_ID_INVALID,
  137. this );
  138. // Set the global TOC as loaded
  139. {
  140. AUTO_LOCK( g_SaveUtilV2TOC.m_mtx );
  141. m_newTOC.CopyInto( &g_SaveUtilV2TOC );
  142. }
  143. // Job finished
  144. float flEndTimeStamp = Plat_FloatTime();
  145. Msg( "CSaveUtilV2Job_Initialize: cellSaveDataAutoSave2 returned %x @%.3f ( total time = %.3f sec )\n", retv, flEndTimeStamp, flEndTimeStamp - flTimeStamp );
  146. return SaveUtilV2_JobDone( retv );
  147. }
  148. void CSaveUtilV2Job_Initialize::DoDataStatCallback( SONY_SAVEUTIL_STAT_PARAMS )
  149. {
  150. Msg( "CSaveUtilV2Job_Initialize::DoDataStatCallback @%.3f\n", Plat_FloatTime() );
  151. Msg("\tnKBRequired %d\n", m_nKBRequired );
  152. Msg("\tisNewData %d\n", get->isNewData );
  153. Msg("\thddFreeSizeKB %d\n", get->hddFreeSizeKB);
  154. Msg("\tsizeKB %d\n", get->sizeKB);
  155. Msg("\tsysSizeKB %d\n", get->sysSizeKB);
  156. Msg("\tbind %d\n", get->bind);
  157. bool bCreateNew = false; // do we need to create a new container?
  158. if ( get->isNewData || get->bind != CELL_SAVEDATA_BINDSTAT_OK )
  159. {
  160. if ( get->isNewData )
  161. { // if the data is just absent, we can always make a new container.
  162. bCreateNew = true;
  163. }
  164. else if ( ( get->bind & ( CELL_SAVEDATA_BINDSTAT_ERR_NOACCOUNTID | CELL_SAVEDATA_BINDSTAT_ERR_LOCALOWNER ) ) == get->bind )
  165. {
  166. // this is actually owned by the current user; since the account
  167. // id will added on the next write, we can safely keep going.
  168. get->bind = 0;
  169. }
  170. else
  171. {
  172. // this is an ownership error
  173. set->reCreateMode = CELL_SAVEDATA_RECREATE_NO;
  174. g_pSaveUtilAsyncStatus->m_nSonyRetValue = CPS3SaveRestoreAsyncStatus::CELL_SAVEDATA_ERROR_WRONG_USER;
  175. cbResult->result = CELL_SAVEDATA_CBRESULT_ERR_INVALID;
  176. return;
  177. }
  178. }
  179. set->setParam = NULL; // don't edit the PARAM.SFO
  180. // Validate free space
  181. if ( !DoDataStat_ValidateFreeSpace( SONY_SAVEUTIL_PARAMS ) )
  182. return;
  183. // if there's a toc, read it.
  184. if ( !get->isNewData )
  185. {
  186. V_memset( &m_LoadSteamFileStat, 0, sizeof( m_LoadSteamFileStat ) );
  187. V_memset( &m_LoadTocFileStat, 0, sizeof( m_LoadTocFileStat ) );
  188. for ( int i = 0 ; i < get->fileListNum ; ++i )
  189. {
  190. // Icons and video have special filetypes, we are interested only in our data
  191. // our data has file type "securefile"
  192. if ( get->fileList[i].fileType != CELL_SAVEDATA_FILETYPE_SECUREFILE )
  193. continue;
  194. // Steam configuration file
  195. if ( !V_strcmp( get->fileList[i].fileName, VALVE_CONTAINER_FILE_STEAM ) )
  196. {
  197. Msg( "CSaveUtilV2Job_Initialize found Steam file: %u bytes\n", get->fileList[i].st_size );
  198. V_memcpy( &m_LoadSteamFileStat, &get->fileList[i], sizeof( m_LoadSteamFileStat ) );
  199. continue;
  200. }
  201. // Every file will have full TOC prepended, makes no sense
  202. // to have files in container that are smaller than required size
  203. if ( get->fileList[i].st_size < CSaveUtilV2ContainerTOC::kStorageCapacity )
  204. continue;
  205. // Remember the file as present in container
  206. m_arrFilesInContainer.AddToTail( get->fileList[i] );
  207. // Add this file for TOC discovery (the latest TOC will be at the start of the file with the alphanumeric-highest filename)
  208. Msg( "CSaveUtilV2Job_Initialize found file '%s', %u bytes\n", get->fileList[i].fileName, get->fileList[i].st_size );
  209. if ( !m_LoadTocFileStat.fileName[0] || // TOC filename not set yet
  210. ( V_strcmp( get->fileList[i].fileName, m_LoadTocFileStat.fileName ) > 0 ) ) // or bigger filename ( -> more recent file)
  211. {
  212. V_memcpy( &m_LoadTocFileStat, &get->fileList[i], sizeof( m_LoadTocFileStat ) );
  213. }
  214. }
  215. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_LoadSteam );
  216. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  217. return;
  218. }
  219. else if ( bCreateNew )
  220. {
  221. // Create a new container
  222. DoDataStat_NewContainer( SONY_SAVEUTIL_PARAMS );
  223. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_WriteEmptySteamFile );
  224. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  225. return;
  226. }
  227. // this means "okay, I'm done"
  228. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_LAST;
  229. }
  230. bool CSaveUtilV2Job_Initialize::DoDataStat_ValidateFreeSpace( SONY_SAVEUTIL_STAT_PARAMS )
  231. {
  232. // do we have enough space?
  233. // system overhead + caller max size ? HDD free space + current container file
  234. int numKbRequired = ( get->sysSizeKB + m_nKBRequired ) - ( get->hddFreeSizeKB + get->sizeKB );
  235. if ( numKbRequired > 0 )
  236. {
  237. // inadequate space.
  238. cbResult->result = CELL_SAVEDATA_CBRESULT_ERR_NOSPACE;
  239. g_pSaveUtilAsyncStatus->m_nSonyRetValue = CELL_SAVEDATA_ERROR_NOSPACE;
  240. cbResult->errNeedSizeKB = numKbRequired;
  241. g_pSaveUtilAsyncStatus->m_uiAdditionalDetails = numKbRequired;
  242. return false;
  243. }
  244. return true;
  245. }
  246. //////////////////////////////////////////////////////////////////////////
  247. void CSaveUtilV2Job_Initialize::DoDataStat_NewContainer( SONY_SAVEUTIL_STAT_PARAMS )
  248. {
  249. set->reCreateMode = CELL_SAVEDATA_RECREATE_YES_RESET_OWNER;
  250. get->bind = 0;
  251. // the convention for editing param.sfo is pointing at the struct in the get param, and then editing that. (jeez...)
  252. set->setParam = &get->getParam;
  253. /* Set parameters of PARAM.SFO */
  254. V_strncpy( set->setParam->title, g_pPS3PathInfo->GetParamSFO_Title(), CELL_SAVEDATA_SYSP_TITLE_SIZE );
  255. // the save game title
  256. wchar_t *szLocalizedSaveDataTitle = g_pLocalize->Find( "#CSGOPS3_SaveData" );
  257. if ( szLocalizedSaveDataTitle )
  258. {
  259. V_UnicodeToUTF8( szLocalizedSaveDataTitle, set->setParam->subTitle, CELL_SAVEDATA_SYSP_SUBTITLE_SIZE );
  260. }
  261. else // failsafe
  262. {
  263. V_strncpy( set->setParam->subTitle, "Counter Strike: Global Offensive" , CELL_SAVEDATA_SYSP_SUBTITLE_SIZE );
  264. }
  265. // the save game caption -- if missing, we just use an empty string here.
  266. szLocalizedSaveDataTitle = g_pLocalize->Find( "#CSGOPS3_SaveDetail" );
  267. if ( szLocalizedSaveDataTitle )
  268. {
  269. V_UnicodeToUTF8( szLocalizedSaveDataTitle, set->setParam->detail, CELL_SAVEDATA_SYSP_DETAIL_SIZE );
  270. }
  271. else
  272. {
  273. memset( set->setParam->detail, 0, CELL_SAVEDATA_SYSP_DETAIL_SIZE );
  274. }
  275. set->setParam->attribute = CELL_SAVEDATA_ATTR_NORMAL;
  276. // listparam is available to the application inside stat callback
  277. Q_memset( set->setParam->listParam, 0, CELL_SAVEDATA_SYSP_LPARAM_SIZE );
  278. memset( set->setParam->reserved, 0x0, sizeof(set->setParam->reserved) ); /* The reserved member must be zero-filled */
  279. memset( set->setParam->reserved2, 0x0, sizeof(set->setParam->reserved2) ); /* The reserved member must be zero-filled */
  280. }
  281. void CSaveUtilV2Job_Initialize::DoDataFile_WriteEmptySteamFile( SONY_SAVEUTIL_FILE_PARAMS )
  282. {
  283. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WriteEmptySteamFile @%.3f\n", Plat_FloatTime() );
  284. const static char szEmptyToc[] = "EMPTY";
  285. set->fileOperation = CELL_SAVEDATA_FILEOP_WRITE;
  286. set->fileBuf = const_cast<char *>(szEmptyToc);
  287. set->fileSize = set->fileBufSize = sizeof(szEmptyToc);
  288. set->fileName = VALVE_CONTAINER_FILE_STEAM;
  289. set->fileOffset = 0;
  290. set->fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE;
  291. memcpy( set->secureFileId, g_pszSaveUtilSecureFileId, CELL_SAVEDATA_SECUREFILEID_SIZE );
  292. set->reserved = NULL;
  293. // call back again to write icon
  294. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon0png );
  295. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  296. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WriteEmptySteamFile will write %d bytes...\n", set->fileSize );
  297. }
  298. void CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon0png( SONY_SAVEUTIL_FILE_PARAMS )
  299. {
  300. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon0png @%.3f\n", Plat_FloatTime() );
  301. // Load ICON0.PS3.PNG
  302. m_bufScratch.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  303. if ( !g_pFullFileSystem->ReadFile( "ps3/ICON0.PS3.PNG", "GAME", m_bufScratch ) )
  304. {
  305. DoDataFile_WriteIcon1pam( SONY_SAVEUTIL_PARAMS );
  306. return;
  307. }
  308. // Write it
  309. set->fileOperation = CELL_SAVEDATA_FILEOP_WRITE;
  310. set->fileBuf = m_bufScratch.Base();
  311. set->fileSize = set->fileBufSize = m_bufScratch.TellPut();
  312. set->fileOffset = 0;
  313. set->fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0;
  314. set->reserved = NULL;
  315. // call back again to write icon
  316. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon1pam );
  317. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  318. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon0png will write %d bytes...\n", set->fileSize );
  319. }
  320. void CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon1pam( SONY_SAVEUTIL_FILE_PARAMS )
  321. {
  322. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon1pam @%.3f\n", Plat_FloatTime() );
  323. // Load ICON1.PS3.PAM
  324. m_bufScratch.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  325. #if defined( CSTRIKE15 )
  326. // TODO($msmith): Remove this and put the PAM back in for CS:GO once it has been updated.
  327. if ( !g_pFullFileSystem->ReadFile( "ps3/not_found.PAM", "GAME", m_bufScratch ) )
  328. #else
  329. if ( !g_pFullFileSystem->ReadFile( "ps3/ICON1.PS3.PAM", "GAME", m_bufScratch ) )
  330. #endif
  331. {
  332. DoDataFile_WritePic1png( SONY_SAVEUTIL_PARAMS );
  333. return;
  334. }
  335. // Write it
  336. set->fileOperation = CELL_SAVEDATA_FILEOP_WRITE;
  337. set->fileBuf = m_bufScratch.Base();
  338. set->fileSize = set->fileBufSize = m_bufScratch.TellPut();
  339. set->fileOffset = 0;
  340. set->fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1;
  341. set->reserved = NULL;
  342. // call back again to write pic1
  343. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_WritePic1png );
  344. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  345. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WriteIcon1pam will write %d bytes...\n", set->fileSize );
  346. }
  347. void CSaveUtilV2Job_Initialize::DoDataFile_WritePic1png( SONY_SAVEUTIL_FILE_PARAMS )
  348. {
  349. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WritePic1png @%.3f\n", Plat_FloatTime() );
  350. // Load PIC1.PS3.PNG
  351. m_bufScratch.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  352. if ( !g_pFullFileSystem->ReadFile( "ps3/PIC1.PS3.PNG", "GAME", m_bufScratch ) )
  353. {
  354. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_LAST;
  355. return;
  356. }
  357. // Write it
  358. set->fileOperation = CELL_SAVEDATA_FILEOP_WRITE;
  359. set->fileBuf = m_bufScratch.Base();
  360. set->fileSize = set->fileBufSize = m_bufScratch.TellPut();
  361. set->fileOffset = 0;
  362. set->fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1;
  363. set->reserved = NULL;
  364. // final write
  365. SetDataFileCallbackFinalize();
  366. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  367. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_WritePic1png will write %d bytes...\n", set->fileSize );
  368. }
  369. //////////////////////////////////////////////////////////////////////////
  370. void CSaveUtilV2Job_Initialize::DoDataFile_LoadSteam( SONY_SAVEUTIL_FILE_PARAMS )
  371. {
  372. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_LoadSteam @%.3f\n", Plat_FloatTime() );
  373. // Check that Steam file is present
  374. if ( m_LoadSteamFileStat.st_size < 16 )
  375. {
  376. DoDataFile_LoadToc( SONY_SAVEUTIL_PARAMS );
  377. return;
  378. }
  379. // Read into Steam buffer
  380. CUtlBuffer *pBuffer = g_pSteamInfoProvider->GetInitialLoadBuffer();
  381. if ( !pBuffer || ( pBuffer->Size() < m_LoadSteamFileStat.st_size ) )
  382. {
  383. Warning( "ERROR: CSaveUtilV2Job_Initialize::DoDataFile_LoadSteam: cannot load Steam config (size %llu bytes)!\n", m_LoadSteamFileStat.st_size );
  384. DoDataFile_LoadToc( SONY_SAVEUTIL_PARAMS );
  385. return;
  386. }
  387. // Read Steam info file
  388. set->fileOperation = CELL_SAVEDATA_FILEOP_READ;
  389. set->fileBuf = pBuffer->Base();
  390. set->fileSize = m_LoadSteamFileStat.st_size;
  391. set->fileBufSize = pBuffer->Size();
  392. set->fileName = VALVE_CONTAINER_FILE_STEAM;
  393. set->fileOffset = 0;
  394. set->fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE;
  395. memcpy( set->secureFileId, g_pszSaveUtilSecureFileId, CELL_SAVEDATA_SECUREFILEID_SIZE );
  396. set->reserved = NULL;
  397. // Set the buffer size
  398. pBuffer->SeekPut( CUtlBuffer::SEEK_HEAD, set->fileSize );
  399. // final read
  400. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_LoadToc );
  401. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  402. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_LoadSteam will load %d bytes...\n", set->fileSize );
  403. }
  404. void CSaveUtilV2Job_Initialize::DoDataFile_LoadToc( SONY_SAVEUTIL_FILE_PARAMS )
  405. {
  406. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_LoadToc @%.3f\n", Plat_FloatTime() );
  407. if ( m_LoadTocFileStat.st_size < CSaveUtilV2ContainerTOC::kStorageCapacity )
  408. {
  409. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_LoadToc -- no TOC available.\n" );
  410. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_LAST;
  411. return;
  412. }
  413. // Load the TOC entry
  414. set->fileOperation = CELL_SAVEDATA_FILEOP_READ;
  415. set->fileBuf = m_bufScratch.Base();
  416. set->fileBufSize = set->fileSize = CSaveUtilV2ContainerTOC::kStorageCapacity;
  417. set->fileName = m_LoadTocFileStat.fileName;
  418. set->fileOffset = 0;
  419. set->fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE;
  420. memcpy( set->secureFileId, g_pszSaveUtilSecureFileId, CELL_SAVEDATA_SECUREFILEID_SIZE );
  421. set->reserved = NULL;
  422. m_bufScratch.SeekPut( CUtlBuffer::SEEK_HEAD, CSaveUtilV2ContainerTOC::kStorageCapacity );
  423. // keep reading
  424. SetDataFileCallback( &CSaveUtilV2Job_Initialize::DoDataFile_DisplayToc );
  425. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_NEXT;
  426. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_LoadToc will load %u bytes of TOC from '%s'...\n", set->fileSize, set->fileName );
  427. }
  428. void CSaveUtilV2Job_Initialize::DoDataFile_DisplayToc( SONY_SAVEUTIL_FILE_PARAMS )
  429. {
  430. Msg( "CSaveUtilV2Job_Initialize::DoDataFile_DisplayToc @%.3f\n", Plat_FloatTime() );
  431. m_newTOC.SerializeFromTocBuffer( m_bufScratch.Base() );
  432. bool bTocValidationResult = PostProcessToc_DeletedFiles();
  433. for ( int k = 0; k < m_newTOC.m_arrEntries.Count(); ++ k )
  434. {
  435. Msg( " %s %s %d/%d %s\n",
  436. m_newTOC.m_arrEntries[k].m_entry.m_chContainerName,
  437. m_newTOC.m_arrEntries[k].m_entry.m_chFile[0],
  438. m_newTOC.m_arrEntries[k].m_entry.m_numBytesFile[0],
  439. m_newTOC.m_arrEntries[k].m_entry.m_numBytesDecompressedFile[0],
  440. m_newTOC.m_arrEntries[k].m_entry.m_chComment
  441. );
  442. }
  443. Msg( " new save game will have index %u\n", m_newTOC.m_idxNewSaveName + 1 );
  444. Msg( " END OF TOC REPORT\n" );
  445. if ( !PostProcessToc_Validate() || !bTocValidationResult )
  446. {
  447. // TOC is not matching contents of the container!
  448. Warning( " ERROR: TOC DOES NOT MATCH SAVE CONTAINER!\n" );
  449. g_pSaveUtilAsyncStatus->m_nSonyRetValue = CELL_SAVEDATA_CBRESULT_ERR_BROKEN;
  450. cbResult->result = CELL_SAVEDATA_CBRESULT_ERR_BROKEN;
  451. }
  452. else
  453. {
  454. cbResult->result = CELL_SAVEDATA_CBRESULT_OK_LAST;
  455. }
  456. }
  457. bool CSaveUtilV2Job_Initialize::PostProcessToc_DeletedFiles()
  458. {
  459. // Iterate over TOC and remove entries that were deleted from container previously
  460. bool bTocAndContainerValid = true;
  461. for ( int k = m_newTOC.m_arrEntries.Count(); k --> 0; )
  462. {
  463. bool bFoundInContainer = false;
  464. int jc = 0;
  465. for ( ; jc < m_arrFilesInContainer.Count(); ++ jc )
  466. {
  467. if ( !V_strcmp( m_newTOC.m_arrEntries[k].m_entry.m_chContainerName, m_arrFilesInContainer[jc].fileName ) )
  468. {
  469. bFoundInContainer = true;
  470. break;
  471. }
  472. }
  473. if ( !bFoundInContainer )
  474. {
  475. Msg( "CSaveUtilV2Job_Initialize::PostProcessToc_DeletedFiles discovered deleted file '%s'\n", m_newTOC.m_arrEntries[k].m_entry.m_chContainerName );
  476. m_newTOC.m_arrEntries.Remove( k );
  477. }
  478. else
  479. {
  480. // Make sure the TOC information matches container stat information
  481. int nExpectedSize = CSaveUtilV2ContainerTOC::kStorageCapacity;
  482. for ( int ipart = 0; ipart < VALVE_CONTAINER_FPARTS; ++ ipart )
  483. nExpectedSize += m_newTOC.m_arrEntries[k].m_entry.m_numBytesFile[ipart];
  484. if ( m_arrFilesInContainer[jc].st_size != nExpectedSize )
  485. {
  486. Msg( "CSaveUtilV2Job_Initialize::PostProcessToc_DeletedFiles discovered size inconsistency in '%s' (TOC size = %d; Container size = %llu)\n",
  487. m_newTOC.m_arrEntries[k].m_entry.m_chContainerName, nExpectedSize, m_arrFilesInContainer[jc].st_size );
  488. bTocAndContainerValid = false;
  489. }
  490. }
  491. }
  492. return bTocAndContainerValid;
  493. }
  494. bool CSaveUtilV2Job_Initialize::PostProcessToc_Validate()
  495. {
  496. // Iterate over TOC and make sure every container file is in TOC
  497. for ( int jc = m_arrFilesInContainer.Count(); jc --> 0; )
  498. {
  499. bool bFoundInTOC = false;
  500. for ( int k = 0; k < m_newTOC.m_arrEntries.Count(); ++ k )
  501. {
  502. if ( !V_strcmp( m_newTOC.m_arrEntries[k].m_entry.m_chContainerName, m_arrFilesInContainer[jc].fileName ) )
  503. {
  504. bFoundInTOC = true;
  505. break;
  506. }
  507. }
  508. if ( bFoundInTOC )
  509. {
  510. m_arrFilesInContainer.Remove( jc );
  511. }
  512. else
  513. {
  514. Msg( "CSaveUtilV2Job_Initialize::PostProcessToc_Validate discovered extra file '%s'\n", m_arrFilesInContainer[jc].fileName );
  515. }
  516. }
  517. // We shouldn't have any extra unaccounted files in the container
  518. return ( !m_arrFilesInContainer.Count() );
  519. }
  520. void CSaveUtilVjobInstance::Init()
  521. {
  522. g_pVJobs->Register( this );
  523. }
  524. void CSaveUtilVjobInstance::Shutdown()
  525. {
  526. g_pVJobs->Unregister( this );
  527. }