This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

1139 lines
46 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#pragma once
#include <limits.h>
#include "appframework/IAppSystem.h"
#include "tier0/memalloc.h"
#include "tier0/threadtools.h"
#include "tier1/checksum_crc.h"
#include "tier1/checksum_md5.h"
#include "tier1/interface.h"
#include "tier1/refcount.h"
#include "tier1/utlstring.h"
#include "tier1/utlsymbol.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 <size_t maxLenInChars>
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 <size_t maxLenInChars>
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 <size_t maxLenInChars>
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 <size_t maxLenInChars>
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 <size_t maxLenInChars>
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 <size_t maxLenInChars>
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<CRefCountServiceMT> {
public:
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);
}
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