summaryrefslogtreecommitdiff
path: root/filesystem/basefilesystem.h
diff options
context:
space:
mode:
Diffstat (limited to 'filesystem/basefilesystem.h')
-rw-r--r--filesystem/basefilesystem.h1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/filesystem/basefilesystem.h b/filesystem/basefilesystem.h
new file mode 100644
index 0000000..e413db7
--- /dev/null
+++ b/filesystem/basefilesystem.h
@@ -0,0 +1,1001 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef BASEFILESYSTEM_H
+#define BASEFILESYSTEM_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#if defined( _WIN32 )
+
+#if !defined( _X360 )
+ #include <io.h>
+ #include <direct.h>
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#endif
+#undef GetCurrentDirectory
+#undef GetJob
+#undef AddJob
+
+#include "tier0/threadtools.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <malloc.h>
+#include <string.h>
+#include "tier1/utldict.h"
+
+#elif defined(POSIX)
+ #include <unistd.h> // unlink
+ #include "linux_support.h"
+ #define INVALID_HANDLE_VALUE (void *)-1
+
+ // undo the prepended "_" 's
+ #define _chmod chmod
+ #define _stat stat
+ #define _alloca alloca
+ #define _S_IFDIR S_IFDIR
+#endif
+
+#include <time.h>
+#include "refcount.h"
+#include "filesystem.h"
+#include "tier1/utlvector.h"
+#include <stdarg.h>
+#include "tier1/utlhashtable.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/utlsymbol.h"
+#include "tier1/utllinkedlist.h"
+#include "tier1/utlstring.h"
+#include "tier1/UtlSortVector.h"
+#include "bspfile.h"
+#include "tier1/utldict.h"
+#include "tier1/tier1.h"
+#include "byteswap.h"
+#include "threadsaferefcountedobject.h"
+#include "filetracker.h"
+// #include "filesystem_init.h"
+
+#if defined( SUPPORT_PACKED_STORE )
+#include "vpklib/packedstore.h"
+#endif
+
+#include "tier0/memdbgon.h"
+
+#ifdef _WIN32
+#define CORRECT_PATH_SEPARATOR '\\'
+#define INCORRECT_PATH_SEPARATOR '/'
+#elif defined(POSIX)
+#define CORRECT_PATH_SEPARATOR '/'
+#define INCORRECT_PATH_SEPARATOR '\\'
+#endif
+
+#ifdef _WIN32
+#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
+#elif defined(POSIX)
+#define PATHSEPARATOR(c) ((c) == '/')
+#endif //_WIN32
+
+#define MAX_FILEPATH 512
+
+extern CUtlSymbolTableMT g_PathIDTable;
+
+enum FileMode_t
+{
+ FM_BINARY,
+ FM_TEXT
+};
+
+enum FileType_t
+{
+ FT_NORMAL,
+ FT_PACK_BINARY,
+ FT_PACK_TEXT,
+ FT_MEMORY_BINARY,
+ FT_MEMORY_TEXT
+};
+
+class IThreadPool;
+class CBlockingFileItemList;
+class KeyValues;
+class CCompiledKeyValuesReader;
+class CBaseFileSystem;
+class CPackFileHandle;
+class CPackFile;
+class IFileList;
+class CFileOpenInfo;
+class CFileAsyncReadJob;
+
+//-----------------------------------------------------------------------------
+
+class CFileHandle
+{
+public:
+ CFileHandle( CBaseFileSystem* fs );
+ virtual ~CFileHandle();
+
+ void Init( CBaseFileSystem* fs );
+
+ int GetSectorSize();
+ bool IsOK();
+ void Flush();
+ void SetBufferSize( int nBytes );
+
+ int Read( void* pBuffer, int nLength );
+ int Read( void* pBuffer, int nDestSize, int nLength );
+
+ int Write( const void* pBuffer, int nLength );
+ int Seek( int64 nOffset, int nWhence );
+ int Tell();
+ int Size();
+
+ int64 AbsoluteBaseOffset();
+ bool EndOfFile();
+
+#if !defined( _RETAIL )
+ char *m_pszTrueFileName;
+ char const *Name() const { return m_pszTrueFileName ? m_pszTrueFileName : ""; }
+
+ void SetName( char const *pName )
+ {
+ Assert( pName );
+ Assert( !m_pszTrueFileName );
+ int len = Q_strlen( pName );
+ m_pszTrueFileName = new char[len + 1];
+ memcpy( m_pszTrueFileName, pName, len + 1 );
+ }
+#endif
+
+ CPackFileHandle *m_pPackFileHandle;
+#if defined( SUPPORT_PACKED_STORE )
+ CPackedStoreFileHandle m_VPKHandle;
+#endif
+ int64 m_nLength;
+ FileType_t m_type;
+ FILE *m_pFile;
+
+protected:
+ CBaseFileSystem *m_fs;
+
+ enum
+ {
+ MAGIC = 0x43464861, // 'CFHa',
+ FREE_MAGIC = 0x4672654d // 'FreM'
+ };
+ unsigned int m_nMagic;
+
+ bool IsValid();
+};
+
+class CMemoryFileHandle : public CFileHandle
+{
+public:
+ CMemoryFileHandle( CBaseFileSystem* pFS, CMemoryFileBacking* pBacking )
+ : CFileHandle( pFS ), m_pBacking( pBacking ), m_nPosition( 0 ) { m_nLength = pBacking->m_nLength; }
+
+ ~CMemoryFileHandle() { m_pBacking->Release(); }
+
+ int Read( void* pBuffer, int nDestSize, int nLength );
+ int Seek( int64 nOffset, int nWhence );
+ int Tell() { return m_nPosition; }
+ int Size() { return (int) m_nLength; }
+
+ CMemoryFileBacking *m_pBacking;
+ int m_nPosition;
+
+private:
+ CMemoryFileHandle( const CMemoryFileHandle& ); // not defined
+ CMemoryFileHandle& operator=( const CMemoryFileHandle& ); // not defined
+};
+
+
+//-----------------------------------------------------------------------------
+
+#ifdef AsyncRead
+#undef AsyncRead
+#undef AsyncReadMutiple
+#endif
+
+#ifdef SUPPORT_PACKED_STORE
+class CPackedStoreRefCount : public CPackedStore, public CRefCounted<CRefCountServiceMT>
+{
+public:
+ CPackedStoreRefCount( char const *pFileBasename, char *pszFName, IBaseFileSystem *pFS );
+
+ bool m_bSignatureValid;
+};
+#else
+class CPackedStoreRefCount : public CRefCounted<CRefCountServiceMT>
+{
+};
+#endif
+
+//-----------------------------------------------------------------------------
+
+abstract_class CBaseFileSystem : public CTier1AppSystem< IFileSystem >
+{
+ friend class CPackFileHandle;
+ friend class CZipPackFileHandle;
+ friend class CPackFile;
+ friend class CZipPackFile;
+ friend class CFileHandle;
+ friend class CFileTracker;
+ friend class CFileTracker2;
+ friend class CFileOpenInfo;
+
+ typedef CTier1AppSystem< IFileSystem > BaseClass;
+
+public:
+ CBaseFileSystem();
+ ~CBaseFileSystem();
+
+ // Methods of IAppSystem
+ virtual void *QueryInterface( const char *pInterfaceName );
+ virtual InitReturnVal_t Init();
+ virtual void Shutdown();
+
+ void InitAsync();
+ void ShutdownAsync();
+
+ void ParsePathID( const char* &pFilename, const char* &pPathID, char tempPathID[MAX_PATH] );
+
+ // file handling
+ virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID );
+ virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL );
+ virtual void Close( FileHandle_t );
+ virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t method );
+ virtual unsigned int Tell( FileHandle_t file );
+ virtual unsigned int Size( FileHandle_t file );
+ virtual unsigned int Size( const char *pFileName, const char *pPathID );
+
+ virtual void SetBufferSize( FileHandle_t file, unsigned nBytes );
+ virtual bool IsOk( FileHandle_t file );
+ virtual void Flush( FileHandle_t file );
+ virtual bool Precache( const char *pFileName, const char *pPathID );
+ virtual bool EndOfFile( FileHandle_t file );
+
+ virtual int Read( void *pOutput, int size, FileHandle_t file );
+ virtual int ReadEx( void* pOutput, int sizeDest, int size, FileHandle_t file );
+ virtual int Write( void const* pInput, int size, FileHandle_t file );
+ virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file );
+ virtual int FPrintf( FileHandle_t file, PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 3, 4 );
+
+ // Reads/writes files to utlbuffers
+ virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes, int nStartingByte, FSAllocFunc_t pfnAlloc = NULL );
+ virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf );
+ virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination );
+ 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 );
+ virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL );
+
+ // Optimal buffer
+ bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign );
+ void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize, unsigned nOffset ) { return malloc( nSize ); }
+ void FreeOptimalReadBuffer( void *p ) { free( p ); }
+
+ // Gets the current working directory
+ virtual bool GetCurrentDirectory( char* pDirectory, int maxlen );
+
+ // this isn't implementable on STEAM as is.
+ virtual void CreateDirHierarchy( const char *path, const char *pathID );
+
+ // returns true if the file is a directory
+ virtual bool IsDirectory( const char *pFileName, const char *pathID );
+
+ // path info
+ virtual const char *GetLocalPath( const char *pFileName, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
+ virtual bool FullPathToRelativePath( const char *pFullpath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
+ virtual bool GetCaseCorrectFullPath_Ptr( const char *pFullPath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
+
+ // removes a file from disk
+ virtual void RemoveFile( char const* pRelativePath, const char *pathID );
+
+ // Remove all search paths (including write path?)
+ virtual void RemoveAllSearchPaths( void );
+
+ // Purpose: Removes all search paths for a given pathID, such as all "GAME" paths.
+ virtual void RemoveSearchPaths( const char *pathID );
+
+ // STUFF FROM IFileSystem
+ // Add paths in priority order (mod dir, game dir, ....)
+ // Can also add pak files (errr, NOT YET!)
+ virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType );
+ virtual bool RemoveSearchPath( const char *pPath, const char *pathID );
+ virtual void PrintSearchPaths( void );
+
+ virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly );
+
+ virtual bool FileExists( const char *pFileName, const char *pPathID = NULL );
+ virtual long GetFileTime( const char *pFileName, const char *pPathID = NULL );
+ virtual bool IsFileWritable( char const *pFileName, const char *pPathID = NULL );
+ virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID = 0 );
+ virtual void FileTimeToString( char *pString, int maxChars, long fileTime );
+
+ virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle );
+ virtual const char *FindFirstEx( const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle );
+ virtual const char *FindNext( FileFindHandle_t handle );
+ virtual bool FindIsDirectory( FileFindHandle_t handle );
+ virtual void FindClose( FileFindHandle_t handle );
+
+ virtual void PrintOpenedFiles( void );
+ virtual void SetWarningFunc( void (*pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... ) );
+ virtual void SetWarningLevel( FileWarningLevel_t level );
+ virtual void AddLoggingFunc( FileSystemLoggingFunc_t logFunc );
+ virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc );
+ virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID );
+
+ virtual void GetLocalCopy( const char *pFileName );
+
+ virtual bool FixUpPath( const char *pFileName, char *pFixedUpFileName, int sizeFixedUpFileName );
+
+ virtual FileNameHandle_t FindOrAddFileName( char const *pFileName );
+ virtual FileNameHandle_t FindFileName( char const *pFileName );
+ virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen );
+ virtual int GetPathIndex( const FileNameHandle_t &handle );
+ long GetPathTime( const char *pFileName, const char *pPathID );
+
+ virtual void EnableWhitelistFileTracking( bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes );
+ virtual void RegisterFileWhitelist( IPureServerWhitelist *pWhiteList, IFileList **ppFilesToReload ) OVERRIDE;
+ virtual void MarkAllCRCsUnverified();
+ virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter );
+ //void CacheFileCRCs_R( const char *pPathname, ECacheCRCType eType, IFileList *pFilter, CUtlDict<int,int> &searchPathNames );
+ virtual EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash );
+ virtual int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles );
+ virtual int GetWhitelistSpewFlags();
+ virtual void SetWhitelistSpewFlags( int flags );
+ virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func );
+
+ // Low-level file caching
+ virtual FileCacheHandle_t CreateFileCache();
+ virtual void AddFilesToFileCache( FileCacheHandle_t cacheId, const char **ppFileNames, int nFileNames, const char *pPathID );
+ virtual bool IsFileCacheFileLoaded( FileCacheHandle_t cacheId, const char* pFileName );
+ virtual bool IsFileCacheLoaded( FileCacheHandle_t cacheId );
+ virtual void DestroyFileCache( FileCacheHandle_t cacheId );
+
+ virtual void CacheAllVPKFileHashes( bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes );
+ virtual bool CheckVPKFileHash( int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t &md5Value );
+ virtual void NotifyFileUnloaded( const char *pszFilename, const char *pPathId ) OVERRIDE;
+
+ // Returns the file system statistics retreived by the implementation. Returns NULL if not supported.
+ virtual const FileSystemStatistics *GetFilesystemStatistics();
+
+ // Load dlls
+ virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID, bool bValidatedDllOnly );
+ virtual void UnloadModule( CSysModule *pModule );
+
+ //--------------------------------------------------------
+ // asynchronous file loading
+ //--------------------------------------------------------
+ virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *pControls );
+ virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *phControls = NULL );
+ virtual FSAsyncStatus_t AsyncFinish( FSAsyncControl_t hControl, bool wait );
+ virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize );
+ virtual FSAsyncStatus_t AsyncAbort( FSAsyncControl_t hControl );
+ virtual FSAsyncStatus_t AsyncStatus( FSAsyncControl_t hControl );
+ virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority);
+ virtual FSAsyncStatus_t AsyncFlush();
+ 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); }
+ virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl);
+ virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl);
+ virtual FSAsyncStatus_t AsyncAppendFile(const char *pDestFileName, const char *pSrcFileName, FSAsyncControl_t *pControl);
+ virtual void AsyncFinishAll( int iToPriority = INT_MIN );
+ virtual void AsyncFinishAllWrites();
+ virtual bool AsyncSuspend();
+ virtual bool AsyncResume();
+
+ virtual void AsyncAddRef( FSAsyncControl_t hControl );
+ virtual void AsyncRelease( FSAsyncControl_t hControl );
+ virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile );
+ virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile );
+ virtual void AsyncAddFetcher( IAsyncFileFetch *pFetcher );
+ virtual void AsyncRemoveFetcher( IAsyncFileFetch *pFetcher );
+
+ //--------------------------------------------------------
+ // pack files
+ //--------------------------------------------------------
+ bool AddPackFile( const char *pFileName, const char *pathID );
+ bool AddPackFileFromPath( const char *pPath, const char *pakfile, bool bCheckForAppendedPack, const char *pathID );
+
+ // converts a partial path into a full path
+ // can be filtered to restrict path types and can provide info about resolved path
+ 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 );
+
+ // Returns the search path, each path is separated by ;s. Returns the length of the string returned
+ virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
+
+#if defined( TRACK_BLOCKING_IO )
+ virtual void EnableBlockingFileAccessTracking( bool state );
+ virtual bool IsBlockingFileAccessEnabled() const;
+ virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo();
+
+ virtual void RecordBlockingFileAccess( bool synchronous, const FileBlockingItem& item );
+
+ virtual bool SetAllowSynchronousLogging( bool state );
+#endif
+
+ virtual bool GetFileTypeForFullPath( char const *pFullPath, wchar_t *buf, size_t bufSizeInBytes );
+
+ virtual void BeginMapAccess();
+ virtual void EndMapAccess();
+ virtual bool FullPathToRelativePathEx( const char *pFullpath, const char *pPathId, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars );
+
+ FSAsyncStatus_t SyncRead( const FileAsyncRequest_t &request );
+ FSAsyncStatus_t SyncWrite(const char *pszFilename, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend );
+ FSAsyncStatus_t SyncAppendFile(const char *pAppendToFileName, const char *pAppendFromFileName );
+ FSAsyncStatus_t SyncGetFileSize( const FileAsyncRequest_t &request );
+ void DoAsyncCallback( const FileAsyncRequest_t &request, void *pData, int nBytesRead, FSAsyncStatus_t result );
+
+ void SetupPreloadData();
+ void DiscardPreloadData();
+
+ virtual void LoadCompiledKeyValues( KeyValuesPreloadType_t type, char const *archiveFile );
+
+ // 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.
+ // Otherwise, it'll just fall through to the regular KeyValues loading routines
+ virtual KeyValues *LoadKeyValues( KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 );
+ virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 );
+ virtual bool ExtractRootKeyName( KeyValuesPreloadType_t type, char *outbuf, size_t bufsize, char const *filename, char const *pPathID = 0 );
+
+ virtual DVDMode_t GetDVDMode() { return m_DVDMode; }
+
+ FSDirtyDiskReportFunc_t GetDirtyDiskReportFunc() { return m_DirtyDiskReportFunc; }
+
+ //-----------------------------------------------------------------------------
+ // MemoryFile cache implementation
+ //-----------------------------------------------------------------------------
+ class CFileCacheObject;
+
+ // XXX For now, we assume that all path IDs are "GAME", never cache files
+ // outside of the game search path, and preferentially return those files
+ // whenever anyone searches for a match even if an on-disk file in another
+ // folder would have been found first in a traditional search. extending
+ // the memory cache to cover non-game files isn't necessary right now, but
+ // should just be a matter of defining a more complex key type. (henryg)
+
+ // Register a CMemoryFileBacking; must balance with UnregisterMemoryFile.
+ // Returns false and outputs an ref-bumped pointer to the existing entry
+ // if the same file has already been registered by someone else; this must
+ // be Unregistered to maintain the balance.
+ virtual bool RegisterMemoryFile( CMemoryFileBacking *pFile, CMemoryFileBacking **ppExistingFileWithRef );
+
+ // Unregister a CMemoryFileBacking; must balance with RegisterMemoryFile.
+ virtual void UnregisterMemoryFile( CMemoryFileBacking *pFile );
+
+ //------------------------------------
+ // Synchronous path for file operations
+ //------------------------------------
+ class CPathIDInfo
+ {
+ public:
+ const CUtlSymbol& GetPathID() const;
+ const char* GetPathIDString() const;
+ void SetPathID( CUtlSymbol id );
+
+ public:
+ // See MarkPathIDByRequestOnly.
+ bool m_bByRequestOnly;
+
+ private:
+ CUtlSymbol m_PathID;
+ const char *m_pDebugPathID;
+ };
+
+ ////////////////////////////////////////////////
+ // IMPLEMENTATION DETAILS FOR CBaseFileSystem //
+ ////////////////////////////////////////////////
+
+ class CSearchPath
+ {
+ public:
+ CSearchPath( void );
+ ~CSearchPath( void );
+
+ const char* GetPathString() const;
+ const char* GetDebugString() const;
+
+ // Path ID ("game", "mod", "gamebin") accessors.
+ const CUtlSymbol& GetPathID() const;
+ const char* GetPathIDString() const;
+
+ // Search path (c:\hl2\hl2) accessors.
+ void SetPath( CUtlSymbol id );
+ const CUtlSymbol& GetPath() const;
+
+ void SetPackFile(CPackFile *pPackFile) { m_pPackFile = pPackFile; }
+ CPackFile *GetPackFile() const { return m_pPackFile; }
+
+ #ifdef SUPPORT_PACKED_STORE
+ void SetPackedStore( CPackedStoreRefCount *pPackedStore ) { m_pPackedStore = pPackedStore; }
+ #endif
+ CPackedStoreRefCount *GetPackedStore() const { return m_pPackedStore; }
+
+ bool IsMapPath() const;
+
+ int m_storeId;
+
+ // Used to track if its search
+ CPathIDInfo *m_pPathIDInfo;
+
+ bool m_bIsRemotePath;
+
+ bool m_bIsTrustedForPureServer;
+
+ private:
+ CUtlSymbol m_Path;
+ const char *m_pDebugPath;
+ CPackFile *m_pPackFile;
+ CPackedStoreRefCount *m_pPackedStore;
+ };
+
+ class CSearchPathsVisits
+ {
+ public:
+ void Reset()
+ {
+ m_Visits.RemoveAll();
+ }
+
+ bool MarkVisit( const CSearchPath &searchPath )
+ {
+ if ( m_Visits.Find( searchPath.m_storeId ) == m_Visits.InvalidIndex() )
+ {
+ MEM_ALLOC_CREDIT();
+ m_Visits.AddToTail( searchPath.m_storeId );
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ CUtlVector<int> m_Visits; // This is a copy of IDs for the search paths we've visited, so
+ };
+
+ class CSearchPathsIterator
+ {
+ public:
+ CSearchPathsIterator( CBaseFileSystem *pFileSystem, const char **ppszFilename, const char *pszPathID, PathTypeFilter_t pathTypeFilter = FILTER_NONE )
+ : m_iCurrent( -1 ),
+ m_PathTypeFilter( pathTypeFilter )
+ {
+ char tempPathID[MAX_PATH];
+ if ( *ppszFilename && (*ppszFilename)[0] == '/' && (*ppszFilename)[1] == '/' ) // ONLY '//' (and not '\\') for our special format
+ {
+ // Allow for UNC-type syntax to specify the path ID.
+ pFileSystem->ParsePathID( *ppszFilename, pszPathID, tempPathID );
+ }
+ if ( pszPathID )
+ {
+ m_pathID = g_PathIDTable.AddString( pszPathID );
+ }
+ else
+ {
+ m_pathID = UTL_INVAL_SYMBOL;
+ }
+
+ if ( *ppszFilename && !Q_IsAbsolutePath( *ppszFilename ) )
+ {
+ // Copy paths to minimize mutex lock time
+ pFileSystem->m_SearchPathsMutex.Lock();
+ CopySearchPaths( pFileSystem->m_SearchPaths );
+ pFileSystem->m_SearchPathsMutex.Unlock();
+
+ pFileSystem->FixUpPath ( *ppszFilename, m_Filename, sizeof( m_Filename ) );
+ }
+ else
+ {
+ // If it's an absolute path, it isn't worth using the paths at all. Simplify
+ // client logic by pretending there's a search path of 1
+ m_EmptyPathIDInfo.m_bByRequestOnly = false;
+ m_EmptySearchPath.m_pPathIDInfo = &m_EmptyPathIDInfo;
+ m_EmptySearchPath.SetPath( m_pathID );
+ m_EmptySearchPath.m_storeId = -1;
+ m_Filename[0] = '\0';
+ }
+ }
+
+ CSearchPathsIterator( CBaseFileSystem *pFileSystem, const char *pszPathID, PathTypeFilter_t pathTypeFilter = FILTER_NONE )
+ : m_iCurrent( -1 ),
+ m_PathTypeFilter( pathTypeFilter )
+ {
+ if ( pszPathID )
+ {
+ m_pathID = g_PathIDTable.AddString( pszPathID );
+ }
+ else
+ {
+ m_pathID = UTL_INVAL_SYMBOL;
+ }
+ // Copy paths to minimize mutex lock time
+ pFileSystem->m_SearchPathsMutex.Lock();
+ CopySearchPaths( pFileSystem->m_SearchPaths );
+ pFileSystem->m_SearchPathsMutex.Unlock();
+ m_Filename[0] = '\0';
+ }
+
+ CSearchPath *GetFirst();
+ CSearchPath *GetNext();
+
+ private:
+ CSearchPathsIterator( const CSearchPathsIterator & );
+ void operator=(const CSearchPathsIterator &);
+ void CopySearchPaths( const CUtlVector<CSearchPath> &searchPaths );
+
+ int m_iCurrent;
+ CUtlSymbol m_pathID;
+ CUtlVector<CSearchPath> m_SearchPaths;
+ CSearchPathsVisits m_visits;
+ CSearchPath m_EmptySearchPath;
+ CPathIDInfo m_EmptyPathIDInfo;
+ PathTypeFilter_t m_PathTypeFilter;
+ char m_Filename[MAX_PATH]; // set for relative names only
+ };
+
+ friend class CSearchPathsIterator;
+
+ struct FindData_t
+ {
+ WIN32_FIND_DATA findData;
+ int currentSearchPathID;
+ CUtlVector<char> wildCardString;
+ HANDLE findHandle;
+ CSearchPathsVisits m_VisitedSearchPaths; // This is a copy of IDs for the search paths we've visited, so avoids searching duplicate paths.
+ int m_CurrentStoreID; // CSearchPath::m_storeId of the current search path.
+
+ CUtlSymbol m_FilterPathID; // What path ID are we looking at? Ignore all others. (Only set by FindFirstEx).
+
+ CUtlDict<int,int> m_VisitedFiles; // We go through the search paths in priority order, and we use this to make sure
+ // that we don't return the same file more than once.
+ CUtlStringList m_fileMatchesFromVPKOrPak;
+ CUtlStringList m_dirMatchesFromVPKOrPak;
+ };
+
+ friend class CSearchPath;
+
+ IPureServerWhitelist *m_pPureServerWhitelist;
+ int m_WhitelistSpewFlags; // Combination of WHITELIST_SPEW_ flags.
+
+ // logging functions
+ CUtlVector< FileSystemLoggingFunc_t > m_LogFuncs;
+
+ CThreadMutex m_SearchPathsMutex;
+ CUtlVector< CSearchPath > m_SearchPaths;
+ CUtlVector<CPathIDInfo*> m_PathIDInfos;
+ CUtlLinkedList<FindData_t> m_FindData;
+
+ CSearchPath *FindSearchPathByStoreId( int storeId );
+
+ int m_iMapLoad;
+
+ // Global list of pack file handles
+ CUtlVector<CPackFile *> m_ZipFiles;
+
+ FILE *m_pLogFile;
+ bool m_bOutputDebugString;
+
+ IThreadPool * m_pThreadPool;
+ CThreadFastMutex m_AsyncCallbackMutex;
+
+ // Statistics:
+ FileSystemStatistics m_Stats;
+
+#if defined( TRACK_BLOCKING_IO )
+ CBlockingFileItemList *m_pBlockingItems;
+ bool m_bBlockingFileAccessReportingEnabled;
+ bool m_bAllowSynchronousLogging;
+
+ friend class CBlockingFileItemList;
+ friend class CAutoBlockReporter;
+#endif
+
+ CFileTracker2 m_FileTracker2;
+
+protected:
+ //----------------------------------------------------------------------------
+ // Purpose: Functions implementing basic file system behavior.
+ //----------------------------------------------------------------------------
+ virtual FILE *FS_fopen( const char *filename, const char *options, unsigned flags, int64 *size ) = 0;
+ virtual void FS_setbufsize( FILE *fp, unsigned nBytes ) = 0;
+ virtual void FS_fclose( FILE *fp ) = 0;
+ virtual void FS_fseek( FILE *fp, int64 pos, int seekType ) = 0;
+ virtual long FS_ftell( FILE *fp ) = 0;
+ virtual int FS_feof( FILE *fp ) = 0;
+ size_t FS_fread( void *dest, size_t size, FILE *fp ) { return FS_fread( dest, (size_t)-1, size, fp ); }
+ virtual size_t FS_fread( void *dest, size_t destSize, size_t size, FILE *fp ) = 0;
+ virtual size_t FS_fwrite( const void *src, size_t size, FILE *fp ) = 0;
+ virtual bool FS_setmode( FILE *fp, FileMode_t mode ) { return false; }
+ virtual size_t FS_vfprintf( FILE *fp, const char *fmt, va_list list ) = 0;
+ virtual int FS_ferror( FILE *fp ) = 0;
+ virtual int FS_fflush( FILE *fp ) = 0;
+ virtual char *FS_fgets( char *dest, int destSize, FILE *fp ) = 0;
+ virtual int FS_stat( const char *path, struct _stat *buf, bool *pbLoadedFromSteamCache=NULL ) = 0;
+ virtual int FS_chmod( const char *path, int pmode ) = 0;
+ virtual HANDLE FS_FindFirstFile( const char *findname, WIN32_FIND_DATA *dat) = 0;
+ virtual bool FS_FindNextFile(HANDLE handle, WIN32_FIND_DATA *dat) = 0;
+ virtual bool FS_FindClose(HANDLE handle) = 0;
+ virtual int FS_GetSectorSize( FILE * ) { return 1; }
+
+#if defined( TRACK_BLOCKING_IO )
+ void BlockingFileAccess_EnterCriticalSection();
+ void BlockingFileAccess_LeaveCriticalSection();
+
+ CThreadMutex m_BlockingFileMutex;
+
+#endif
+
+ void GetFileNameForHandle( FileHandle_t handle, char *buf, size_t buflen );
+
+protected:
+ //-----------------------------------------------------------------------------
+ // Purpose: For tracking unclosed files
+ // NOTE: The symbol table could take up memory that we don't want to eat here.
+ // In that case, we shouldn't store them in a table, or we should store them as locally allocates stings
+ // so we can control the size
+ //-----------------------------------------------------------------------------
+ class COpenedFile
+ {
+ public:
+ COpenedFile( void );
+ ~COpenedFile( void );
+
+ COpenedFile( const COpenedFile& src );
+
+ bool operator==( const COpenedFile& src ) const;
+
+ void SetName( char const *name );
+ char const *GetName( void );
+
+ FILE *m_pFile;
+ char *m_pName;
+ };
+
+ CThreadFastMutex m_MemoryFileMutex;
+ CUtlHashtable< const char*, CMemoryFileBacking* > m_MemoryFileHash;
+
+
+ //CUtlRBTree< COpenedFile, int > m_OpenedFiles;
+ CThreadMutex m_OpenedFilesMutex;
+ CUtlVector <COpenedFile> m_OpenedFiles;
+
+ static bool OpenedFileLessFunc( COpenedFile const& src1, COpenedFile const& src2 );
+
+ FileWarningLevel_t m_fwLevel;
+ void (*m_pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... );
+
+ FILE *Trace_FOpen( const char *filename, const char *options, unsigned flags, int64 *size );
+ void Trace_FClose( FILE *fp );
+ void Trace_FRead( int size, FILE* file );
+ void Trace_FWrite( int size, FILE* file );
+
+ void Trace_DumpUnclosedFiles( void );
+
+public:
+ void LogAccessToFile( char const *accesstype, char const *fullpath, char const *options );
+ void Warning( FileWarningLevel_t level, PRINTF_FORMAT_STRING const char *fmt, ... );
+
+protected:
+ // 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.
+ const char* FindFirstHelper( const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle, int *pFoundStoreID );
+ bool FindNextFileHelper( FindData_t *pFindData, int *pFoundStoreID );
+ bool FindNextFileInVPKOrPakHelper( FindData_t *pFindData );
+
+ void RemoveAllMapSearchPaths( void );
+ void AddMapPackFile( const char *pPath, const char *pPathID, SearchPathAdd_t addType );
+ void AddPackFiles( const char *pPath, const CUtlSymbol &pathID, SearchPathAdd_t addType );
+ bool PreparePackFile( CPackFile &packfile, int offsetofpackinmetafile, int64 filelen );
+ void AddVPKFile( const char *pPath, const char *pPathID, SearchPathAdd_t addType );
+ bool RemoveVPKFile( const char *pPath, const char *pPathID );
+
+ void HandleOpenRegularFile( CFileOpenInfo &openInfo, bool bIsAbsolutePath );
+
+ FileHandle_t FindFileInSearchPath( CFileOpenInfo &openInfo );
+ long FastFileTime( const CSearchPath *path, const char *pFileName );
+
+ const char *GetWritePath( const char *pFilename, const char *pathID );
+
+ // Computes a full write path
+ void ComputeFullWritePath( char* pDest, int maxlen, const char *pWritePathID, char const *pRelativePath );
+
+ void AddSearchPathInternal( const char *pPath, const char *pathID, SearchPathAdd_t addType, bool bAddPackFiles );
+
+ // Opens a file for read or write
+ FileHandle_t OpenForRead( const char *pFileName, const char *pOptions, unsigned flags, const char *pathID, char **ppszResolvedFilename = NULL );
+ FileHandle_t OpenForWrite( const char *pFileName, const char *pOptions, const char *pathID );
+ CSearchPath *FindWritePath( const char *pFilename, const char *pathID );
+
+ // Helper function for fs_log file logging
+ void LogFileAccess( const char *pFullFileName );
+ bool LookupKeyValuesRootKeyName( char const *filename, char const *pPathID, char *rootName, size_t bufsize );
+ void UnloadCompiledKeyValues();
+
+ // If bByRequestOnly is -1, then it will default to false if it doesn't already exist, and it
+ // won't change it if it does already exist. Otherwise, it will be set to the value of bByRequestOnly.
+ CPathIDInfo* FindOrAddPathIDInfo( const CUtlSymbol &id, int bByRequestOnly );
+ static bool FilterByPathID( const CSearchPath *pSearchPath, const CUtlSymbol &pathID );
+
+ // Global/shared filename/path table
+ CUtlFilenameSymbolTable m_FileNames;
+
+ int m_WhitelistFileTrackingEnabled; // -1 if unset, 0 if disabled (single player), 1 if enabled (multiplayer).
+ FSDirtyDiskReportFunc_t m_DirtyDiskReportFunc;
+
+ void SetSearchPathIsTrustedSource( CSearchPath *pPath );
+
+ struct CompiledKeyValuesPreloaders_t
+ {
+ CompiledKeyValuesPreloaders_t() :
+ m_CacheFile( 0 ),
+ m_pReader( 0 )
+ {
+ }
+ FileNameHandle_t m_CacheFile;
+ CCompiledKeyValuesReader *m_pReader;
+ };
+
+ CompiledKeyValuesPreloaders_t m_PreloadData[ NUM_PRELOAD_TYPES ];
+
+ static CUtlSymbol m_GamePathID;
+ static CUtlSymbol m_BSPPathID;
+
+ static DVDMode_t m_DVDMode;
+
+ // Pack exclude paths are strictly for 360 to allow holes in search paths and pack files
+ // which fall through to support new or dynamic data on the host pc.
+ static CUtlVector< FileNameHandle_t > m_ExcludePaths;
+
+ /// List of installed hooks to intercept async file operations
+ CUtlVector< IAsyncFileFetch * > m_vecAsyncFetchers;
+
+ /// List of active async jobs being serviced by customer fetchers
+ CUtlVector< CFileAsyncReadJob * > m_vecAsyncCustomFetchJobs;
+
+ /// Remove a custom fetch job from the list (and release our reference)
+ friend class CFileAsyncReadJob;
+ void RemoveAsyncCustomFetchJob( CFileAsyncReadJob *pJob );
+};
+
+inline const CUtlSymbol& CBaseFileSystem::CPathIDInfo::GetPathID() const
+{
+ return m_PathID;
+}
+
+
+inline const char* CBaseFileSystem::CPathIDInfo::GetPathIDString() const
+{
+ return g_PathIDTable.String( m_PathID );
+}
+
+
+inline const char* CBaseFileSystem::CSearchPath::GetPathString() const
+{
+ return g_PathIDTable.String( m_Path );
+}
+
+
+inline void CBaseFileSystem::CPathIDInfo::SetPathID( CUtlSymbol sym )
+{
+ m_PathID = sym;
+ m_pDebugPathID = GetPathIDString();
+}
+
+
+inline const CUtlSymbol& CBaseFileSystem::CSearchPath::GetPathID() const
+{
+ return m_pPathIDInfo->GetPathID();
+}
+
+
+inline const char* CBaseFileSystem::CSearchPath::GetPathIDString() const
+{
+ return m_pPathIDInfo->GetPathIDString();
+}
+
+
+inline void CBaseFileSystem::CSearchPath::SetPath( CUtlSymbol id )
+{
+ m_Path = id;
+ m_pDebugPath = g_PathIDTable.String( m_Path );
+}
+
+
+inline const CUtlSymbol& CBaseFileSystem::CSearchPath::GetPath() const
+{
+ return m_Path;
+}
+
+
+inline bool CBaseFileSystem::FilterByPathID( const CSearchPath *pSearchPath, const CUtlSymbol &pathID )
+{
+ if ( (UtlSymId_t)pathID == UTL_INVAL_SYMBOL )
+ {
+ // They didn't specify a specific search path, so if this search path's path ID is by
+ // request only, then ignore it.
+ return pSearchPath->m_pPathIDInfo->m_bByRequestOnly;
+ }
+ else
+ {
+ // Bit of a hack, but specifying "BSP" as the search path will search in "GAME" for only the map/.bsp pack file path
+ if ( pathID == m_BSPPathID )
+ {
+ if ( pSearchPath->GetPathID() != m_GamePathID )
+ return true;
+
+ if ( !pSearchPath->GetPackFile() )
+ return true;
+
+ if ( !pSearchPath->IsMapPath() )
+ return true;
+
+ return false;
+ }
+ else
+ {
+ return (pSearchPath->GetPathID() != pathID);
+ }
+ }
+}
+
+#if defined( TRACK_BLOCKING_IO )
+
+class CAutoBlockReporter
+{
+public:
+
+ CAutoBlockReporter( CBaseFileSystem *fs, bool synchronous, char const *filename, int eBlockType, int nTypeOfAccess ) :
+ m_pFS( fs ),
+ m_Item( eBlockType, filename, 0.0f, nTypeOfAccess ),
+ m_bSynchronous( synchronous )
+ {
+ Assert( m_pFS );
+ m_Timer.Start();
+ }
+
+ CAutoBlockReporter( CBaseFileSystem *fs, bool synchronous, FileHandle_t handle, int eBlockType, int nTypeOfAccess ) :
+ m_pFS( fs ),
+ m_Item( eBlockType, NULL, 0.0f, nTypeOfAccess ),
+ m_bSynchronous( synchronous )
+ {
+ Assert( m_pFS );
+ char name[ 512 ];
+ m_pFS->GetFileNameForHandle( handle, name, sizeof( name ) );
+ m_Item.SetFileName( name );
+ m_Timer.Start();
+ }
+
+ ~CAutoBlockReporter()
+ {
+ m_Timer.End();
+ m_Item.m_flElapsed = m_Timer.GetDuration().GetSeconds();
+ m_pFS->RecordBlockingFileAccess( m_bSynchronous, m_Item );
+ }
+
+private:
+
+ CBaseFileSystem *m_pFS;
+
+ CFastTimer m_Timer;
+ FileBlockingItem m_Item;
+ bool m_bSynchronous;
+};
+
+#define AUTOBLOCKREPORTER_FN( name, fs, sync, filename, blockType, accessType ) CAutoBlockReporter block##name( fs, sync, filename, blockType, accessType );
+#define AUTOBLOCKREPORTER_FH( name, fs, sync, handle, blockType, accessType ) CAutoBlockReporter block##name( fs, sync, handle, blockType, accessType );
+
+#else
+
+#define AUTOBLOCKREPORTER_FN( name, fs, sync, filename, blockType, accessType ) // Nothing
+#define AUTOBLOCKREPORTER_FH( name, fs, sync, handle , blockType, accessType ) // Nothing
+
+#endif
+
+// singleton accessor
+CBaseFileSystem *BaseFileSystem();
+
+#include "tier0/memdbgoff.h"
+
+#endif // BASEFILESYSTEM_H