//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //===========================================================================// #ifndef FILESYSTEM_H #define FILESYSTEM_H #pragma once #include #include "tier0/threadtools.h" #include "tier0/memalloc.h" #include "tier1/interface.h" #include "tier1/utlsymbol.h" #include "tier1/utlstring.h" #include "appframework/IAppSystem.h" #include "tier1/checksum_crc.h" #include "tier1/checksum_md5.h" #include "tier1/refcount.h" #ifdef _WIN32 #pragma once #endif //----------------------------------------------------------------------------- // Forward declarations //----------------------------------------------------------------------------- class CUtlBuffer; class KeyValues; class IFileList; class IThreadPool; class CMemoryFileBacking; typedef void * FileHandle_t; typedef void * FileCacheHandle_t; typedef int FileFindHandle_t; typedef void (*FileSystemLoggingFunc_t)( const char *fileName, const char *accessType ); typedef int WaitForResourcesHandle_t; #ifdef _X360 typedef void* HANDLE; #endif #define USE_CRC_FILE_TRACKING 0 // Turn on some extra pure server debug spew in certain builds. // WARNING: This spew can be used by hackers to locate places to hack // the code to bypas sv_pure! Be careful! #if defined( _DEBUG ) || defined( STAGING_ONLY ) #define PURE_SERVER_DEBUG_SPEW #endif /// How strict will the pure server be for a particular set of files enum EPureServerFileClass { ePureServerFileClass_Unknown = -1, // dummy debugging value ePureServerFileClass_Any = 0, ePureServerFileClass_AnyTrusted, ePureServerFileClass_CheckHash, }; class IPureServerWhitelist { public: // Reference counting virtual void AddRef() = 0; virtual void Release() = 0; // What should we do with a particular file? virtual EPureServerFileClass GetFileClass( const char *pszFilename ) = 0; // Access list of trusted keys which we will allow to set trusted content virtual int GetTrustedKeyCount() const = 0; virtual const byte *GetTrustedKey( int iKeyIndex, int *nKeySize ) const = 0; }; //----------------------------------------------------------------------------- // Enums used by the interface //----------------------------------------------------------------------------- #define FILESYSTEM_MAX_SEARCH_PATHS 128 enum FileSystemSeek_t { FILESYSTEM_SEEK_HEAD = SEEK_SET, FILESYSTEM_SEEK_CURRENT = SEEK_CUR, FILESYSTEM_SEEK_TAIL = SEEK_END, }; enum { FILESYSTEM_INVALID_FIND_HANDLE = -1 }; enum FileWarningLevel_t { // A problem! FILESYSTEM_WARNING = -1, // Don't print anything FILESYSTEM_WARNING_QUIET = 0, // On shutdown, report names of files left unclosed FILESYSTEM_WARNING_REPORTUNCLOSED, // Report number of times a file was opened, closed FILESYSTEM_WARNING_REPORTUSAGE, // Report all open/close events to console ( !slow! ) FILESYSTEM_WARNING_REPORTALLACCESSES, // Report all open/close/read events to the console ( !slower! ) FILESYSTEM_WARNING_REPORTALLACCESSES_READ, // Report all open/close/read/write events to the console ( !slower! ) FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, // Report all open/close/read/write events and all async I/O file events to the console ( !slower(est)! ) FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC, }; // search path filtering enum PathTypeFilter_t { FILTER_NONE = 0, // no filtering, all search path types match FILTER_CULLPACK = 1, // pack based search paths are culled (maps and zips) FILTER_CULLNONPACK = 2, // non-pack based search paths are culled }; // search path querying (bit flags) enum { PATH_IS_NORMAL = 0x00, // normal path, not pack based PATH_IS_PACKFILE = 0x01, // path is a pack file PATH_IS_MAPPACKFILE = 0x02, // path is a map pack file PATH_IS_REMOTE = 0x04, // path is the remote filesystem }; typedef uint32 PathTypeQuery_t; #define IS_PACKFILE( n ) ( n & ( PATH_IS_PACKFILE | PATH_IS_MAPPACKFILE ) ) #define IS_REMOTE( n ) ( n & PATH_IS_REMOTE ) enum DVDMode_t { DVDMODE_OFF = 0, // not using dvd DVDMODE_STRICT = 1, // dvd device only DVDMODE_DEV = 2, // dev mode, mutiple devices ok }; // In non-retail builds, enable the file blocking access tracking stuff... #if defined( TRACK_BLOCKING_IO ) enum FileBlockingWarning_t { // Report how long synchronous i/o took to complete FILESYSTEM_BLOCKING_SYNCHRONOUS = 0, // Report how long async i/o took to complete if AsyncFileFinished caused it to load via "blocking" i/o FILESYSTEM_BLOCKING_ASYNCHRONOUS_BLOCK, // Report how long async i/o took to complete FILESYSTEM_BLOCKING_ASYNCHRONOUS, // Report how long the async "callback" took FILESYSTEM_BLOCKING_CALLBACKTIMING, FILESYSTEM_BLOCKING_NUMBINS, }; #pragma pack(1) class FileBlockingItem { public: enum { FB_ACCESS_OPEN = 1, FB_ACCESS_CLOSE = 2, FB_ACCESS_READ = 3, FB_ACCESS_WRITE = 4, FB_ACCESS_APPEND = 5, FB_ACCESS_SIZE = 6 }; FileBlockingItem() : m_ItemType( (FileBlockingWarning_t)0 ), m_flElapsed( 0.0f ), m_nAccessType( 0 ) { SetFileName( NULL ); } FileBlockingItem( int type, char const *filename, float elapsed, int accessType ) : m_ItemType( (FileBlockingWarning_t)type ), m_flElapsed( elapsed ), m_nAccessType( accessType ) { SetFileName( filename ); } void SetFileName( char const *filename ) { if ( !filename ) { m_szFilename[ 0 ] = 0; return; } int len = Q_strlen( filename ); if ( len >= sizeof( m_szFilename ) ) { Q_strncpy( m_szFilename, &filename[ len - sizeof( m_szFilename ) + 1 ], sizeof( m_szFilename ) ); } else { Q_strncpy( m_szFilename, filename, sizeof( m_szFilename ) ); } } char const *GetFileName() const { return m_szFilename; } FileBlockingWarning_t m_ItemType; float m_flElapsed; byte m_nAccessType; private: char m_szFilename[ 32 ]; }; #pragma pack() class IBlockingFileItemList { public: // You can't call any of the below calls without locking first virtual void LockMutex() = 0; virtual void UnlockMutex() = 0; virtual int First() const = 0; virtual int Next( int i ) const = 0; virtual int InvalidIndex() const = 0; virtual const FileBlockingItem& Get( int index ) const = 0; virtual void Reset() = 0; }; #endif // TRACK_BLOCKING_IO enum FilesystemMountRetval_t { FILESYSTEM_MOUNT_OK = 0, FILESYSTEM_MOUNT_FAILED, }; enum SearchPathAdd_t { PATH_ADD_TO_HEAD, // First path searched PATH_ADD_TO_TAIL, // Last path searched }; enum FilesystemOpenExFlags_t { FSOPEN_UNBUFFERED = (1 << 0), FSOPEN_FORCE_TRACK_CRC = (1 << 1), // This makes it calculate a CRC for the file (if the file came from disk) regardless // of the IFileList passed to RegisterFileWhitelist. FSOPEN_NEVERINPACK = (1 << 2), // 360 only, hint to FS that file is not allowed to be in pack file }; #define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 //----------------------------------------------------------------------------- // Structures used by the interface //----------------------------------------------------------------------------- struct FileSystemStatistics { CInterlockedUInt nReads, nWrites, nBytesRead, nBytesWritten, nSeeks; }; //----------------------------------------------------------------------------- // File system allocation functions. Client must free on failure //----------------------------------------------------------------------------- typedef void *(*FSAllocFunc_t)( const char *pszFilename, unsigned nBytes ); //----------------------------------------------------------------------------- // Used to display dirty disk error functions //----------------------------------------------------------------------------- typedef void (*FSDirtyDiskReportFunc_t)(); //----------------------------------------------------------------------------- // Asynchronous support types //----------------------------------------------------------------------------- DECLARE_POINTER_HANDLE(FSAsyncControl_t); DECLARE_POINTER_HANDLE(FSAsyncFile_t); const FSAsyncFile_t FS_INVALID_ASYNC_FILE = (FSAsyncFile_t)(0x0000ffff); //--------------------------------------------------------- // Async file status //--------------------------------------------------------- enum FSAsyncStatus_t { FSASYNC_ERR_NOT_MINE = -8, // Filename not part of the specified file system, try a different one. (Used internally to find the right filesystem) FSASYNC_ERR_RETRY_LATER = -7, // Failure for a reason that might be temporary. You might retry, but not immediately. (E.g. Network problems) FSASYNC_ERR_ALIGNMENT = -6, // read parameters invalid for unbuffered IO FSASYNC_ERR_FAILURE = -5, // hard subsystem failure FSASYNC_ERR_READING = -4, // read error on file FSASYNC_ERR_NOMEMORY = -3, // out of memory for file read FSASYNC_ERR_UNKNOWNID = -2, // caller's provided id is not recognized FSASYNC_ERR_FILEOPEN = -1, // filename could not be opened (bad path, not exist, etc) FSASYNC_OK = 0, // operation is successful FSASYNC_STATUS_PENDING, // file is properly queued, waiting for service FSASYNC_STATUS_INPROGRESS, // file is being accessed FSASYNC_STATUS_ABORTED, // file was aborted by caller FSASYNC_STATUS_UNSERVICED, // file is not yet queued }; //--------------------------------------------------------- // Async request flags //--------------------------------------------------------- enum FSAsyncFlags_t { FSASYNC_FLAGS_ALLOCNOFREE = ( 1 << 0 ), // do the allocation for dataPtr, but don't free FSASYNC_FLAGS_FREEDATAPTR = ( 1 << 1 ), // free the memory for the dataPtr post callback FSASYNC_FLAGS_SYNC = ( 1 << 2 ), // Actually perform the operation synchronously. Used to simplify client code paths FSASYNC_FLAGS_NULLTERMINATE = ( 1 << 3 ), // allocate an extra byte and null terminate the buffer read in }; //--------------------------------------------------------- // Return value for CheckFileCRC. //--------------------------------------------------------- enum EFileCRCStatus { k_eFileCRCStatus_CantOpenFile, // We don't have this file. k_eFileCRCStatus_GotCRC, k_eFileCRCStatus_FileInVPK }; // Used in CacheFileCRCs. enum ECacheCRCType { k_eCacheCRCType_SingleFile, k_eCacheCRCType_Directory, k_eCacheCRCType_Directory_Recursive }; //--------------------------------------------------------- // Optional completion callback for each async file serviced (or failed) // call is not reentrant, async i/o guaranteed suspended until return // Note: If you change the signature of the callback, you will have to account for it in FileSystemV12 (toml [4/18/2005] ) //--------------------------------------------------------- struct FileAsyncRequest_t; typedef void (*FSAsyncCallbackFunc_t)(const FileAsyncRequest_t &request, int nBytesRead, FSAsyncStatus_t err); //--------------------------------------------------------- // Description of an async request //--------------------------------------------------------- struct FileAsyncRequest_t { FileAsyncRequest_t() { memset( this, 0, sizeof(*this) ); hSpecificAsyncFile = FS_INVALID_ASYNC_FILE; } const char * pszFilename; // file system name void * pData; // optional, system will alloc/free if NULL int nOffset; // optional initial seek_set, 0=beginning int nBytes; // optional read clamp, -1=exist test, 0=full read FSAsyncCallbackFunc_t pfnCallback; // optional completion callback void * pContext; // caller's unique file identifier int priority; // inter list priority, 0=lowest unsigned flags; // behavior modifier const char * pszPathID; // path ID (NOTE: this field is here to remain binary compatible with release HL2 filesystem interface) FSAsyncFile_t hSpecificAsyncFile; // Optional hint obtained using AsyncBeginRead() FSAllocFunc_t pfnAlloc; // custom allocator. can be null. not compatible with FSASYNC_FLAGS_FREEDATAPTR }; struct FileHash_t { enum EFileHashType_t { k_EFileHashTypeUnknown = 0, k_EFileHashTypeEntireFile = 1, k_EFileHashTypeIncompleteFile = 2, }; FileHash_t() { m_eFileHashType = FileHash_t::k_EFileHashTypeUnknown; m_cbFileLen = 0; m_PackFileID = 0; m_nPackFileNumber = 0; } int m_eFileHashType; CRC32_t m_crcIOSequence; MD5Value_t m_md5contents; int m_cbFileLen; int m_PackFileID; int m_nPackFileNumber; bool operator==( const FileHash_t &src ) const { return m_crcIOSequence == src.m_crcIOSequence && m_md5contents == src.m_md5contents && m_eFileHashType == src.m_eFileHashType; } bool operator!=( const FileHash_t &src ) const { return m_crcIOSequence != src.m_crcIOSequence || m_md5contents != src.m_md5contents || m_eFileHashType != src.m_eFileHashType; } }; class CUnverifiedFileHash { public: char m_PathID[MAX_PATH]; char m_Filename[MAX_PATH]; int m_nFileFraction; FileHash_t m_FileHash; }; class CUnverifiedCRCFile { public: char m_PathID[MAX_PATH]; char m_Filename[MAX_PATH]; CRC32_t m_CRC; }; class CUnverifiedMD5File { public: char m_PathID[MAX_PATH]; char m_Filename[MAX_PATH]; unsigned char bits[MD5_DIGEST_LENGTH]; }; // Spew flags for SetWhitelistSpewFlags (set with the fs_whitelist_spew_flags cvar). // Update the comment for the fs_whitelist_spew_flags cvar if you change these. #define WHITELIST_SPEW_WHILE_LOADING 0x0001 // list files as they are added to the CRC tracker #define WHITELIST_SPEW_RELOAD_FILES 0x0002 // show files the filesystem is telling the engine to reload #define WHITELIST_SPEW_DONT_RELOAD_FILES 0x0004 // show files the filesystem is NOT telling the engine to reload //----------------------------------------------------------------------------- // Interface to fetch a file asynchronously from any source. This is used // as a hook //----------------------------------------------------------------------------- abstract_class IAsyncFileFetch { public: typedef void *Handle; /// Initiate a request. Returns error status, or on success /// returns an opaque handle used to terminate the job /// /// Should return FSASYNC_ERR_NOT_MINE if the filename isn't /// handled by this interface /// /// The callback is required, and is the only mechanism to communicate /// status. (No polling.) The request is automatically destroyed anytime /// after the callback is executed. virtual FSAsyncStatus_t Start( const FileAsyncRequest_t &request, Handle *pOutHandle, IThreadPool *pThreadPool ) = 0; /// Attempt to complete any active work, returning status. The callback WILL /// be executed (this is necessary in case we allocated the buffer). /// Afterwards, the request is automatically destroyed. virtual FSAsyncStatus_t FinishSynchronous( Handle hControl ) = 0; /// Terminate any active work and destroy all resources and bookkeeping info. /// The callback will NOT be executed. virtual FSAsyncStatus_t Abort( Handle hControl ) = 0; }; // This interface is for VPK files to communicate with FileTracker abstract_class IThreadedFileMD5Processor { public: virtual int SubmitThreadedMD5Request( uint8 *pubBuffer, int cubBuffer, int PackFileID, int nPackFileNumber, int nPackFileFraction ) = 0; virtual bool BlockUntilMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut ) = 0; virtual bool IsMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut ) = 0; }; //----------------------------------------------------------------------------- // Base file system interface //----------------------------------------------------------------------------- // This is the minimal interface that can be implemented to provide access to // a named set of files. #define BASEFILESYSTEM_INTERFACE_VERSION "VBaseFileSystem011" abstract_class IBaseFileSystem { public: virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; // if pathID is NULL, all paths will be searched for the file virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = 0 ) = 0; virtual void Close( FileHandle_t file ) = 0; virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; virtual unsigned int Tell( FileHandle_t file ) = 0; virtual unsigned int Size( FileHandle_t file ) = 0; virtual unsigned int Size( const char *pFileName, const char *pPathID = 0 ) = 0; virtual void Flush( FileHandle_t file ) = 0; virtual bool Precache( const char *pFileName, const char *pPathID = 0 ) = 0; virtual bool FileExists( const char *pFileName, const char *pPathID = 0 ) = 0; virtual bool IsFileWritable( char const *pFileName, const char *pPathID = 0 ) = 0; virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID = 0 ) = 0; virtual long GetFileTime( const char *pFileName, const char *pPathID = 0 ) = 0; //-------------------------------------------------------- // Reads/writes files to utlbuffers. Use this for optimal read performance when doing open/read/close //-------------------------------------------------------- virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf ) = 0; virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination ) = 0; }; //----------------------------------------------------------------------------- // Main file system interface //----------------------------------------------------------------------------- #define FILESYSTEM_INTERFACE_VERSION "VFileSystem022" abstract_class IFileSystem : public IAppSystem, public IBaseFileSystem { public: //-------------------------------------------------------- // Steam operations //-------------------------------------------------------- virtual bool IsSteam() const = 0; // Supplying an extra app id will mount this app in addition // to the one specified in the environment variable "steamappid" // // If nExtraAppId is < -1, then it will mount that app ID only. // (Was needed by the dedicated server b/c the "SteamAppId" env var only gets passed to steam.dll // at load time, so the dedicated couldn't pass it in that way). virtual FilesystemMountRetval_t MountSteamContent( int nExtraAppId = -1 ) = 0; //-------------------------------------------------------- // Search path manipulation //-------------------------------------------------------- // Add paths in priority order (mod dir, game dir, ....) // If one or more .pak files are in the specified directory, then they are // added after the file system path // If the path is the relative path to a .bsp file, then any previous .bsp file // override is cleared and the current .bsp is searched for an embedded PAK file // and this file becomes the highest priority search path ( i.e., it's looked at first // even before the mod's file system path ). virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType = PATH_ADD_TO_TAIL ) = 0; virtual bool RemoveSearchPath( const char *pPath, const char *pathID = 0 ) = 0; // Remove all search paths (including write path?) virtual void RemoveAllSearchPaths( void ) = 0; // Remove search paths associated with a given pathID virtual void RemoveSearchPaths( const char *szPathID ) = 0; // This is for optimization. If you mark a path ID as "by request only", then files inside it // will only be accessed if the path ID is specifically requested. Otherwise, it will be ignored. // If there are currently no search paths with the specified path ID, then it will still // remember it in case you add search paths with this path ID. virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly ) = 0; // converts a partial path into a full path // Prefer using the RelativePathToFullPath_safe template wrapper to calling this directly 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 ) = 0; template const char *RelativePathToFullPath_safe( const char *pFileName, const char *pPathID, OUT_Z_ARRAY char (&pDest)[maxLenInChars], PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL ) { return RelativePathToFullPath( pFileName, pPathID, pDest, (int)maxLenInChars, pathFilter, pPathType ); } // Returns the search path, each path is separated by ;s. Returns the length of the string returned // Prefer using the GetSearchPath_safe template wrapper to calling this directly virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; template int GetSearchPath_safe( const char *pathID, bool bGetPackFiles, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) { return GetSearchPath( pathID, bGetPackFiles, pDest, (int)maxLenInChars ); } // interface for custom pack files > 4Gb virtual bool AddPackFile( const char *fullpath, const char *pathID ) = 0; //-------------------------------------------------------- // File manipulation operations //-------------------------------------------------------- // Deletes a file (on the WritePath) virtual void RemoveFile( char const* pRelativePath, const char *pathID = 0 ) = 0; // Renames a file (on the WritePath) virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID = 0 ) = 0; // create a local directory structure virtual void CreateDirHierarchy( const char *path, const char *pathID = 0 ) = 0; // File I/O and info virtual bool IsDirectory( const char *pFileName, const char *pathID = 0 ) = 0; virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) = 0; //-------------------------------------------------------- // Open file operations //-------------------------------------------------------- virtual void SetBufferSize( FileHandle_t file, unsigned nBytes ) = 0; virtual bool IsOk( FileHandle_t file ) = 0; virtual bool EndOfFile( FileHandle_t file ) = 0; virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) = 0; virtual int FPrintf( FileHandle_t file, PRINTF_FORMAT_STRING const char *pFormat, ... ) = 0; //-------------------------------------------------------- // Dynamic library operations //-------------------------------------------------------- // load/unload modules virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID = 0, bool bValidatedDllOnly = true ) = 0; virtual void UnloadModule( CSysModule *pModule ) = 0; //-------------------------------------------------------- // File searching operations //-------------------------------------------------------- // FindFirst/FindNext. Also see FindFirstEx. virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle ) = 0; virtual const char *FindNext( FileFindHandle_t handle ) = 0; virtual bool FindIsDirectory( FileFindHandle_t handle ) = 0; virtual void FindClose( FileFindHandle_t handle ) = 0; // Same as FindFirst, but you can filter by path ID, which can make it faster. virtual const char *FindFirstEx( const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle ) = 0; //-------------------------------------------------------- // File name and directory operations //-------------------------------------------------------- // FIXME: This method is obsolete! Use RelativePathToFullPath instead! // converts a partial path into a full path // Prefer using the GetLocalPath_safe template wrapper to calling this directly virtual const char *GetLocalPath( const char *pFileName, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; template const char *GetLocalPath_safe( const char *pFileName, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) { return GetLocalPath( pFileName, pDest, (int)maxLenInChars ); } // Returns true on success ( based on current list of search paths, otherwise false if // it can't be resolved ) // Prefer using the FullPathToRelativePath_safe template wrapper to calling this directly virtual bool FullPathToRelativePath( const char *pFullpath, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; template bool FullPathToRelativePath_safe( const char *pFullpath, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) { return FullPathToRelativePath( pFullpath, pDest, (int)maxLenInChars ); } // Gets the current working directory virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) = 0; //-------------------------------------------------------- // Filename dictionary operations //-------------------------------------------------------- virtual FileNameHandle_t FindOrAddFileName( char const *pFileName ) = 0; virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen ) = 0; //-------------------------------------------------------- // Asynchronous file operations //-------------------------------------------------------- //------------------------------------ // Global operations //------------------------------------ FSAsyncStatus_t AsyncRead( const FileAsyncRequest_t &request, FSAsyncControl_t *phControl = NULL ) { return AsyncReadMultiple( &request, 1, phControl ); } virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *phControls = NULL ) = 0; virtual FSAsyncStatus_t AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl = NULL ) = 0; virtual FSAsyncStatus_t AsyncAppendFile(const char *pAppendToFileName, const char *pAppendFromFileName, FSAsyncControl_t *pControl = NULL ) = 0; virtual void AsyncFinishAll( int iToPriority = 0 ) = 0; virtual void AsyncFinishAllWrites() = 0; virtual FSAsyncStatus_t AsyncFlush() = 0; virtual bool AsyncSuspend() = 0; virtual bool AsyncResume() = 0; /// Add async fetcher interface. This gives apps a hook to intercept async requests and /// pull the data from a source of their choosing. The immediate use case is to load /// assets from the CDN via HTTP. virtual void AsyncAddFetcher( IAsyncFileFetch *pFetcher ) = 0; virtual void AsyncRemoveFetcher( IAsyncFileFetch *pFetcher ) = 0; //------------------------------------ // Functions to hold a file open if planning on doing mutiple reads. Use is optional, // and is taken only as a hint //------------------------------------ virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile ) = 0; virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile ) = 0; //------------------------------------ // Request management //------------------------------------ virtual FSAsyncStatus_t AsyncFinish( FSAsyncControl_t hControl, bool wait = true ) = 0; virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize ) = 0; virtual FSAsyncStatus_t AsyncAbort( FSAsyncControl_t hControl ) = 0; virtual FSAsyncStatus_t AsyncStatus( FSAsyncControl_t hControl ) = 0; // set a new priority for a file already in the queue virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) = 0; virtual void AsyncAddRef( FSAsyncControl_t hControl ) = 0; virtual void AsyncRelease( FSAsyncControl_t hControl ) = 0; //-------------------------------------------------------- // Remote resource management //-------------------------------------------------------- // starts waiting for resources to be available // returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) = 0; // get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done // returns false if no progress is available // any calls after complete is true or on an invalid handle will return false, 0.0f, true virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */ ) = 0; // cancels a progress call virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) = 0; // hints that a set of files will be loaded in near future // HintResourceNeed() is not to be confused with resource precaching. virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) = 0; // returns true if a file is on disk virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0; // copies file out of pak/bsp/steam cache onto disk (to be accessible by third-party code) virtual void GetLocalCopy( const char *pFileName ) = 0; //-------------------------------------------------------- // Debugging operations //-------------------------------------------------------- // Dump to printf/OutputDebugString the list of files that have not been closed virtual void PrintOpenedFiles( void ) = 0; virtual void PrintSearchPaths( void ) = 0; // output virtual void SetWarningFunc( void (*pfnWarning)( PRINTF_FORMAT_STRING const char *fmt, ... ) ) = 0; virtual void SetWarningLevel( FileWarningLevel_t level ) = 0; virtual void AddLoggingFunc( void (*pfnLogFunc)( const char *fileName, const char *accessType ) ) = 0; virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc ) = 0; // Returns the file system statistics retreived by the implementation. Returns NULL if not supported. virtual const FileSystemStatistics *GetFilesystemStatistics() = 0; //-------------------------------------------------------- // Start of new functions after Lost Coast release (7/05) //-------------------------------------------------------- virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL ) = 0; // Extended version of read provides more context to allow for more optimal reading virtual int ReadEx( void* pOutput, int sizeDest, int size, FileHandle_t file ) = 0; virtual int ReadFileEx( const char *pFileName, const char *pPath, void **ppBuf, bool bNullTerminate = false, bool bOptimalAlloc = false, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; virtual FileNameHandle_t FindFileName( char const *pFileName ) = 0; #if defined( TRACK_BLOCKING_IO ) virtual void EnableBlockingFileAccessTracking( bool state ) = 0; virtual bool IsBlockingFileAccessEnabled() const = 0; virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo() = 0; #endif virtual void SetupPreloadData() = 0; virtual void DiscardPreloadData() = 0; // Fixme, we could do these via a string embedded into the compiled data, etc... enum KeyValuesPreloadType_t { TYPE_VMT, TYPE_SOUNDEMITTER, TYPE_SOUNDSCAPE, NUM_PRELOAD_TYPES }; virtual void LoadCompiledKeyValues( KeyValuesPreloadType_t type, char const *archiveFile ) = 0; // 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 ) = 0; virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) = 0; virtual bool ExtractRootKeyName( KeyValuesPreloadType_t type, char *outbuf, size_t bufsize, char const *filename, char const *pPathID = 0 ) = 0; virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t *pControl = NULL ) = 0; virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t *pControl = NULL ) = 0; // Async read functions with memory blame FSAsyncStatus_t AsyncReadCreditAlloc( const FileAsyncRequest_t &request, const char *pszFile, int line, FSAsyncControl_t *phControl = NULL ) { return AsyncReadMultipleCreditAlloc( &request, 1, pszFile, line, phControl ); } virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *phControls = NULL ) = 0; virtual bool GetFileTypeForFullPath( char const *pFullPath, OUT_Z_BYTECAP(bufSizeInBytes) wchar_t *buf, size_t bufSizeInBytes ) = 0; //-------------------------------------------------------- //-------------------------------------------------------- virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; //-------------------------------------------------------- // Optimal IO operations //-------------------------------------------------------- virtual bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign ) = 0; inline unsigned GetOptimalReadSize( FileHandle_t hFile, unsigned nLogicalSize ); virtual void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize = 0, unsigned nOffset = 0 ) = 0; virtual void FreeOptimalReadBuffer( void * ) = 0; //-------------------------------------------------------- // //-------------------------------------------------------- virtual void BeginMapAccess() = 0; virtual void EndMapAccess() = 0; // Returns true on success, otherwise false if it can't be resolved // Prefer using the FullPathToRelativePathEx_safe template wrapper to calling this directly virtual bool FullPathToRelativePathEx( const char *pFullpath, const char *pPathId, OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars ) = 0; template bool FullPathToRelativePathEx_safe( const char *pFullpath, OUT_Z_ARRAY char (&pDest)[maxLenInChars] ) { return FullPathToRelativePathEx( pFullpath, pDest, (int)maxLenInChars ); } virtual int GetPathIndex( const FileNameHandle_t &handle ) = 0; virtual long GetPathTime( const char *pPath, const char *pPathID ) = 0; virtual DVDMode_t GetDVDMode() = 0; //-------------------------------------------------------- // Whitelisting for pure servers. //-------------------------------------------------------- // This should be called ONCE at startup. Multiplayer games (gameinfo.txt does not contain singleplayer_only) // want to enable this so sv_pure works. virtual void EnableWhitelistFileTracking( bool bEnable, bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes ) = 0; // This is called when the client connects to a server using a pure_server_whitelist.txt file. virtual void RegisterFileWhitelist( IPureServerWhitelist *pWhiteList, IFileList **pFilesToReload ) = 0; // Called when the client logs onto a server. Any files that came off disk should be marked as // unverified because this server may have a different set of files it wants to guarantee. virtual void MarkAllCRCsUnverified() = 0; // As the server loads whitelists when it transitions maps, it calls this to calculate CRCs for any files marked // with check_crc. Then it calls CheckCachedFileCRC later when it gets client requests to verify CRCs. virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter ) = 0; virtual EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash ) = 0; // Fills in the list of files that have been loaded off disk and have not been verified. // Returns the number of files filled in (between 0 and nMaxFiles). // // This also removes any files it's returning from the unverified CRC list, so they won't be // returned from here again. // The client sends batches of these to the server to verify. virtual int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles ) = 0; // Control debug message output. // Pass a combination of WHITELIST_SPEW_ flags. virtual int GetWhitelistSpewFlags() = 0; virtual void SetWhitelistSpewFlags( int flags ) = 0; // Installs a callback used to display a dirty disk dialog virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func ) = 0; //-------------------------------------------------------- // Low-level file caching. Cached files are loaded into memory and used // to satisfy read requests (sync and async) until the cache is destroyed. // NOTE: this could defeat file whitelisting, if a file were loaded in // a non-whitelisted environment and then reused. Clients should not cache // files across moves between pure/non-pure environments. //-------------------------------------------------------- virtual FileCacheHandle_t CreateFileCache() = 0; virtual void AddFilesToFileCache( FileCacheHandle_t cacheId, const char **ppFileNames, int nFileNames, const char *pPathID ) = 0; virtual bool IsFileCacheFileLoaded( FileCacheHandle_t cacheId, const char* pFileName ) = 0; virtual bool IsFileCacheLoaded( FileCacheHandle_t cacheId ) = 0; virtual void DestroyFileCache( FileCacheHandle_t cacheId ) = 0; // 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 ) = 0; // Unregister a CMemoryFileBacking; must balance with RegisterMemoryFile. virtual void UnregisterMemoryFile( CMemoryFileBacking *pFile ) = 0; virtual void CacheAllVPKFileHashes( bool bCacheAllVPKHashes, bool bRecalculateAndCheckHashes ) = 0; virtual bool CheckVPKFileHash( int PackFileID, int nPackFileNumber, int nFileFraction, MD5Value_t &md5Value ) = 0; // Called when we unload a file, to remove that file's info for pure server purposes. virtual void NotifyFileUnloaded( const char *pszFilename, const char *pPathId ) = 0; // Returns true on successfully retrieve case-sensitive full path, otherwise false // Prefer using the GetCaseCorrectFullPath template wrapper to calling this directly virtual bool GetCaseCorrectFullPath_Ptr( const char *pFullPath, OUT_Z_CAP( maxLenInChars ) char *pDest, int maxLenInChars ) = 0; template bool GetCaseCorrectFullPath( const char *pFullPath, OUT_Z_ARRAY char( &pDest )[maxLenInChars] ) { return GetCaseCorrectFullPath_Ptr( pFullPath, pDest, (int)maxLenInChars ); } }; //----------------------------------------------------------------------------- // Memory file backing, which you can use to fake out the filesystem, caching data // in memory and have it associated with a file //----------------------------------------------------------------------------- class CMemoryFileBacking : public CRefCounted { public: // malloc and free in headers with our janky memdbg system. What could go wrong. Except everything. // (this free can't skip memdbg if paired malloc used memdbg) #include CMemoryFileBacking( IFileSystem* pFS ) : m_pFS( pFS ), m_nRegistered( 0 ), m_pFileName( NULL ), m_pData( NULL ), m_nLength( 0 ) { } ~CMemoryFileBacking() { free( (char*) m_pFileName ); if ( m_pData ) m_pFS->FreeOptimalReadBuffer( (char*) m_pData ); } #include IFileSystem* m_pFS; int m_nRegistered; const char* m_pFileName; const char* m_pData; int m_nLength; private: CMemoryFileBacking( const CMemoryFileBacking& ); // not defined CMemoryFileBacking& operator=( const CMemoryFileBacking& ); // not defined }; //----------------------------------------------------------------------------- #if defined( _X360 ) && !defined( _RETAIL ) extern char g_szXboxProfileLastFileOpened[MAX_PATH]; #define SetLastProfileFileRead( s ) Q_strncpy( g_szXboxProfileLastFileOpened, sizeof( g_szXboxProfileLastFileOpened), pFileName ) #define GetLastProfileFileRead() (&g_szXboxProfileLastFileOpened[0]) #else #define SetLastProfileFileRead( s ) ((void)0) #define GetLastProfileFileRead() NULL #endif #if defined( _X360 ) && defined( _BASETSD_H_ ) class CXboxDiskCacheSetter { public: CXboxDiskCacheSetter( SIZE_T newSize ) { m_oldSize = XGetFileCacheSize(); XSetFileCacheSize( newSize ); } ~CXboxDiskCacheSetter() { XSetFileCacheSize( m_oldSize ); } private: SIZE_T m_oldSize; }; #define DISK_INTENSIVE() CXboxDiskCacheSetter cacheSetter( 1024*1024 ) #else #define DISK_INTENSIVE() ((void)0) #endif //----------------------------------------------------------------------------- inline unsigned IFileSystem::GetOptimalReadSize( FileHandle_t hFile, unsigned nLogicalSize ) { unsigned align; if ( GetOptimalIOConstraints( hFile, &align, NULL, NULL ) ) return AlignValue( nLogicalSize, align ); else return nLogicalSize; } //----------------------------------------------------------------------------- // We include this here so it'll catch compile errors in VMPI early. #include "filesystem_passthru.h" //----------------------------------------------------------------------------- // Async memory tracking //----------------------------------------------------------------------------- #if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) #define AsyncRead( a, b ) AsyncReadCreditAlloc( a, __FILE__, __LINE__, b ) #define AsyncReadMutiple( a, b, c ) AsyncReadMultipleCreditAlloc( a, b, __FILE__, __LINE__, c ) #endif extern IFileSystem *g_pFullFileSystem; #endif // FILESYSTEM_H