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.

390 lines
12 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #ifndef FILETRACKER_H
  7. #define FILETRACKER_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "ifilelist.h"
  12. #include "tier1/utldict.h"
  13. class CBaseFileSystem;
  14. class CFileHandle;
  15. enum EFileFlags
  16. {
  17. k_eFileFlags_None = 0x0000,
  18. k_eFileFlagsLoadedFromSteam = 0x0001,
  19. k_eFileFlagsHasCRC = 0x0002, // m_CRC represents the most recently-loaded version of the file. This might be
  20. // unset but m_CRC (and k_eFileFlagsGotCRCOnce) could be set, signifying that
  21. // the file has been opened since last time we calculated the CRC but we didn't
  22. // calculate a CRC for that file version.
  23. k_eFileFlagsForcedLoadFromSteam = 0x0004, // Set if k_eFileFlagsLoadedFromSteam is set AND we forced Steam to not check the disk for this file.
  24. k_eFileFlagsGotCRCOnce = 0x0008, // This is set if we EVER had k_eFileFlagsHasCRC set.. m_CRC will still be set in that case,
  25. // but it'll be the last CRC we calculated and not necessarily
  26. k_eFileFlagsFailedToLoadLastTime = 0x0010 // This is used if we had a record of the file and the game tried to open it, but
  27. // it couldn't be opened. This will happen if the file was loaded from disk, then
  28. // sv_pure is turned on and the file is forced to come from Steam, but there is no
  29. // Steam version. In that case, the game should be told to retry the file
  30. // next time sv_pure is changed because if sv_pure goes back to 0 it -would- load
  31. // the file legitimately.
  32. };
  33. class CPathIDFileList;
  34. class CFileInfo
  35. {
  36. public:
  37. CFileInfo();
  38. ~CFileInfo();
  39. const char* GetFilename();
  40. const char* GetPathIDString();
  41. public:
  42. unsigned short m_Flags; // This is a combination of EFileFlags.
  43. CRC32_t m_CRC; // The CRC for this file.
  44. CPathIDFileList *m_pPathIDFileList;
  45. int m_PathIDFileListDictIndex; // Our index into m_pPathIDFileList->m_Files
  46. int m_iNeedsVerificationListIndex; // Index into m_NeedsVerificationList or -1 if not in the list.
  47. };
  48. // This tracks a list of files for the specified path ID.
  49. class CPathIDFileList
  50. {
  51. public:
  52. CPathIDFileList();
  53. ~CPathIDFileList();
  54. CFileInfo* FindFileInfo( const char *pFilename );
  55. CFileInfo* AddFileInfo( const char *pFilename );
  56. public:
  57. CUtlSymbol m_PathID; // "" for a null path ID.
  58. CUtlDict<CFileInfo*,int> m_Files;
  59. CUtlLinkedList<CFileInfo*,int> m_UnverifiedCRCFiles; // These are the files whose CRCs have not been verified yet.
  60. // These just point at entries in m_Files.
  61. };
  62. //-----------------------------------------------------------------------------
  63. // This tracks the files that have been opened by the filesystem.
  64. // It remembers if they were loaded from Steam or off-disk.
  65. // If the filesystem is tracking CRCs, then it will calculate a CRC
  66. // for each file that came off disk.
  67. //
  68. // TODO: This is similar to CBaseFileSystem::m_OpenedFiles - it could probably
  69. // manage both sets of files in the same list. Having 2 separate lists might
  70. // be confusing.
  71. //-----------------------------------------------------------------------------
  72. class CFileTracker
  73. {
  74. public:
  75. CFileTracker( CBaseFileSystem *pFileSystem );
  76. ~CFileTracker();
  77. // If this is true, then we'll calculate CRCs for each file that came off disk.
  78. void SetWantFileCRCs( bool bWantCRCs );
  79. // As files are opened, if it is calculating CRCs, it will add those files and their
  80. // CRCs to the "unverified CRC" list. The client can then ask the server to verify
  81. // those CRCs to make sure the client is "pure".
  82. void MarkAllCRCsUnverified();
  83. void MarkAllCRCsVerified( bool bLockMutex=true );
  84. // Cache a file's CRC. Loads the file and calculates the CRC if we don't have it yet.
  85. void CacheFileCRC( const char *pPathID, const char *pRelativeFilename );
  86. EFileCRCStatus CheckCachedFileCRC( const char *pPathID, const char *pRelativeFilename, CRC32_t *pCRC );
  87. // This is like CacheFileCRC, but it assumes that the same file would be found by pPathIDToCopyFrom, so it just
  88. // copies the CRC record from that path ID into the one in pPathID and avoids a redundant CRC calculation.
  89. void CacheFileCRC_Copy( const char *pPathID, const char *pRelativeFilename, const char *pPathIDToCopyFrom );
  90. // When we don't have a whitelist, it loads files without bothering to calculate their CRCs (we'd only
  91. // need them on a pure server), but when we get a whitelist, we'll want the CRCs, so it goes back, opens those
  92. // files, and calculates the CRCs for them.
  93. void CalculateMissingCRCs( IFileList *pForceMatchList );
  94. int GetUnverifiedCRCFiles( CUnverifiedCRCFile *pFiles, int nMaxFiles );
  95. // Note that we just opened this file and calculate a CRC for it.
  96. void NoteFileLoadedFromDisk( const char *pFilename, const char *pPathID, FileHandle_t fp );
  97. void NoteFileLoadedFromSteam( const char *pFilename, const char *pPathID, bool bForcedLoadFromSteam );
  98. void NoteFileFailedToLoad( const char *pFilename, const char *pPathID );
  99. // Get a file info from a specific path ID.
  100. CFileInfo* GetFileInfo( const char *pFilename, const char *pPathID );
  101. // Get all file infos with the specified filename (i.e. in all path IDs).
  102. int GetFileInfos( CFileInfo **ppFileInfos, int nMaxFileInfos, const char *pFilename );
  103. // Clear everything.
  104. void Clear();
  105. private:
  106. void CalculateMissingCRC( const char *pFilename, const char *pPathID );
  107. CPathIDFileList* GetPathIDFileList( const char *pPathID, bool bAutoAdd=true );
  108. CRC32_t CalculateCRCForFile( FileHandle_t fp );
  109. private:
  110. CUtlLinkedList<CFileInfo*> m_NeedsVerificationList; // The list of files that need CRCs verified.
  111. CUtlDict<CPathIDFileList*,int> m_PathIDs;
  112. CBaseFileSystem *m_pFileSystem;
  113. CThreadMutex m_Mutex; // Threads call into here, so we need to be safe.
  114. };
  115. inline const char* CFileInfo::GetFilename()
  116. {
  117. return m_pPathIDFileList->m_Files.GetElementName( m_PathIDFileListDictIndex );
  118. }
  119. inline const char* CFileInfo::GetPathIDString()
  120. {
  121. return m_pPathIDFileList->m_PathID.String();
  122. }
  123. struct TrackedFile_t
  124. {
  125. TrackedFile_t()
  126. {
  127. m_nFileFraction = 0;
  128. m_nFilePos = 0;
  129. m_nLength = 0;
  130. m_cubSequentialRead = 0;
  131. m_PackFileID = 0;
  132. m_nPackFileNumber = 0;
  133. m_bPackOrVPKFile = false;
  134. m_bFileInVPK = false;
  135. m_cubTotalRead = 0;
  136. }
  137. CRC32_t m_crcIdentifier;
  138. CUtlString m_filename;
  139. CUtlString m_path;
  140. int m_nFileFraction;
  141. MD5Context_t m_md5ctx;
  142. FileHash_t m_filehashFinal;
  143. FileHash_t m_filehashInProgress;
  144. int m_cubTotalRead;
  145. int64 m_nFilePos;
  146. int64 m_nLength;
  147. int64 m_cubSequentialRead;
  148. int m_idxRecentFileList;
  149. int m_PackFileID;
  150. int m_nPackFileNumber;
  151. bool m_bPackOrVPKFile;
  152. bool m_bFileInVPK;
  153. void RebuildFileName( const char *pFilename, const char *pPathID )
  154. {
  155. m_filename = pFilename;
  156. m_path = pPathID;
  157. CRC32_t crcFilename;
  158. CRC32_Init( &crcFilename );
  159. CRC32_ProcessBuffer( &crcFilename, pFilename, Q_strlen( pFilename ) );
  160. if ( pPathID )
  161. CRC32_ProcessBuffer( &crcFilename, pPathID, Q_strlen( pPathID ) );
  162. CRC32_Final( &crcFilename );
  163. m_crcIdentifier = crcFilename;
  164. }
  165. static bool Less( const TrackedFile_t& lhs, const TrackedFile_t& rhs )
  166. {
  167. if ( lhs.m_crcIdentifier < rhs.m_crcIdentifier )
  168. return true;
  169. if ( lhs.m_crcIdentifier > rhs.m_crcIdentifier )
  170. return false;
  171. if ( lhs.m_nFileFraction < rhs.m_nFileFraction )
  172. return true;
  173. if ( lhs.m_nFileFraction > rhs.m_nFileFraction )
  174. return false;
  175. int nCmp = Q_strcmp( lhs.m_filename.String(), rhs.m_filename.String() );
  176. if ( nCmp < 0 )
  177. return true;
  178. if ( nCmp > 0 )
  179. return false;
  180. nCmp = Q_strcmp( lhs.m_path.String(), rhs.m_path.String() );
  181. if ( nCmp < 0 )
  182. return true;
  183. return false;
  184. }
  185. bool GetCRCValues( FileHash_t *pFileHash );
  186. void ProcessFileRead( void *dest, size_t nBytesRead );
  187. };
  188. struct FileInVPK_t
  189. {
  190. FileInVPK_t()
  191. {
  192. m_PackFileID = 0;
  193. m_nPackFileNumber = 0;
  194. m_nFileOffset = 0;
  195. }
  196. int m_PackFileID;
  197. int m_nPackFileNumber;
  198. int m_nFileOffset;
  199. int m_idxAllOpenedFiles;
  200. static bool Less( const FileInVPK_t& lhs, const FileInVPK_t& rhs )
  201. {
  202. if ( lhs.m_nFileOffset < rhs.m_nFileOffset )
  203. return true;
  204. if ( lhs.m_nFileOffset > rhs.m_nFileOffset )
  205. return false;
  206. if ( lhs.m_nPackFileNumber < rhs.m_nPackFileNumber )
  207. return true;
  208. if ( lhs.m_nPackFileNumber > rhs.m_nPackFileNumber )
  209. return false;
  210. if ( lhs.m_PackFileID < rhs.m_PackFileID )
  211. return true;
  212. if ( lhs.m_PackFileID > rhs.m_PackFileID )
  213. return false;
  214. return false;
  215. }
  216. };
  217. struct TrackedVPKFile_t
  218. {
  219. TrackedVPKFile_t()
  220. {
  221. m_PackFileID = 0;
  222. m_nPackFileNumber = 0;
  223. }
  224. int m_PackFileID;
  225. int m_nPackFileNumber;
  226. int m_nFileFraction;
  227. int m_idxAllOpenedFiles;
  228. static bool Less( const TrackedVPKFile_t& lhs, const TrackedVPKFile_t& rhs )
  229. {
  230. if ( lhs.m_nPackFileNumber < rhs.m_nPackFileNumber )
  231. return true;
  232. if ( lhs.m_nPackFileNumber > rhs.m_nPackFileNumber )
  233. return false;
  234. if ( lhs.m_nFileFraction < rhs.m_nFileFraction )
  235. return true;
  236. if ( lhs.m_nFileFraction > rhs.m_nFileFraction )
  237. return false;
  238. if ( lhs.m_PackFileID < rhs.m_PackFileID )
  239. return true;
  240. if ( lhs.m_PackFileID > rhs.m_PackFileID )
  241. return false;
  242. return false;
  243. }
  244. };
  245. class StuffToMD5_t
  246. {
  247. public:
  248. uint8 *m_pubBuffer;
  249. int m_cubBuffer;
  250. MD5Value_t m_md5Value;
  251. int m_PackFileID;
  252. int m_nPackFileNumber;
  253. int m_nPackFileFraction;
  254. int m_idxListSubmittedJobs;
  255. };
  256. class SubmittedMd5Job_t
  257. {
  258. public:
  259. bool m_bFinished;
  260. MD5Value_t m_md5Value;
  261. };
  262. class CFileTracker2
  263. #ifdef SUPPORT_VPK
  264. : IThreadedFileMD5Processor
  265. #endif
  266. {
  267. public:
  268. CFileTracker2( CBaseFileSystem *pFileSystem );
  269. ~CFileTracker2();
  270. void InitAsyncThread();
  271. void ShutdownAsync();
  272. void MarkAllCRCsUnverified();
  273. int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles );
  274. EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash );
  275. #ifdef SUPPORT_VPK
  276. unsigned ThreadedProcessMD5Requests();
  277. virtual int SubmitThreadedMD5Request( uint8 *pubBuffer, int cubBuffer, int PackFileID, int nPackFileNumber, int nPackFileFraction );
  278. virtual bool BlockUntilMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut );
  279. virtual bool IsMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut );
  280. int NotePackFileOpened( const char *pRawFileName, const char *pFilename, const char *pPathID, int64 nLength );
  281. void NotePackFileAccess( const char *pFilename, const char *pPathID, CPackedStoreFileHandle &VPKHandle );
  282. void NotePackFileRead( CPackedStoreFileHandle &VPKHandle, void *pBuffer, int nReadLength );
  283. void AddFileHashForVPKFile( int nPackFileNumber, int nFileFraction, int cbFileLen, MD5Value_t &md5, CPackedStoreFileHandle &fhandle );
  284. #endif
  285. void NoteFileLoadedFromDisk( const char *pFilename, const char *pPathID, FILE *fp, int64 nLength );
  286. void RecordFileSeek( FILE *fp, int64 pos, int seekType );
  287. void RecordFileClose( FILE *fp );
  288. void RecordFileRead( void *dest, size_t nBytesRead, size_t nBytesRequested, FILE *fp );
  289. int ListOpenedFiles( bool bListAll, const char *pchFilenameFind, bool bListRecentFiles );
  290. private:
  291. int IdxFileFromName( const char *pFilename, const char *pPathID, int nFileFraction, int64 nLength, bool bPackOrVPKFile, bool bRecordInRecentList );
  292. static const int k_nFileFractionSize = 0x00100000; // 1 MB
  293. static const int k_nFileFractionMask = 0xFFF00000; // 1 MB
  294. CUtlRBTree< TrackedFile_t, int > m_treeAllOpenedFiles;
  295. CUtlMap< FILE *, int, int > m_mapAllOpenFiles; // points into m_treeAllOpenedFiles
  296. CUtlRBTree< FileInVPK_t, int > m_treeFileInVPK;
  297. CUtlRBTree< TrackedVPKFile_t, int > m_treeTrackedVPKFiles;
  298. CUtlLinkedList<int> m_RecentFileList; // points into m_treeAllOpenedFiles
  299. int m_cMissedReads;
  300. CBaseFileSystem *m_pFileSystem;
  301. CThreadMutex m_Mutex; // Threads call into here, so we need to be safe.
  302. bool m_bComputeFileHashes;
  303. CThreadEvent m_threadEventWorkToDo;
  304. CThreadEvent m_threadEventWorkCompleted;
  305. volatile bool m_bThreadShouldRun;
  306. ThreadHandle_t m_hWorkThread;
  307. CTSQueue< StuffToMD5_t > m_PendingJobs;
  308. CTSQueue< StuffToMD5_t > m_CompletedJobs;
  309. CUtlLinkedList< SubmittedMd5Job_t > m_SubmittedJobs;
  310. // just stats
  311. int m_cThreadBlocks;
  312. };
  313. #endif // FILETRACKER_H