Team Fortress 2 Source Code as on 22/4/2020
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.

596 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "basefilesystem.h"
  7. #include "tier0/vprof.h"
  8. // NOTE: This has to be the last file included!
  9. #include "tier0/memdbgon.h"
  10. #if !defined( DEDICATED )
  11. #ifdef SUPPORT_PACKED_STORE
  12. unsigned ThreadStubProcessMD5Requests( void *pParam )
  13. {
  14. return ((CFileTracker2 *)pParam)->ThreadedProcessMD5Requests();
  15. }
  16. //-----------------------------------------------------------------------------
  17. // ThreadedProcessMD5Requests
  18. // Calculate the MD5s of all the blocks submitted to us
  19. //-----------------------------------------------------------------------------
  20. unsigned CFileTracker2::ThreadedProcessMD5Requests()
  21. {
  22. ThreadSetDebugName( "ProcessMD5Requests" );
  23. while ( m_bThreadShouldRun )
  24. {
  25. StuffToMD5_t stuff;
  26. while ( m_PendingJobs.PopItem( &stuff ) )
  27. {
  28. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  29. MD5Context_t ctx;
  30. memset( &ctx, 0, sizeof(MD5Context_t) );
  31. MD5Init( &ctx );
  32. MD5Update( &ctx, stuff.m_pubBuffer, stuff.m_cubBuffer );
  33. MD5Final( stuff.m_md5Value.bits, &ctx);
  34. {
  35. // update the FileTracker MD5 database
  36. AUTO_LOCK( m_Mutex );
  37. TrackedVPKFile_t &trackedVPKFile = m_treeTrackedVPKFiles[ stuff.m_idxTrackedVPKFile ];
  38. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ trackedVPKFile.m_idxAllOpenedFiles ];
  39. memcpy( trackedfile.m_filehashFinal.m_md5contents.bits, stuff.m_md5Value.bits, sizeof( trackedfile.m_filehashFinal.m_md5contents.bits ) );
  40. trackedfile.m_filehashFinal.m_crcIOSequence = stuff.m_cubBuffer;
  41. trackedfile.m_filehashFinal.m_cbFileLen = stuff.m_cubBuffer;
  42. trackedfile.m_filehashFinal.m_eFileHashType = FileHash_t::k_EFileHashTypeEntireFile;
  43. trackedfile.m_filehashFinal.m_nPackFileNumber = trackedVPKFile.m_nPackFileNumber;
  44. trackedfile.m_filehashFinal.m_PackFileID = trackedVPKFile.m_PackFileID;
  45. }
  46. m_CompletedJobs.PushItem( stuff );
  47. m_threadEventWorkCompleted.Set();
  48. }
  49. {
  50. tmZone( TELEMETRY_LEVEL0, TMZF_IDLE, "m_threadEventWorkToDo" );
  51. m_threadEventWorkToDo.Wait( 1000 );
  52. }
  53. }
  54. return 0;
  55. }
  56. //-----------------------------------------------------------------------------
  57. // SubmitThreadedMD5Request
  58. // add pubBuffer,cubBuffer to our queue of stuff to MD5
  59. // caller promises that the memory will remain valid
  60. // until BlockUntilMD5RequestComplete() is called
  61. // returns: request handle
  62. //-----------------------------------------------------------------------------
  63. int CFileTracker2::SubmitThreadedMD5Request( uint8 *pubBuffer, int cubBuffer, int PackFileID, int nPackFileNumber, int nPackFileFraction )
  64. {
  65. int idxList;
  66. StuffToMD5_t stuff;
  67. {
  68. AUTO_LOCK( m_Mutex );
  69. TrackedVPKFile_t trackedVPKFileFind;
  70. trackedVPKFileFind.m_nPackFileNumber = nPackFileNumber;
  71. trackedVPKFileFind.m_PackFileID = PackFileID;
  72. trackedVPKFileFind.m_nFileFraction = nPackFileFraction;
  73. int idxTrackedVPKFile = m_treeTrackedVPKFiles.Find( trackedVPKFileFind );
  74. if ( idxTrackedVPKFile != m_treeTrackedVPKFiles.InvalidIndex() )
  75. {
  76. // dont early out if we have already done the MD5, if the caller wants us
  77. // to do it again - then do it again
  78. m_cDupMD5s++;
  79. }
  80. else
  81. {
  82. // this is an error, we should already know about the file
  83. Assert(0);
  84. return 0;
  85. }
  86. SubmittedMd5Job_t submittedjob;
  87. submittedjob.m_bFinished = false;
  88. idxList = m_SubmittedJobs.AddToTail( submittedjob );
  89. stuff.m_pubBuffer = pubBuffer;
  90. stuff.m_cubBuffer = cubBuffer;
  91. stuff.m_idxTrackedVPKFile = idxTrackedVPKFile;
  92. stuff.m_idxListSubmittedJobs = idxList;
  93. }
  94. // Start thread if it wasn't already active. Do this down here due to the
  95. // return 0 above us. Ie, don't start the thread unless we actually have work
  96. // to do.
  97. if ( m_hWorkThread == NULL )
  98. {
  99. Assert( !m_bThreadShouldRun );
  100. m_bThreadShouldRun = true;
  101. m_hWorkThread = CreateSimpleThread( ThreadStubProcessMD5Requests, this );
  102. }
  103. // submit the work
  104. m_PendingJobs.PushItem( stuff );
  105. m_threadEventWorkToDo.Set();
  106. return idxList + 1;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // IsMD5RequestComplete
  110. // is request identified by iRequest finished?
  111. // ( the caller wants to free the memory, but now must wait until we finish
  112. // calculating the MD5 )
  113. //-----------------------------------------------------------------------------
  114. bool CFileTracker2::IsMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut )
  115. {
  116. AUTO_LOCK( m_Mutex );
  117. int idxListWaiting = iRequest - 1;
  118. // deal with all completed jobs
  119. StuffToMD5_t stuff;
  120. while ( m_CompletedJobs.PopItem( &stuff ) )
  121. {
  122. int idxList = stuff.m_idxListSubmittedJobs;
  123. Q_memcpy( &m_SubmittedJobs[ idxList ].m_md5Value, &stuff.m_md5Value, sizeof( MD5Value_t ) );
  124. m_SubmittedJobs[ idxList ].m_bFinished = true;
  125. }
  126. // did the one we wanted finish?
  127. if ( m_SubmittedJobs[ idxListWaiting ].m_bFinished )
  128. {
  129. Q_memcpy( pMd5ValueOut, &m_SubmittedJobs[ idxListWaiting ].m_md5Value, sizeof( MD5Value_t ) );
  130. // you can not ask again, we have removed it from the list
  131. m_SubmittedJobs.Remove(idxListWaiting);
  132. return true;
  133. }
  134. // not done yet
  135. return false;
  136. }
  137. //-----------------------------------------------------------------------------
  138. // BlockUntilMD5RequestComplete
  139. // block until request identified by iRequest is finished
  140. // ( the caller wants to free the memory, but now must wait until we finish
  141. // calculating the MD5 )
  142. //-----------------------------------------------------------------------------
  143. bool CFileTracker2::BlockUntilMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut )
  144. {
  145. while ( 1 )
  146. {
  147. if ( IsMD5RequestComplete( iRequest, pMd5ValueOut ) )
  148. return true;
  149. m_cThreadBlocks++;
  150. m_threadEventWorkCompleted.Wait( 1 );
  151. }
  152. return false;
  153. }
  154. #endif // SUPPORT_PACKED_STORE
  155. CFileTracker2::CFileTracker2( CBaseFileSystem *pFileSystem ):
  156. m_treeAllOpenedFiles( TrackedFile_t::Less ),
  157. m_treeTrackedVPKFiles( TrackedVPKFile_t::Less )
  158. {
  159. #if defined( DEDICATED )
  160. Assert( 0 );
  161. #endif
  162. m_pFileSystem = pFileSystem;
  163. m_cThreadBlocks = 0;
  164. m_cDupMD5s = 0;
  165. #ifdef SUPPORT_PACKED_STORE
  166. m_bThreadShouldRun = false;
  167. m_hWorkThread = NULL;
  168. #endif
  169. }
  170. CFileTracker2::~CFileTracker2()
  171. {
  172. #ifdef SUPPORT_PACKED_STORE
  173. Assert( !m_bThreadShouldRun );
  174. Assert( m_hWorkThread == NULL );
  175. #endif
  176. }
  177. void CFileTracker2::ShutdownAsync()
  178. {
  179. #ifdef SUPPORT_PACKED_STORE
  180. m_bThreadShouldRun = false;
  181. m_threadEventWorkToDo.Set();
  182. // wait for it to die
  183. if ( m_hWorkThread )
  184. {
  185. ThreadJoin( m_hWorkThread );
  186. ReleaseThreadHandle( m_hWorkThread );
  187. m_hWorkThread = NULL;
  188. }
  189. #endif
  190. }
  191. void CFileTracker2::MarkAllCRCsUnverified()
  192. {
  193. // AUTO_LOCK( m_Mutex );
  194. }
  195. int CFileTracker2::GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles )
  196. {
  197. return 0;
  198. }
  199. EFileCRCStatus CFileTracker2::CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash )
  200. {
  201. Assert( ThreadInMainThread() );
  202. AUTO_LOCK( m_Mutex );
  203. TrackedFile_t trackedfileFind;
  204. trackedfileFind.RebuildFileName( m_stringPool, pRelativeFilename, pPathID, nFileFraction );
  205. int idx = m_treeAllOpenedFiles.Find( trackedfileFind );
  206. if ( idx != m_treeAllOpenedFiles.InvalidIndex() )
  207. {
  208. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ idx ];
  209. if ( trackedfile.m_bFileInVPK )
  210. {
  211. // the FileHash is not meaningful, because the file is in a VPK, we have hashed the entire VPK
  212. // if the user is sending us a hash for this file, it means he has extracted it from the VPK and tricked the client into loading it
  213. // instead of the version in the VPK.
  214. return k_eFileCRCStatus_FileInVPK;
  215. }
  216. return k_eFileCRCStatus_CantOpenFile;
  217. }
  218. else
  219. {
  220. return k_eFileCRCStatus_CantOpenFile;
  221. }
  222. }
  223. void TrackedFile_t::RebuildFileName( CStringPool &stringPool, const char *pFilename, const char *pPathID, int nFileFraction )
  224. {
  225. char szFixedName[ MAX_PATH ];
  226. char szPathName[ MAX_PATH ];
  227. V_strcpy_safe( szFixedName, pFilename );
  228. V_RemoveDotSlashes( szFixedName );
  229. V_FixSlashes( szFixedName );
  230. V_strlower( szFixedName ); // !KLUDGE!
  231. m_filename = stringPool.Allocate( szFixedName );
  232. V_strcpy_safe( szPathName, pPathID ? pPathID : "" );
  233. V_strupr( szPathName ); // !KLUDGE!
  234. m_path = stringPool.Allocate( szPathName );
  235. // CRC32_t crcFilename;
  236. // CRC32_Init( &crcFilename );
  237. // CRC32_ProcessBuffer( &crcFilename, m_filename, Q_strlen( m_filename ) );
  238. // CRC32_ProcessBuffer( &crcFilename, m_path, Q_strlen( m_path ) );
  239. // CRC32_Final( &crcFilename );
  240. // m_crcIdentifier = crcFilename;
  241. m_nFileFraction = nFileFraction;
  242. }
  243. #ifdef SUPPORT_PACKED_STORE
  244. void CFileTracker2::NotePackFileAccess( const char *pFilename, const char *pPathID, int iSearchPathStoreId, CPackedStoreFileHandle &VPKHandle )
  245. {
  246. #if !defined( _GAMECONSOLE ) && !defined( DEDICATED )
  247. AUTO_LOCK( m_Mutex );
  248. Assert( iSearchPathStoreId > 0 );
  249. int idxFile = IdxFileFromName( pFilename, pPathID, 0, false );
  250. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ idxFile ];
  251. // we could use the CRC data from the VPK header - and verify it
  252. // VPKHandle.GetFileCRCFromHeaderData();
  253. // for now all we are going to do is track that this file came from a VPK
  254. trackedfile.m_PackFileID = VPKHandle.m_pOwner->m_PackFileID;
  255. trackedfile.m_nPackFileNumber = VPKHandle.m_nFileNumber; // this might be useful to send up
  256. trackedfile.m_iLoadedSearchPathStoreId = iSearchPathStoreId;
  257. trackedfile.m_bFileInVPK = true;
  258. #endif // !defined( _GAMECONSOLE ) && !defined( DEDICATED )
  259. }
  260. #endif // SUPPORT_PACKED_STORE
  261. struct FileListToUnloadForWhitelistChange : public IFileList
  262. {
  263. virtual bool IsFileInList( const char *pFilename )
  264. {
  265. char szFixedName[ MAX_PATH ];
  266. GetFixedName( pFilename, szFixedName );
  267. return m_dictFiles.Find( szFixedName ) >= 0;
  268. }
  269. virtual void Release()
  270. {
  271. delete this;
  272. }
  273. void AddFile( const char *pszFilename )
  274. {
  275. char szFixedName[ MAX_PATH ];
  276. GetFixedName( pszFilename, szFixedName );
  277. if ( m_dictFiles.Find( szFixedName ) < 0 )
  278. m_dictFiles.Insert( szFixedName );
  279. }
  280. void GetFixedName( const char *pszFilename, char *pszFixedName )
  281. {
  282. V_strncpy( pszFixedName, pszFilename, MAX_PATH );
  283. V_strlower( pszFixedName );
  284. V_FixSlashes( pszFixedName );
  285. }
  286. CUtlDict<int> m_dictFiles;
  287. };
  288. IFileList *CFileTracker2::GetFilesToUnloadForWhitelistChange( IPureServerWhitelist *pNewWhiteList )
  289. {
  290. FileListToUnloadForWhitelistChange *pResult = new FileListToUnloadForWhitelistChange;
  291. for ( int i = m_treeAllOpenedFiles.FirstInorder() ; i >= 0 ; i = m_treeAllOpenedFiles.NextInorder( i ) )
  292. {
  293. TrackedFile_t &f = m_treeAllOpenedFiles[i];
  294. // !KLUDGE! If we ignored it at all, just reload it.
  295. // This is more conservative than we need to be, but the set of files we are ignoring is probably
  296. // pretty small so it should be fine.
  297. if ( f.m_bIgnoredForPureServer )
  298. {
  299. f.m_bIgnoredForPureServer = false;
  300. #ifdef PURE_SERVER_DEBUG_SPEW
  301. Msg( "%s was ignored for pure server purposes. Queuing for reload\n", f.m_filename );
  302. #endif
  303. pResult->AddFile( f.m_filename );
  304. continue;
  305. }
  306. if ( f.m_iLoadedSearchPathStoreId != 0 && pNewWhiteList && pNewWhiteList->GetFileClass( f.m_filename ) == ePureServerFileClass_AnyTrusted )
  307. {
  308. // Check if we loaded it from a path that no longer exists or is no longer trusted
  309. const CBaseFileSystem::CSearchPath *pSearchPath = m_pFileSystem->FindSearchPathByStoreId( f.m_iLoadedSearchPathStoreId );
  310. if ( pSearchPath == NULL )
  311. {
  312. #ifdef PURE_SERVER_DEBUG_SPEW
  313. Msg( "%s was loaded from search path that's no longer mounted. Queuing for reload\n", f.m_filename );
  314. #endif
  315. pResult->AddFile( f.m_filename );
  316. }
  317. else if ( !pSearchPath->m_bIsTrustedForPureServer )
  318. {
  319. #ifdef PURE_SERVER_DEBUG_SPEW
  320. Msg( "%s was loaded from search path that's not currently trusted. Queuing for reload\n", f.m_filename );
  321. #endif
  322. pResult->AddFile( f.m_filename );
  323. }
  324. else
  325. {
  326. #if defined( _DEBUG ) && defined( PURE_SERVER_DEBUG_SPEW )
  327. Msg( "%s is OK. Keeping\n", f.m_filename );
  328. #endif
  329. }
  330. }
  331. }
  332. // Do we need to reload anything?
  333. if ( pResult->m_dictFiles.Count() > 0 )
  334. return pResult;
  335. // Nothing to reload, return an empty list as an optimization
  336. pResult->Release();
  337. return NULL;
  338. }
  339. #ifdef SUPPORT_PACKED_STORE
  340. void CFileTracker2::AddFileHashForVPKFile( int nPackFileNumber, int nFileFraction, int cbFileLen, MD5Value_t &md5, CPackedStoreFileHandle &VPKHandle )
  341. {
  342. #if !defined( DEDICATED )
  343. AUTO_LOCK( m_Mutex );
  344. char szDataFileName[MAX_PATH];
  345. VPKHandle.m_nFileNumber = nPackFileNumber;
  346. VPKHandle.GetPackFileName( szDataFileName, sizeof(szDataFileName) );
  347. const char *pszFileName = V_GetFileName( szDataFileName );
  348. TrackedVPKFile_t trackedVPKFile;
  349. trackedVPKFile.m_nPackFileNumber = VPKHandle.m_nFileNumber;
  350. trackedVPKFile.m_PackFileID = VPKHandle.m_pOwner->m_PackFileID;
  351. trackedVPKFile.m_nFileFraction = nFileFraction;
  352. trackedVPKFile.m_idxAllOpenedFiles = IdxFileFromName( pszFileName, "GAME", nFileFraction, true );
  353. m_treeTrackedVPKFiles.Insert( trackedVPKFile );
  354. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ trackedVPKFile.m_idxAllOpenedFiles ];
  355. // These set in IdxFileFromName:
  356. // trackedfile.m_crcIdentifier
  357. // trackedfile.m_filename
  358. // trackedfile.m_path
  359. // trackedfile.m_bPackOrVPKFile
  360. // trackedfile.m_nFileFraction
  361. // Not set:
  362. // trackedfile.m_iLoadedSearchPathStoreId
  363. // trackedfile.m_bIgnoredForPureServer
  364. trackedfile.m_bFileInVPK = false;
  365. trackedfile.m_bPackOrVPKFile = true;
  366. trackedfile.m_filehashFinal.m_cbFileLen = cbFileLen;
  367. trackedfile.m_filehashFinal.m_eFileHashType = FileHash_t::k_EFileHashTypeEntireFile;
  368. trackedfile.m_filehashFinal.m_nPackFileNumber = nPackFileNumber;
  369. trackedfile.m_filehashFinal.m_PackFileID = VPKHandle.m_pOwner->m_PackFileID;
  370. trackedfile.m_filehashFinal.m_crcIOSequence = cbFileLen;
  371. Q_memcpy( trackedfile.m_filehashFinal.m_md5contents.bits, md5.bits, sizeof( md5.bits) );
  372. #endif // !DEDICATED
  373. }
  374. #endif // SUPPORT_PACKED_STORE
  375. int CFileTracker2::IdxFileFromName( const char *pFilename, const char *pPathID, int nFileFraction, bool bPackOrVPKFile )
  376. {
  377. TrackedFile_t trackedfile;
  378. trackedfile.RebuildFileName( m_stringPool, pFilename, pPathID, nFileFraction );
  379. trackedfile.m_bPackOrVPKFile = bPackOrVPKFile;
  380. int idxFile = m_treeAllOpenedFiles.Find( trackedfile );
  381. if ( idxFile == m_treeAllOpenedFiles.InvalidIndex() )
  382. {
  383. idxFile = m_treeAllOpenedFiles.Insert( trackedfile );
  384. }
  385. return idxFile;
  386. }
  387. #ifdef SUPPORT_PACKED_STORE
  388. int CFileTracker2::NotePackFileOpened( const char *pVPKAbsPath, const char *pPathID, int64 nLength )
  389. {
  390. #if !defined( _GAMECONSOLE )
  391. AUTO_LOCK( m_Mutex );
  392. int idxFile = IdxFileFromName( pVPKAbsPath, pPathID, 0, true );
  393. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ idxFile ];
  394. // we have the real name we want to use. correct the name
  395. trackedfile.m_bPackOrVPKFile = true;
  396. trackedfile.m_PackFileID = idxFile + 1;
  397. trackedfile.m_filehashFinal.m_PackFileID = trackedfile.m_PackFileID;
  398. trackedfile.m_filehashFinal.m_nPackFileNumber = -1;
  399. m_treeAllOpenedFiles.Reinsert( idxFile );
  400. return idxFile + 1;
  401. #else
  402. return 0;
  403. #endif
  404. }
  405. #endif // SUPPORT_PACKED_STORE
  406. void CFileTracker2::NoteFileIgnoredForPureServer( const char *pFilename, const char *pPathID, int iSearchPathStoreId )
  407. {
  408. #if !defined( _GAMECONSOLE )
  409. AUTO_LOCK( m_Mutex );
  410. int idxFile = IdxFileFromName( pFilename, pPathID, 0, false );
  411. m_treeAllOpenedFiles[ idxFile ].m_bIgnoredForPureServer = true;
  412. #endif
  413. }
  414. void CFileTracker2::NoteFileLoadedFromDisk( const char *pFilename, const char *pPathID, int iSearchPathStoreId, FILE *fp, int64 nLength )
  415. {
  416. #if !defined( _GAMECONSOLE ) && !defined( DEDICATED )
  417. AUTO_LOCK( m_Mutex );
  418. Assert( iSearchPathStoreId != 0 );
  419. int idxFile = IdxFileFromName( pFilename, pPathID, 0, false );
  420. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ idxFile ];
  421. trackedfile.m_iLoadedSearchPathStoreId = iSearchPathStoreId;
  422. #endif
  423. }
  424. void CFileTracker2::NoteFileUnloaded( const char *pFilename, const char *pPathID )
  425. {
  426. #if !defined( _GAMECONSOLE )
  427. AUTO_LOCK( m_Mutex );
  428. // Locate bookeeping entry, if any
  429. TrackedFile_t trackedfile;
  430. trackedfile.RebuildFileName( m_stringPool, pFilename, pPathID, 0 );
  431. int idxFile = m_treeAllOpenedFiles.Find( trackedfile );
  432. if ( idxFile >= 0 )
  433. {
  434. // Clear state
  435. TrackedFile_t &trackedfile = m_treeAllOpenedFiles[ idxFile ];
  436. trackedfile.m_iLoadedSearchPathStoreId = 0;
  437. trackedfile.m_bIgnoredForPureServer = false;
  438. }
  439. #endif
  440. }
  441. int CFileTracker2::ListOpenedFiles( bool bAllOpened, const char *pchFilenameFind )
  442. {
  443. AUTO_LOCK( m_Mutex );
  444. int i;
  445. int InvalidIndex;
  446. if ( bAllOpened )
  447. {
  448. i = m_treeAllOpenedFiles.FirstInorder();
  449. InvalidIndex = m_treeAllOpenedFiles.InvalidIndex();
  450. }
  451. else
  452. {
  453. i = m_treeTrackedVPKFiles.FirstInorder();
  454. InvalidIndex = m_treeTrackedVPKFiles.InvalidIndex();
  455. }
  456. Msg( "#, Path, FileName, (PackFileID, PackFileNumber), FileLen, FileFraction\n" );
  457. int count = 0;
  458. int cPackFiles = 0;
  459. while ( i != InvalidIndex )
  460. {
  461. int index = bAllOpened ? i : m_treeTrackedVPKFiles[ i ].m_idxAllOpenedFiles;
  462. TrackedFile_t &file = m_treeAllOpenedFiles[ index ];
  463. if ( file.m_PackFileID )
  464. cPackFiles++;
  465. if ( !pchFilenameFind ||
  466. Q_strstr( file.m_filename, pchFilenameFind ) ||
  467. Q_strstr( file.m_path, pchFilenameFind ) )
  468. {
  469. Msg( "%d %s %s ( %d, %d ) %d %d%s%s\n",
  470. count, file.m_path, file.m_filename, file.m_PackFileID, file.m_nPackFileNumber,
  471. file.m_filehashFinal.m_cbFileLen, file.m_nFileFraction /*, file.m_crcIdentifier*/,
  472. file.m_bFileInVPK ? " (invpk)" : "",
  473. file.m_bPackOrVPKFile ? " (vpk)" : "");
  474. }
  475. i = bAllOpened ? m_treeAllOpenedFiles.NextInorder( i ) : m_treeTrackedVPKFiles.NextInorder( i );
  476. count++;
  477. }
  478. Msg( "cThreadedBlocks:%d cDupMD5s:%d\n", m_cThreadBlocks, m_cDupMD5s );
  479. Msg( "TrackedVPKFiles:%d AllOpenedFiles:%d files VPKfiles:%d StringPoolCount:%d\n",
  480. m_treeTrackedVPKFiles.Count(), m_treeAllOpenedFiles.Count(), cPackFiles, m_stringPool.Count() );
  481. return m_treeAllOpenedFiles.Count();
  482. }
  483. static void CC_TrackerListAllFiles( const CCommand &args )
  484. {
  485. const char *pchFilenameFind = ( args.ArgC() >= 2 ) ? args[1] : NULL;
  486. BaseFileSystem()->m_FileTracker2.ListOpenedFiles( true, pchFilenameFind );
  487. }
  488. static ConCommand trackerlistallfiles( "trackerlistallfiles", CC_TrackerListAllFiles, "TrackerListAllFiles" );
  489. static void CC_TrackerListVPKFiles( const CCommand &args )
  490. {
  491. const char *pchFilenameFind = ( args.ArgC() >= 2 ) ? args[1] : NULL;
  492. BaseFileSystem()->m_FileTracker2.ListOpenedFiles( false, pchFilenameFind );
  493. }
  494. static ConCommand trackerlistvpkfiles( "trackerlistvpkfiles", CC_TrackerListVPKFiles, "TrackerListVPKFiles" );
  495. #endif // !DEDICATED