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.

1001 lines
35 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #ifndef BASEFILESYSTEM_H
  8. #define BASEFILESYSTEM_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #if defined( _WIN32 )
  13. #if !defined( _X360 )
  14. #include <io.h>
  15. #include <direct.h>
  16. #define WIN32_LEAN_AND_MEAN
  17. #include <windows.h>
  18. #endif
  19. #undef GetCurrentDirectory
  20. #undef GetJob
  21. #undef AddJob
  22. #include "tier0/threadtools.h"
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <malloc.h>
  27. #include <string.h>
  28. #include "tier1/utldict.h"
  29. #elif defined(POSIX)
  30. #include <unistd.h> // unlink
  31. #include "linux_support.h"
  32. #define INVALID_HANDLE_VALUE (void *)-1
  33. // undo the prepended "_" 's
  34. #define _chmod chmod
  35. #define _stat stat
  36. #define _alloca alloca
  37. #define _S_IFDIR S_IFDIR
  38. #endif
  39. #include <time.h>
  40. #include "refcount.h"
  41. #include "filesystem.h"
  42. #include "tier1/utlvector.h"
  43. #include <stdarg.h>
  44. #include "tier1/utlhashtable.h"
  45. #include "tier1/utlrbtree.h"
  46. #include "tier1/utlsymbol.h"
  47. #include "tier1/utllinkedlist.h"
  48. #include "tier1/utlstring.h"
  49. #include "tier1/UtlSortVector.h"
  50. #include "bspfile.h"
  51. #include "tier1/utldict.h"
  52. #include "tier1/tier1.h"
  53. #include "byteswap.h"
  54. #include "threadsaferefcountedobject.h"
  55. #include "filetracker.h"
  56. // #include "filesystem_init.h"
  57. #if defined( SUPPORT_PACKED_STORE )
  58. #include "vpklib/packedstore.h"
  59. #endif
  60. #include "tier0/memdbgon.h"
  61. #ifdef _WIN32
  62. #define CORRECT_PATH_SEPARATOR '\\'
  63. #define INCORRECT_PATH_SEPARATOR '/'
  64. #elif defined(POSIX)
  65. #define CORRECT_PATH_SEPARATOR '/'
  66. #define INCORRECT_PATH_SEPARATOR '\\'
  67. #endif
  68. #ifdef _WIN32
  69. #define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
  70. #elif defined(POSIX)
  71. #define PATHSEPARATOR(c) ((c) == '/')
  72. #endif //_WIN32
  73. #define MAX_FILEPATH 512
  74. extern CUtlSymbolTableMT g_PathIDTable;
  75. enum FileMode_t
  76. {
  77. FM_BINARY,
  78. FM_TEXT
  79. };
  80. enum FileType_t
  81. {
  82. FT_NORMAL,
  83. FT_PACK_BINARY,
  84. FT_PACK_TEXT,
  85. FT_MEMORY_BINARY,
  86. FT_MEMORY_TEXT
  87. };
  88. class IThreadPool;
  89. class CBlockingFileItemList;
  90. class KeyValues;
  91. class CCompiledKeyValuesReader;
  92. class CBaseFileSystem;
  93. class CPackFileHandle;
  94. class CPackFile;
  95. class IFileList;
  96. class CFileOpenInfo;
  97. class CFileAsyncReadJob;
  98. //-----------------------------------------------------------------------------
  99. class CFileHandle
  100. {
  101. public:
  102. CFileHandle( CBaseFileSystem* fs );
  103. virtual ~CFileHandle();
  104. void Init( CBaseFileSystem* fs );
  105. int GetSectorSize();
  106. bool IsOK();
  107. void Flush();
  108. void SetBufferSize( int nBytes );
  109. int Read( void* pBuffer, int nLength );
  110. int Read( void* pBuffer, int nDestSize, int nLength );
  111. int Write( const void* pBuffer, int nLength );
  112. int Seek( int64 nOffset, int nWhence );
  113. int Tell();
  114. int Size();
  115. int64 AbsoluteBaseOffset();
  116. bool EndOfFile();
  117. #if !defined( _RETAIL )
  118. char *m_pszTrueFileName;
  119. char const *Name() const { return m_pszTrueFileName ? m_pszTrueFileName : ""; }
  120. void SetName( char const *pName )
  121. {
  122. Assert( pName );
  123. Assert( !m_pszTrueFileName );
  124. int len = Q_strlen( pName );
  125. m_pszTrueFileName = new char[len + 1];
  126. memcpy( m_pszTrueFileName, pName, len + 1 );
  127. }
  128. #endif
  129. CPackFileHandle *m_pPackFileHandle;
  130. #if defined( SUPPORT_PACKED_STORE )
  131. CPackedStoreFileHandle m_VPKHandle;
  132. #endif
  133. int64 m_nLength;
  134. FileType_t m_type;
  135. FILE *m_pFile;
  136. protected:
  137. CBaseFileSystem *m_fs;
  138. enum
  139. {
  140. MAGIC = 0x43464861, // 'CFHa',
  141. FREE_MAGIC = 0x4672654d // 'FreM'
  142. };
  143. unsigned int m_nMagic;
  144. bool IsValid();
  145. };
  146. class CMemoryFileHandle : public CFileHandle
  147. {
  148. public:
  149. CMemoryFileHandle( CBaseFileSystem* pFS, CMemoryFileBacking* pBacking )
  150. : CFileHandle( pFS ), m_pBacking( pBacking ), m_nPosition( 0 ) { m_nLength = pBacking->m_nLength; }
  151. ~CMemoryFileHandle() { m_pBacking->Release(); }
  152. int Read( void* pBuffer, int nDestSize, int nLength );
  153. int Seek( int64 nOffset, int nWhence );
  154. int Tell() { return m_nPosition; }
  155. int Size() { return (int) m_nLength; }
  156. CMemoryFileBacking *m_pBacking;
  157. int m_nPosition;
  158. private:
  159. CMemoryFileHandle( const CMemoryFileHandle& ); // not defined
  160. CMemoryFileHandle& operator=( const CMemoryFileHandle& ); // not defined
  161. };
  162. //-----------------------------------------------------------------------------
  163. #ifdef AsyncRead
  164. #undef AsyncRead
  165. #undef AsyncReadMutiple
  166. #endif
  167. #ifdef SUPPORT_PACKED_STORE
  168. class CPackedStoreRefCount : public CPackedStore, public CRefCounted<CRefCountServiceMT>
  169. {
  170. public:
  171. CPackedStoreRefCount( char const *pFileBasename, char *pszFName, IBaseFileSystem *pFS );
  172. bool m_bSignatureValid;
  173. };
  174. #else
  175. class CPackedStoreRefCount : public CRefCounted<CRefCountServiceMT>
  176. {
  177. };
  178. #endif
  179. //-----------------------------------------------------------------------------
  180. abstract_class CBaseFileSystem : public CTier1AppSystem< IFileSystem >
  181. {
  182. friend class CPackFileHandle;
  183. friend class CZipPackFileHandle;
  184. friend class CPackFile;
  185. friend class CZipPackFile;
  186. friend class CFileHandle;
  187. friend class CFileTracker;
  188. friend class CFileTracker2;
  189. friend class CFileOpenInfo;
  190. typedef CTier1AppSystem< IFileSystem > BaseClass;
  191. public:
  192. CBaseFileSystem();
  193. ~CBaseFileSystem();
  194. // Methods of IAppSystem
  195. virtual void *QueryInterface( const char *pInterfaceName );
  196. virtual InitReturnVal_t Init();
  197. virtual void Shutdown();
  198. void InitAsync();
  199. void ShutdownAsync();
  200. void ParsePathID( const char* &pFilename, const char* &pPathID, char tempPathID[MAX_PATH] );
  201. // file handling
  202. virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID );
  203. virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL );
  204. virtual void Close( FileHandle_t );
  205. virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t method );
  206. virtual unsigned int Tell( FileHandle_t file );
  207. virtual unsigned int Size( FileHandle_t file );
  208. virtual unsigned int Size( const char *pFileName, const char *pPathID );
  209. virtual void SetBufferSize( FileHandle_t file, unsigned nBytes );
  210. virtual bool IsOk( FileHandle_t file );
  211. virtual void Flush( FileHandle_t file );
  212. virtual bool Precache( const char *pFileName, const char *pPathID );
  213. virtual bool EndOfFile( FileHandle_t file );
  214. virtual int Read( void *pOutput, int size, FileHandle_t file );
  215. virtual int ReadEx( void* pOutput, int sizeDest, int size, FileHandle_t file );
  216. virtual int Write( void const* pInput, int size, FileHandle_t file );
  217. virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file );
  218. virtual int FPrintf( FileHandle_t file, PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 3, 4 );
  219. // Reads/writes files to utlbuffers
  220. virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes, int nStartingByte, FSAllocFunc_t pfnAlloc = NULL );
  221. virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf );
  222. virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination );
  223. virtual int ReadFileEx( const char *pFileName, const char *pPath, void **ppBuf, bool bNullTerminate, bool bOptimalAlloc, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL );
  224. virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL );
  225. // Optimal buffer
  226. bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign );
  227. void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize, unsigned nOffset ) { return malloc( nSize ); }
  228. void FreeOptimalReadBuffer( void *p ) { free( p ); }
  229. // Gets the current working directory
  230. virtual bool GetCurrentDirectory( char* pDirectory, int maxlen );
  231. // this isn't implementable on STEAM as is.
  232. virtual void CreateDirHierarchy( const char *path, const char *pathID );
  233. // returns true if the file is a directory
  234. virtual bool IsDirectory( const char *pFileName, const char *pathID );
  235. // path info
  236. virtual const char *GetLocalPath( const char *pFileName, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
  237. virtual bool FullPathToRelativePath( const char *pFullpath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
  238. virtual bool GetCaseCorrectFullPath_Ptr( const char *pFullPath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
  239. // removes a file from disk
  240. virtual void RemoveFile( char const* pRelativePath, const char *pathID );
  241. // Remove all search paths (including write path?)
  242. virtual void RemoveAllSearchPaths( void );
  243. // Purpose: Removes all search paths for a given pathID, such as all "GAME" paths.
  244. virtual void RemoveSearchPaths( const char *pathID );
  245. // STUFF FROM IFileSystem
  246. // Add paths in priority order (mod dir, game dir, ....)
  247. // Can also add pak files (errr, NOT YET!)
  248. virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType );
  249. virtual bool RemoveSearchPath( const char *pPath, const char *pathID );
  250. virtual void PrintSearchPaths( void );
  251. virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly );
  252. virtual bool FileExists( const char *pFileName, const char *pPathID = NULL );
  253. virtual long GetFileTime( const char *pFileName, const char *pPathID = NULL );
  254. virtual bool IsFileWritable( char const *pFileName, const char *pPathID = NULL );
  255. virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID = 0 );
  256. virtual void FileTimeToString( char *pString, int maxChars, long fileTime );
  257. virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle );
  258. virtual const char *FindFirstEx( const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle );
  259. virtual const char *FindNext( FileFindHandle_t handle );
  260. virtual bool FindIsDirectory( FileFindHandle_t handle );
  261. virtual void FindClose( FileFindHandle_t handle );
  262. virtual void PrintOpenedFiles( void );
  263. virtual void SetWarningFunc( void (*pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... ) );
  264. virtual void SetWarningLevel( FileWarningLevel_t level );
  265. virtual void AddLoggingFunc( FileSystemLoggingFunc_t logFunc );
  266. virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc );
  267. virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID );
  268. virtual void GetLocalCopy( const char *pFileName );
  269. virtual bool FixUpPath( const char *pFileName, char *pFixedUpFileName, int sizeFixedUpFileName );
  270. virtual FileNameHandle_t FindOrAddFileName( char const *pFileName );
  271. virtual FileNameHandle_t FindFileName( char const *pFileName );
  272. virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen );
  273. virtual int GetPathIndex( const FileNameHandle_t &handle );
  274. long GetPathTime( const char *pFileName, const char *pPathID );
  275. virtual void EnableWhitelistFileTracking( bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes );
  276. virtual void RegisterFileWhitelist( IPureServerWhitelist *pWhiteList, IFileList **ppFilesToReload ) OVERRIDE;
  277. virtual void MarkAllCRCsUnverified();
  278. virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter );
  279. //void CacheFileCRCs_R( const char *pPathname, ECacheCRCType eType, IFileList *pFilter, CUtlDict<int,int> &searchPathNames );
  280. virtual EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash );
  281. virtual int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles );
  282. virtual int GetWhitelistSpewFlags();
  283. virtual void SetWhitelistSpewFlags( int flags );
  284. virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func );
  285. // Low-level file caching
  286. virtual FileCacheHandle_t CreateFileCache();
  287. virtual void AddFilesToFileCache( FileCacheHandle_t cacheId, const char **ppFileNames, int nFileNames, const char *pPathID );
  288. virtual bool IsFileCacheFileLoaded( FileCacheHandle_t cacheId, const char* pFileName );
  289. virtual bool IsFileCacheLoaded( FileCacheHandle_t cacheId );
  290. virtual void DestroyFileCache( FileCacheHandle_t cacheId );
  291. virtual void CacheAllVPKFileHashes( bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes );
  292. virtual bool CheckVPKFileHash( int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t &md5Value );
  293. virtual void NotifyFileUnloaded( const char *pszFilename, const char *pPathId ) OVERRIDE;
  294. // Returns the file system statistics retreived by the implementation. Returns NULL if not supported.
  295. virtual const FileSystemStatistics *GetFilesystemStatistics();
  296. // Load dlls
  297. virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID, bool bValidatedDllOnly );
  298. virtual void UnloadModule( CSysModule *pModule );
  299. //--------------------------------------------------------
  300. // asynchronous file loading
  301. //--------------------------------------------------------
  302. virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *pControls );
  303. virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *phControls = NULL );
  304. virtual FSAsyncStatus_t AsyncFinish( FSAsyncControl_t hControl, bool wait );
  305. virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize );
  306. virtual FSAsyncStatus_t AsyncAbort( FSAsyncControl_t hControl );
  307. virtual FSAsyncStatus_t AsyncStatus( FSAsyncControl_t hControl );
  308. virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority);
  309. virtual FSAsyncStatus_t AsyncFlush();
  310. virtual FSAsyncStatus_t AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl) { return AsyncWrite( pFileName, pSrc, nSrcBytes, bFreeMemory, true, pControl); }
  311. virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl);
  312. virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl);
  313. virtual FSAsyncStatus_t AsyncAppendFile(const char *pDestFileName, const char *pSrcFileName, FSAsyncControl_t *pControl);
  314. virtual void AsyncFinishAll( int iToPriority = INT_MIN );
  315. virtual void AsyncFinishAllWrites();
  316. virtual bool AsyncSuspend();
  317. virtual bool AsyncResume();
  318. virtual void AsyncAddRef( FSAsyncControl_t hControl );
  319. virtual void AsyncRelease( FSAsyncControl_t hControl );
  320. virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile );
  321. virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile );
  322. virtual void AsyncAddFetcher( IAsyncFileFetch *pFetcher );
  323. virtual void AsyncRemoveFetcher( IAsyncFileFetch *pFetcher );
  324. //--------------------------------------------------------
  325. // pack files
  326. //--------------------------------------------------------
  327. bool AddPackFile( const char *pFileName, const char *pathID );
  328. bool AddPackFileFromPath( const char *pPath, const char *pakfile, bool bCheckForAppendedPack, const char *pathID );
  329. // converts a partial path into a full path
  330. // can be filtered to restrict path types and can provide info about resolved path
  331. virtual const char *RelativePathToFullPath( const char *pFileName, const char *pPathID, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL );
  332. // Returns the search path, each path is separated by ;s. Returns the length of the string returned
  333. virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
  334. #if defined( TRACK_BLOCKING_IO )
  335. virtual void EnableBlockingFileAccessTracking( bool state );
  336. virtual bool IsBlockingFileAccessEnabled() const;
  337. virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo();
  338. virtual void RecordBlockingFileAccess( bool synchronous, const FileBlockingItem& item );
  339. virtual bool SetAllowSynchronousLogging( bool state );
  340. #endif
  341. virtual bool GetFileTypeForFullPath( char const *pFullPath, wchar_t *buf, size_t bufSizeInBytes );
  342. virtual void BeginMapAccess();
  343. virtual void EndMapAccess();
  344. virtual bool FullPathToRelativePathEx( const char *pFullpath, const char *pPathId, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
  345. FSAsyncStatus_t SyncRead( const FileAsyncRequest_t &request );
  346. FSAsyncStatus_t SyncWrite(const char *pszFilename, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend );
  347. FSAsyncStatus_t SyncAppendFile(const char *pAppendToFileName, const char *pAppendFromFileName );
  348. FSAsyncStatus_t SyncGetFileSize( const FileAsyncRequest_t &request );
  349. void DoAsyncCallback( const FileAsyncRequest_t &request, void *pData, int nBytesRead, FSAsyncStatus_t result );
  350. void SetupPreloadData();
  351. void DiscardPreloadData();
  352. virtual void LoadCompiledKeyValues( KeyValuesPreloadType_t type, char const *archiveFile );
  353. // If the "PreloadedData" hasn't been purged, then this'll try and instance the KeyValues using the fast path of compiled keyvalues loaded during startup.
  354. // Otherwise, it'll just fall through to the regular KeyValues loading routines
  355. virtual KeyValues *LoadKeyValues( KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 );
  356. virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 );
  357. virtual bool ExtractRootKeyName( KeyValuesPreloadType_t type, char *outbuf, size_t bufsize, char const *filename, char const *pPathID = 0 );
  358. virtual DVDMode_t GetDVDMode() { return m_DVDMode; }
  359. FSDirtyDiskReportFunc_t GetDirtyDiskReportFunc() { return m_DirtyDiskReportFunc; }
  360. //-----------------------------------------------------------------------------
  361. // MemoryFile cache implementation
  362. //-----------------------------------------------------------------------------
  363. class CFileCacheObject;
  364. // XXX For now, we assume that all path IDs are "GAME", never cache files
  365. // outside of the game search path, and preferentially return those files
  366. // whenever anyone searches for a match even if an on-disk file in another
  367. // folder would have been found first in a traditional search. extending
  368. // the memory cache to cover non-game files isn't necessary right now, but
  369. // should just be a matter of defining a more complex key type. (henryg)
  370. // Register a CMemoryFileBacking; must balance with UnregisterMemoryFile.
  371. // Returns false and outputs an ref-bumped pointer to the existing entry
  372. // if the same file has already been registered by someone else; this must
  373. // be Unregistered to maintain the balance.
  374. virtual bool RegisterMemoryFile( CMemoryFileBacking *pFile, CMemoryFileBacking **ppExistingFileWithRef );
  375. // Unregister a CMemoryFileBacking; must balance with RegisterMemoryFile.
  376. virtual void UnregisterMemoryFile( CMemoryFileBacking *pFile );
  377. //------------------------------------
  378. // Synchronous path for file operations
  379. //------------------------------------
  380. class CPathIDInfo
  381. {
  382. public:
  383. const CUtlSymbol& GetPathID() const;
  384. const char* GetPathIDString() const;
  385. void SetPathID( CUtlSymbol id );
  386. public:
  387. // See MarkPathIDByRequestOnly.
  388. bool m_bByRequestOnly;
  389. private:
  390. CUtlSymbol m_PathID;
  391. const char *m_pDebugPathID;
  392. };
  393. ////////////////////////////////////////////////
  394. // IMPLEMENTATION DETAILS FOR CBaseFileSystem //
  395. ////////////////////////////////////////////////
  396. class CSearchPath
  397. {
  398. public:
  399. CSearchPath( void );
  400. ~CSearchPath( void );
  401. const char* GetPathString() const;
  402. const char* GetDebugString() const;
  403. // Path ID ("game", "mod", "gamebin") accessors.
  404. const CUtlSymbol& GetPathID() const;
  405. const char* GetPathIDString() const;
  406. // Search path (c:\hl2\hl2) accessors.
  407. void SetPath( CUtlSymbol id );
  408. const CUtlSymbol& GetPath() const;
  409. void SetPackFile(CPackFile *pPackFile) { m_pPackFile = pPackFile; }
  410. CPackFile *GetPackFile() const { return m_pPackFile; }
  411. #ifdef SUPPORT_PACKED_STORE
  412. void SetPackedStore( CPackedStoreRefCount *pPackedStore ) { m_pPackedStore = pPackedStore; }
  413. #endif
  414. CPackedStoreRefCount *GetPackedStore() const { return m_pPackedStore; }
  415. bool IsMapPath() const;
  416. int m_storeId;
  417. // Used to track if its search
  418. CPathIDInfo *m_pPathIDInfo;
  419. bool m_bIsRemotePath;
  420. bool m_bIsTrustedForPureServer;
  421. private:
  422. CUtlSymbol m_Path;
  423. const char *m_pDebugPath;
  424. CPackFile *m_pPackFile;
  425. CPackedStoreRefCount *m_pPackedStore;
  426. };
  427. class CSearchPathsVisits
  428. {
  429. public:
  430. void Reset()
  431. {
  432. m_Visits.RemoveAll();
  433. }
  434. bool MarkVisit( const CSearchPath &searchPath )
  435. {
  436. if ( m_Visits.Find( searchPath.m_storeId ) == m_Visits.InvalidIndex() )
  437. {
  438. MEM_ALLOC_CREDIT();
  439. m_Visits.AddToTail( searchPath.m_storeId );
  440. return false;
  441. }
  442. return true;
  443. }
  444. private:
  445. CUtlVector<int> m_Visits; // This is a copy of IDs for the search paths we've visited, so
  446. };
  447. class CSearchPathsIterator
  448. {
  449. public:
  450. CSearchPathsIterator( CBaseFileSystem *pFileSystem, const char **ppszFilename, const char *pszPathID, PathTypeFilter_t pathTypeFilter = FILTER_NONE )
  451. : m_iCurrent( -1 ),
  452. m_PathTypeFilter( pathTypeFilter )
  453. {
  454. char tempPathID[MAX_PATH];
  455. if ( *ppszFilename && (*ppszFilename)[0] == '/' && (*ppszFilename)[1] == '/' ) // ONLY '//' (and not '\\') for our special format
  456. {
  457. // Allow for UNC-type syntax to specify the path ID.
  458. pFileSystem->ParsePathID( *ppszFilename, pszPathID, tempPathID );
  459. }
  460. if ( pszPathID )
  461. {
  462. m_pathID = g_PathIDTable.AddString( pszPathID );
  463. }
  464. else
  465. {
  466. m_pathID = UTL_INVAL_SYMBOL;
  467. }
  468. if ( *ppszFilename && !Q_IsAbsolutePath( *ppszFilename ) )
  469. {
  470. // Copy paths to minimize mutex lock time
  471. pFileSystem->m_SearchPathsMutex.Lock();
  472. CopySearchPaths( pFileSystem->m_SearchPaths );
  473. pFileSystem->m_SearchPathsMutex.Unlock();
  474. pFileSystem->FixUpPath ( *ppszFilename, m_Filename, sizeof( m_Filename ) );
  475. }
  476. else
  477. {
  478. // If it's an absolute path, it isn't worth using the paths at all. Simplify
  479. // client logic by pretending there's a search path of 1
  480. m_EmptyPathIDInfo.m_bByRequestOnly = false;
  481. m_EmptySearchPath.m_pPathIDInfo = &m_EmptyPathIDInfo;
  482. m_EmptySearchPath.SetPath( m_pathID );
  483. m_EmptySearchPath.m_storeId = -1;
  484. m_Filename[0] = '\0';
  485. }
  486. }
  487. CSearchPathsIterator( CBaseFileSystem *pFileSystem, const char *pszPathID, PathTypeFilter_t pathTypeFilter = FILTER_NONE )
  488. : m_iCurrent( -1 ),
  489. m_PathTypeFilter( pathTypeFilter )
  490. {
  491. if ( pszPathID )
  492. {
  493. m_pathID = g_PathIDTable.AddString( pszPathID );
  494. }
  495. else
  496. {
  497. m_pathID = UTL_INVAL_SYMBOL;
  498. }
  499. // Copy paths to minimize mutex lock time
  500. pFileSystem->m_SearchPathsMutex.Lock();
  501. CopySearchPaths( pFileSystem->m_SearchPaths );
  502. pFileSystem->m_SearchPathsMutex.Unlock();
  503. m_Filename[0] = '\0';
  504. }
  505. CSearchPath *GetFirst();
  506. CSearchPath *GetNext();
  507. private:
  508. CSearchPathsIterator( const CSearchPathsIterator & );
  509. void operator=(const CSearchPathsIterator &);
  510. void CopySearchPaths( const CUtlVector<CSearchPath> &searchPaths );
  511. int m_iCurrent;
  512. CUtlSymbol m_pathID;
  513. CUtlVector<CSearchPath> m_SearchPaths;
  514. CSearchPathsVisits m_visits;
  515. CSearchPath m_EmptySearchPath;
  516. CPathIDInfo m_EmptyPathIDInfo;
  517. PathTypeFilter_t m_PathTypeFilter;
  518. char m_Filename[MAX_PATH]; // set for relative names only
  519. };
  520. friend class CSearchPathsIterator;
  521. struct FindData_t
  522. {
  523. WIN32_FIND_DATA findData;
  524. int currentSearchPathID;
  525. CUtlVector<char> wildCardString;
  526. HANDLE findHandle;
  527. CSearchPathsVisits m_VisitedSearchPaths; // This is a copy of IDs for the search paths we've visited, so avoids searching duplicate paths.
  528. int m_CurrentStoreID; // CSearchPath::m_storeId of the current search path.
  529. CUtlSymbol m_FilterPathID; // What path ID are we looking at? Ignore all others. (Only set by FindFirstEx).
  530. CUtlDict<int,int> m_VisitedFiles; // We go through the search paths in priority order, and we use this to make sure
  531. // that we don't return the same file more than once.
  532. CUtlStringList m_fileMatchesFromVPKOrPak;
  533. CUtlStringList m_dirMatchesFromVPKOrPak;
  534. };
  535. friend class CSearchPath;
  536. IPureServerWhitelist *m_pPureServerWhitelist;
  537. int m_WhitelistSpewFlags; // Combination of WHITELIST_SPEW_ flags.
  538. // logging functions
  539. CUtlVector< FileSystemLoggingFunc_t > m_LogFuncs;
  540. CThreadMutex m_SearchPathsMutex;
  541. CUtlVector< CSearchPath > m_SearchPaths;
  542. CUtlVector<CPathIDInfo*> m_PathIDInfos;
  543. CUtlLinkedList<FindData_t> m_FindData;
  544. CSearchPath *FindSearchPathByStoreId( int storeId );
  545. int m_iMapLoad;
  546. // Global list of pack file handles
  547. CUtlVector<CPackFile *> m_ZipFiles;
  548. FILE *m_pLogFile;
  549. bool m_bOutputDebugString;
  550. IThreadPool * m_pThreadPool;
  551. CThreadFastMutex m_AsyncCallbackMutex;
  552. // Statistics:
  553. FileSystemStatistics m_Stats;
  554. #if defined( TRACK_BLOCKING_IO )
  555. CBlockingFileItemList *m_pBlockingItems;
  556. bool m_bBlockingFileAccessReportingEnabled;
  557. bool m_bAllowSynchronousLogging;
  558. friend class CBlockingFileItemList;
  559. friend class CAutoBlockReporter;
  560. #endif
  561. CFileTracker2 m_FileTracker2;
  562. protected:
  563. //----------------------------------------------------------------------------
  564. // Purpose: Functions implementing basic file system behavior.
  565. //----------------------------------------------------------------------------
  566. virtual FILE *FS_fopen( const char *filename, const char *options, unsigned flags, int64 *size ) = 0;
  567. virtual void FS_setbufsize( FILE *fp, unsigned nBytes ) = 0;
  568. virtual void FS_fclose( FILE *fp ) = 0;
  569. virtual void FS_fseek( FILE *fp, int64 pos, int seekType ) = 0;
  570. virtual long FS_ftell( FILE *fp ) = 0;
  571. virtual int FS_feof( FILE *fp ) = 0;
  572. size_t FS_fread( void *dest, size_t size, FILE *fp ) { return FS_fread( dest, (size_t)-1, size, fp ); }
  573. virtual size_t FS_fread( void *dest, size_t destSize, size_t size, FILE *fp ) = 0;
  574. virtual size_t FS_fwrite( const void *src, size_t size, FILE *fp ) = 0;
  575. virtual bool FS_setmode( FILE *fp, FileMode_t mode ) { return false; }
  576. virtual size_t FS_vfprintf( FILE *fp, const char *fmt, va_list list ) = 0;
  577. virtual int FS_ferror( FILE *fp ) = 0;
  578. virtual int FS_fflush( FILE *fp ) = 0;
  579. virtual char *FS_fgets( char *dest, int destSize, FILE *fp ) = 0;
  580. virtual int FS_stat( const char *path, struct _stat *buf, bool *pbLoadedFromSteamCache=NULL ) = 0;
  581. virtual int FS_chmod( const char *path, int pmode ) = 0;
  582. virtual HANDLE FS_FindFirstFile( const char *findname, WIN32_FIND_DATA *dat) = 0;
  583. virtual bool FS_FindNextFile(HANDLE handle, WIN32_FIND_DATA *dat) = 0;
  584. virtual bool FS_FindClose(HANDLE handle) = 0;
  585. virtual int FS_GetSectorSize( FILE * ) { return 1; }
  586. #if defined( TRACK_BLOCKING_IO )
  587. void BlockingFileAccess_EnterCriticalSection();
  588. void BlockingFileAccess_LeaveCriticalSection();
  589. CThreadMutex m_BlockingFileMutex;
  590. #endif
  591. void GetFileNameForHandle( FileHandle_t handle, char *buf, size_t buflen );
  592. protected:
  593. //-----------------------------------------------------------------------------
  594. // Purpose: For tracking unclosed files
  595. // NOTE: The symbol table could take up memory that we don't want to eat here.
  596. // In that case, we shouldn't store them in a table, or we should store them as locally allocates stings
  597. // so we can control the size
  598. //-----------------------------------------------------------------------------
  599. class COpenedFile
  600. {
  601. public:
  602. COpenedFile( void );
  603. ~COpenedFile( void );
  604. COpenedFile( const COpenedFile& src );
  605. bool operator==( const COpenedFile& src ) const;
  606. void SetName( char const *name );
  607. char const *GetName( void );
  608. FILE *m_pFile;
  609. char *m_pName;
  610. };
  611. CThreadFastMutex m_MemoryFileMutex;
  612. CUtlHashtable< const char*, CMemoryFileBacking* > m_MemoryFileHash;
  613. //CUtlRBTree< COpenedFile, int > m_OpenedFiles;
  614. CThreadMutex m_OpenedFilesMutex;
  615. CUtlVector <COpenedFile> m_OpenedFiles;
  616. static bool OpenedFileLessFunc( COpenedFile const& src1, COpenedFile const& src2 );
  617. FileWarningLevel_t m_fwLevel;
  618. void (*m_pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... );
  619. FILE *Trace_FOpen( const char *filename, const char *options, unsigned flags, int64 *size );
  620. void Trace_FClose( FILE *fp );
  621. void Trace_FRead( int size, FILE* file );
  622. void Trace_FWrite( int size, FILE* file );
  623. void Trace_DumpUnclosedFiles( void );
  624. public:
  625. void LogAccessToFile( char const *accesstype, char const *fullpath, char const *options );
  626. void Warning( FileWarningLevel_t level, PRINTF_FORMAT_STRING const char *fmt, ... );
  627. protected:
  628. // Note: if pFoundStoreID is passed in, then it will set that to the CSearchPath::m_storeId value of the search path it found the file in.
  629. const char* FindFirstHelper( const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle, int *pFoundStoreID );
  630. bool FindNextFileHelper( FindData_t *pFindData, int *pFoundStoreID );
  631. bool FindNextFileInVPKOrPakHelper( FindData_t *pFindData );
  632. void RemoveAllMapSearchPaths( void );
  633. void AddMapPackFile( const char *pPath, const char *pPathID, SearchPathAdd_t addType );
  634. void AddPackFiles( const char *pPath, const CUtlSymbol &pathID, SearchPathAdd_t addType );
  635. bool PreparePackFile( CPackFile &packfile, int offsetofpackinmetafile, int64 filelen );
  636. void AddVPKFile( const char *pPath, const char *pPathID, SearchPathAdd_t addType );
  637. bool RemoveVPKFile( const char *pPath, const char *pPathID );
  638. void HandleOpenRegularFile( CFileOpenInfo &openInfo, bool bIsAbsolutePath );
  639. FileHandle_t FindFileInSearchPath( CFileOpenInfo &openInfo );
  640. long FastFileTime( const CSearchPath *path, const char *pFileName );
  641. const char *GetWritePath( const char *pFilename, const char *pathID );
  642. // Computes a full write path
  643. void ComputeFullWritePath( char* pDest, int maxlen, const char *pWritePathID, char const *pRelativePath );
  644. void AddSearchPathInternal( const char *pPath, const char *pathID, SearchPathAdd_t addType, bool bAddPackFiles );
  645. // Opens a file for read or write
  646. FileHandle_t OpenForRead( const char *pFileName, const char *pOptions, unsigned flags, const char *pathID, char **ppszResolvedFilename = NULL );
  647. FileHandle_t OpenForWrite( const char *pFileName, const char *pOptions, const char *pathID );
  648. CSearchPath *FindWritePath( const char *pFilename, const char *pathID );
  649. // Helper function for fs_log file logging
  650. void LogFileAccess( const char *pFullFileName );
  651. bool LookupKeyValuesRootKeyName( char const *filename, char const *pPathID, char *rootName, size_t bufsize );
  652. void UnloadCompiledKeyValues();
  653. // If bByRequestOnly is -1, then it will default to false if it doesn't already exist, and it
  654. // won't change it if it does already exist. Otherwise, it will be set to the value of bByRequestOnly.
  655. CPathIDInfo* FindOrAddPathIDInfo( const CUtlSymbol &id, int bByRequestOnly );
  656. static bool FilterByPathID( const CSearchPath *pSearchPath, const CUtlSymbol &pathID );
  657. // Global/shared filename/path table
  658. CUtlFilenameSymbolTable m_FileNames;
  659. int m_WhitelistFileTrackingEnabled; // -1 if unset, 0 if disabled (single player), 1 if enabled (multiplayer).
  660. FSDirtyDiskReportFunc_t m_DirtyDiskReportFunc;
  661. void SetSearchPathIsTrustedSource( CSearchPath *pPath );
  662. struct CompiledKeyValuesPreloaders_t
  663. {
  664. CompiledKeyValuesPreloaders_t() :
  665. m_CacheFile( 0 ),
  666. m_pReader( 0 )
  667. {
  668. }
  669. FileNameHandle_t m_CacheFile;
  670. CCompiledKeyValuesReader *m_pReader;
  671. };
  672. CompiledKeyValuesPreloaders_t m_PreloadData[ NUM_PRELOAD_TYPES ];
  673. static CUtlSymbol m_GamePathID;
  674. static CUtlSymbol m_BSPPathID;
  675. static DVDMode_t m_DVDMode;
  676. // Pack exclude paths are strictly for 360 to allow holes in search paths and pack files
  677. // which fall through to support new or dynamic data on the host pc.
  678. static CUtlVector< FileNameHandle_t > m_ExcludePaths;
  679. /// List of installed hooks to intercept async file operations
  680. CUtlVector< IAsyncFileFetch * > m_vecAsyncFetchers;
  681. /// List of active async jobs being serviced by customer fetchers
  682. CUtlVector< CFileAsyncReadJob * > m_vecAsyncCustomFetchJobs;
  683. /// Remove a custom fetch job from the list (and release our reference)
  684. friend class CFileAsyncReadJob;
  685. void RemoveAsyncCustomFetchJob( CFileAsyncReadJob *pJob );
  686. };
  687. inline const CUtlSymbol& CBaseFileSystem::CPathIDInfo::GetPathID() const
  688. {
  689. return m_PathID;
  690. }
  691. inline const char* CBaseFileSystem::CPathIDInfo::GetPathIDString() const
  692. {
  693. return g_PathIDTable.String( m_PathID );
  694. }
  695. inline const char* CBaseFileSystem::CSearchPath::GetPathString() const
  696. {
  697. return g_PathIDTable.String( m_Path );
  698. }
  699. inline void CBaseFileSystem::CPathIDInfo::SetPathID( CUtlSymbol sym )
  700. {
  701. m_PathID = sym;
  702. m_pDebugPathID = GetPathIDString();
  703. }
  704. inline const CUtlSymbol& CBaseFileSystem::CSearchPath::GetPathID() const
  705. {
  706. return m_pPathIDInfo->GetPathID();
  707. }
  708. inline const char* CBaseFileSystem::CSearchPath::GetPathIDString() const
  709. {
  710. return m_pPathIDInfo->GetPathIDString();
  711. }
  712. inline void CBaseFileSystem::CSearchPath::SetPath( CUtlSymbol id )
  713. {
  714. m_Path = id;
  715. m_pDebugPath = g_PathIDTable.String( m_Path );
  716. }
  717. inline const CUtlSymbol& CBaseFileSystem::CSearchPath::GetPath() const
  718. {
  719. return m_Path;
  720. }
  721. inline bool CBaseFileSystem::FilterByPathID( const CSearchPath *pSearchPath, const CUtlSymbol &pathID )
  722. {
  723. if ( (UtlSymId_t)pathID == UTL_INVAL_SYMBOL )
  724. {
  725. // They didn't specify a specific search path, so if this search path's path ID is by
  726. // request only, then ignore it.
  727. return pSearchPath->m_pPathIDInfo->m_bByRequestOnly;
  728. }
  729. else
  730. {
  731. // Bit of a hack, but specifying "BSP" as the search path will search in "GAME" for only the map/.bsp pack file path
  732. if ( pathID == m_BSPPathID )
  733. {
  734. if ( pSearchPath->GetPathID() != m_GamePathID )
  735. return true;
  736. if ( !pSearchPath->GetPackFile() )
  737. return true;
  738. if ( !pSearchPath->IsMapPath() )
  739. return true;
  740. return false;
  741. }
  742. else
  743. {
  744. return (pSearchPath->GetPathID() != pathID);
  745. }
  746. }
  747. }
  748. #if defined( TRACK_BLOCKING_IO )
  749. class CAutoBlockReporter
  750. {
  751. public:
  752. CAutoBlockReporter( CBaseFileSystem *fs, bool synchronous, char const *filename, int eBlockType, int nTypeOfAccess ) :
  753. m_pFS( fs ),
  754. m_Item( eBlockType, filename, 0.0f, nTypeOfAccess ),
  755. m_bSynchronous( synchronous )
  756. {
  757. Assert( m_pFS );
  758. m_Timer.Start();
  759. }
  760. CAutoBlockReporter( CBaseFileSystem *fs, bool synchronous, FileHandle_t handle, int eBlockType, int nTypeOfAccess ) :
  761. m_pFS( fs ),
  762. m_Item( eBlockType, NULL, 0.0f, nTypeOfAccess ),
  763. m_bSynchronous( synchronous )
  764. {
  765. Assert( m_pFS );
  766. char name[ 512 ];
  767. m_pFS->GetFileNameForHandle( handle, name, sizeof( name ) );
  768. m_Item.SetFileName( name );
  769. m_Timer.Start();
  770. }
  771. ~CAutoBlockReporter()
  772. {
  773. m_Timer.End();
  774. m_Item.m_flElapsed = m_Timer.GetDuration().GetSeconds();
  775. m_pFS->RecordBlockingFileAccess( m_bSynchronous, m_Item );
  776. }
  777. private:
  778. CBaseFileSystem *m_pFS;
  779. CFastTimer m_Timer;
  780. FileBlockingItem m_Item;
  781. bool m_bSynchronous;
  782. };
  783. #define AUTOBLOCKREPORTER_FN( name, fs, sync, filename, blockType, accessType ) CAutoBlockReporter block##name( fs, sync, filename, blockType, accessType );
  784. #define AUTOBLOCKREPORTER_FH( name, fs, sync, handle, blockType, accessType ) CAutoBlockReporter block##name( fs, sync, handle, blockType, accessType );
  785. #else
  786. #define AUTOBLOCKREPORTER_FN( name, fs, sync, filename, blockType, accessType ) // Nothing
  787. #define AUTOBLOCKREPORTER_FH( name, fs, sync, handle , blockType, accessType ) // Nothing
  788. #endif
  789. // singleton accessor
  790. CBaseFileSystem *BaseFileSystem();
  791. #include "tier0/memdbgoff.h"
  792. #endif // BASEFILESYSTEM_H