uid issue
This commit is contained in:
532
filesystem/filesystem_stdio/FileTracker.cpp
Normal file
532
filesystem/filesystem_stdio/FileTracker.cpp
Normal file
@ -0,0 +1,532 @@
|
||||
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "basefilesystem.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
|
||||
bool CompareFilenames( const char *pa, const char *pb )
|
||||
{
|
||||
// Case-insensitive and path separator-insensitive compare.
|
||||
const char *a = pa;
|
||||
const char *b = pb;
|
||||
while ( *a && *b )
|
||||
{
|
||||
char ca = *a;
|
||||
char cb = *b;
|
||||
|
||||
if ( ca >= 'a' && ca <= 'z' )
|
||||
ca = 'A' + (ca - 'a');
|
||||
else if ( ca == '/' )
|
||||
ca = '\\';
|
||||
|
||||
if ( cb >= 'a' && cb <= 'z' )
|
||||
cb = 'A' + (cb - 'a');
|
||||
else if ( cb == '/' )
|
||||
cb = '\\';
|
||||
|
||||
if ( ca != cb )
|
||||
return false;
|
||||
|
||||
++a;
|
||||
++b;
|
||||
}
|
||||
|
||||
// Filenames also must be the same length.
|
||||
if ( *a != *b )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CFileTracker.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CFileTracker::CFileTracker( CBaseFileSystem *pFileSystem )
|
||||
{
|
||||
m_pFileSystem = pFileSystem;
|
||||
}
|
||||
|
||||
CFileTracker::~CFileTracker()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void CFileTracker::NoteFileLoadedFromDisk( const char *pFilename, const char *pPathID, FileHandle_t fp )
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
if ( !pPathID )
|
||||
pPathID = "";
|
||||
|
||||
CPathIDFileList *pPath = GetPathIDFileList( pPathID );
|
||||
CFileInfo *pInfo = pPath->FindFileInfo( pFilename );
|
||||
|
||||
if ( m_pFileSystem->m_WhitelistSpewFlags & WHITELIST_SPEW_WHILE_LOADING )
|
||||
{
|
||||
if ( pInfo )
|
||||
Warning( "(Duplicate): [%s]\\%s", pPathID, pFilename );
|
||||
else
|
||||
Warning( "(Unique ): [%s]\\%s", pPathID, pFilename );
|
||||
}
|
||||
|
||||
if ( pInfo )
|
||||
{
|
||||
// Clear all the flags, but remember if we ever had a CRC.
|
||||
pInfo->m_Flags &= k_eFileFlagsGotCRCOnce;
|
||||
pInfo->m_Flags &= ~k_eFileFlagsFailedToLoadLastTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
pInfo = pPath->AddFileInfo( pFilename );
|
||||
pInfo->m_Flags = (EFileFlags)0;
|
||||
}
|
||||
|
||||
if ( !fp )
|
||||
{
|
||||
if ( m_pFileSystem->m_WhitelistSpewFlags & WHITELIST_SPEW_WHILE_LOADING )
|
||||
{
|
||||
Warning( "\n" );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Remember that we calculated the CRC and that it is unverified.
|
||||
pInfo->m_CRC = CalculateCRCForFile( fp );
|
||||
pInfo->m_Flags |= k_eFileFlagsHasCRC | k_eFileFlagsGotCRCOnce;
|
||||
if ( pInfo->m_iNeedsVerificationListIndex == -1 )
|
||||
pInfo->m_iNeedsVerificationListIndex = m_NeedsVerificationList.AddToTail( pInfo );
|
||||
|
||||
if ( m_pFileSystem->m_WhitelistSpewFlags & WHITELIST_SPEW_WHILE_LOADING )
|
||||
{
|
||||
Warning( " - %u\n", pInfo->m_CRC );
|
||||
}
|
||||
}
|
||||
|
||||
void CFileTracker::NoteFileFailedToLoad( const char *pFilename, const char *pPathID )
|
||||
{
|
||||
CPathIDFileList *pPath = GetPathIDFileList( pPathID );
|
||||
CFileInfo *pInfo = pPath->FindFileInfo( pFilename );
|
||||
if ( pInfo )
|
||||
{
|
||||
pInfo->m_Flags |= k_eFileFlagsFailedToLoadLastTime;
|
||||
}
|
||||
}
|
||||
|
||||
CRC32_t CFileTracker::CalculateCRCForFile( FileHandle_t fp )
|
||||
{
|
||||
CRC32_t crc;
|
||||
|
||||
// Calculate the CRC.
|
||||
unsigned int initialFilePos = m_pFileSystem->Tell( fp );
|
||||
m_pFileSystem->Seek( fp, 0, FILESYSTEM_SEEK_HEAD );
|
||||
|
||||
#define CRC_CHUNK_SIZE (32*1024)
|
||||
char tempBuf[CRC_CHUNK_SIZE];
|
||||
|
||||
CRC32_Init( &crc );
|
||||
|
||||
unsigned int fileLength = m_pFileSystem->Size( fp );
|
||||
|
||||
int nChunks = fileLength / CRC_CHUNK_SIZE + 1;
|
||||
unsigned int curStartByte = 0;
|
||||
for ( int iChunk=0; iChunk < nChunks; iChunk++ )
|
||||
{
|
||||
int curEndByte = min( curStartByte + CRC_CHUNK_SIZE, fileLength );
|
||||
int chunkLen = curEndByte - curStartByte;
|
||||
if ( chunkLen == 0 )
|
||||
break;
|
||||
|
||||
m_pFileSystem->Read( tempBuf, chunkLen, fp ); // TODO: handle errors here..
|
||||
CRC32_ProcessBuffer( &crc, tempBuf, chunkLen );
|
||||
|
||||
curStartByte += CRC_CHUNK_SIZE;
|
||||
}
|
||||
CRC32_Final( &crc );
|
||||
|
||||
// Go back to where we started.
|
||||
m_pFileSystem->Seek( fp, initialFilePos, FILESYSTEM_SEEK_HEAD );
|
||||
return crc;
|
||||
}
|
||||
|
||||
CFileInfo* CFileTracker::GetFileInfo( const char *pFilename, const char *pPathID )
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
CPathIDFileList *pPath = GetPathIDFileList( pPathID, false );
|
||||
if ( !pPath )
|
||||
return NULL;
|
||||
|
||||
return pPath->FindFileInfo( pFilename );
|
||||
}
|
||||
|
||||
int CFileTracker::GetFileInfos( CFileInfo **ppFileInfos, int nMaxFileInfos, const char *pFilename )
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
int nOut = 0;
|
||||
for ( int i=m_PathIDs.First(); i != m_PathIDs.InvalidIndex(); i=m_PathIDs.Next( i ) )
|
||||
{
|
||||
CFileInfo *pCur = m_PathIDs[i]->FindFileInfo( pFilename );
|
||||
if ( pCur )
|
||||
{
|
||||
if ( nOut < nMaxFileInfos )
|
||||
{
|
||||
ppFileInfos[nOut++] = pCur;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( !"CFileTracker::GetFileInfos - overflowed list!" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nOut;
|
||||
}
|
||||
|
||||
void CFileTracker::NoteFileLoadedFromSteam( const char *pFilename, const char *pPathID, bool bForcedLoadFromSteam )
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
if ( !pPathID )
|
||||
pPathID = "";
|
||||
|
||||
CPathIDFileList *pPath = GetPathIDFileList( pPathID );
|
||||
CFileInfo *pInfo = pPath->FindFileInfo( pFilename );
|
||||
if ( !pInfo )
|
||||
pInfo = pPath->AddFileInfo( pFilename );
|
||||
|
||||
if ( m_pFileSystem->m_WhitelistSpewFlags & WHITELIST_SPEW_WHILE_LOADING )
|
||||
{
|
||||
Warning( "From Steam: [%s]\\%s\n", pPathID, pFilename );
|
||||
}
|
||||
|
||||
pInfo->m_Flags = k_eFileFlagsLoadedFromSteam;
|
||||
if ( bForcedLoadFromSteam )
|
||||
pInfo->m_Flags |= k_eFileFlagsForcedLoadFromSteam;
|
||||
}
|
||||
|
||||
|
||||
void CFileTracker::CalculateMissingCRCs( IFileList *pWantCRCList )
|
||||
{
|
||||
// First build a list of files that need a CRC and don't have one.
|
||||
m_Mutex.Lock();
|
||||
CUtlLinkedList<CFileInfo*,int> needCRCList;
|
||||
|
||||
for ( int i=m_PathIDs.First(); i != m_PathIDs.InvalidIndex(); i=m_PathIDs.Next( i ) )
|
||||
{
|
||||
CPathIDFileList *pPath = m_PathIDs[i];
|
||||
FOR_EACH_LL( pPath->m_Files, j )
|
||||
{
|
||||
CFileInfo *pInfo = pPath->m_Files[j];
|
||||
|
||||
if ( !( pInfo->m_Flags & k_eFileFlagsLoadedFromSteam ) && !( pInfo->m_Flags & k_eFileFlagsHasCRC ) )
|
||||
{
|
||||
// If the new "force match" list doesn't care whether the file has a CRC or not, then don't bother to calculate it.
|
||||
if ( !pWantCRCList->IsFileInList( pInfo->m_pFilename ) )
|
||||
continue;
|
||||
|
||||
needCRCList.AddToTail( pInfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Mutex.Unlock();
|
||||
|
||||
// Then, when the mutex is not locked, go generate the CRCs for them.
|
||||
FOR_EACH_LL( needCRCList, i )
|
||||
{
|
||||
CFileInfo *pInfo = needCRCList[i];
|
||||
CalculateMissingCRC( pInfo->m_pFilename, pInfo->GetPathIDString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CFileTracker::CacheFileCRC( const char *pPathID, const char *pRelativeFilename )
|
||||
{
|
||||
Assert( ThreadInMainThread() );
|
||||
|
||||
// Get the file's info. Load the file if necessary.
|
||||
CFileInfo *pInfo = GetFileInfo( pRelativeFilename, pPathID );
|
||||
if ( !pInfo )
|
||||
{
|
||||
CalculateMissingCRC( pRelativeFilename, pPathID );
|
||||
pInfo = GetFileInfo( pRelativeFilename, pPathID );
|
||||
}
|
||||
|
||||
if ( !pInfo )
|
||||
return;
|
||||
|
||||
// Already cached a CRC for this file?
|
||||
if ( !( pInfo->m_Flags & k_eFileFlagsGotCRCOnce ) )
|
||||
{
|
||||
// Ok, it's from disk but we don't have the CRC.
|
||||
CalculateMissingCRC( pInfo->GetFilename(), pInfo->GetPathIDString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CFileTracker::CacheFileCRC_Copy( const char *pPathID, const char *pRelativeFilename, const char *pPathIDToCopyFrom )
|
||||
{
|
||||
Assert( ThreadInMainThread() );
|
||||
|
||||
// Get the file's info. Load the file if necessary.
|
||||
CFileInfo *pSourceInfo = GetFileInfo( pRelativeFilename, pPathIDToCopyFrom );
|
||||
if ( !pSourceInfo || !( pSourceInfo->m_Flags & k_eFileFlagsGotCRCOnce ) )
|
||||
{
|
||||
// Strange, we don't have a CRC for the one they wanted to copy from, so calculate that CRC.
|
||||
CacheFileCRC( pPathIDToCopyFrom, pRelativeFilename );
|
||||
if ( !( pSourceInfo->m_Flags & k_eFileFlagsGotCRCOnce ) )
|
||||
{
|
||||
// Still didn't get it. Ok.. well get a CRC for the target one anyway.
|
||||
CacheFileCRC( pPathID, pRelativeFilename );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup a CFileInfo for the target..
|
||||
CPathIDFileList *pPath = GetPathIDFileList( pPathID );
|
||||
CFileInfo *pDestInfo = pPath->FindFileInfo( pRelativeFilename );
|
||||
if ( !pDestInfo )
|
||||
pDestInfo = pPath->AddFileInfo( pRelativeFilename );
|
||||
|
||||
pDestInfo->m_CRC = pSourceInfo->m_CRC;
|
||||
pDestInfo->m_Flags = pSourceInfo->m_Flags;
|
||||
}
|
||||
|
||||
|
||||
EFileCRCStatus CFileTracker::CheckCachedFileCRC( const char *pPathID, const char *pRelativeFilename, CRC32_t *pCRC )
|
||||
{
|
||||
Assert( ThreadInMainThread() );
|
||||
|
||||
// Get the file's info. Load the file if necessary.
|
||||
CFileInfo *pInfo = GetFileInfo( pRelativeFilename, pPathID );
|
||||
if ( pInfo && (pInfo->m_Flags & k_eFileFlagsGotCRCOnce) )
|
||||
{
|
||||
*pCRC = pInfo->m_CRC;
|
||||
return k_eFileCRCStatus_GotCRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return k_eFileCRCStatus_CantOpenFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CFileTracker::CalculateMissingCRC( const char *pFilename, const char *pPathID )
|
||||
{
|
||||
// Force it to make a CRC of disk files.
|
||||
FileHandle_t fh = m_pFileSystem->FindFileInSearchPaths( pFilename, "rb", pPathID, FSOPEN_FORCE_TRACK_CRC, NULL, true );
|
||||
if ( !fh )
|
||||
return;
|
||||
|
||||
CFileInfo *pInfo = GetFileInfo( pFilename, pPathID );
|
||||
if ( pInfo )
|
||||
{
|
||||
// Now we're about to modify the file itself.. lock the mutex.
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
// The FindFileInSearchPaths call might have done the CRC for us.
|
||||
if ( !( pInfo->m_Flags & k_eFileFlagsHasCRC ) )
|
||||
{
|
||||
pInfo->m_CRC = CalculateCRCForFile( fh );
|
||||
pInfo->m_Flags |= k_eFileFlagsHasCRC | k_eFileFlagsGotCRCOnce;
|
||||
if ( pInfo->m_iNeedsVerificationListIndex == -1 )
|
||||
{
|
||||
pInfo->m_iNeedsVerificationListIndex = m_NeedsVerificationList.AddToTail( pInfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
m_pFileSystem->Close( fh );
|
||||
}
|
||||
|
||||
|
||||
void CFileTracker::MarkAllCRCsUnverified()
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
// First clear the 'needs verification' list.
|
||||
MarkAllCRCsVerified();
|
||||
|
||||
Assert( m_NeedsVerificationList.Count() == 0 );
|
||||
for ( int i=m_PathIDs.First(); i != m_PathIDs.InvalidIndex(); i=m_PathIDs.Next( i ) )
|
||||
{
|
||||
CPathIDFileList *pPath = m_PathIDs[i];
|
||||
FOR_EACH_LL( pPath->m_Files, j )
|
||||
{
|
||||
CFileInfo *pInfo = pPath->m_Files[j];
|
||||
|
||||
if ( !(pInfo->m_Flags & k_eFileFlagsLoadedFromSteam) && ( pInfo->m_Flags & k_eFileFlagsHasCRC ) )
|
||||
{
|
||||
pInfo->m_iNeedsVerificationListIndex = m_NeedsVerificationList.AddToTail( pInfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CFileTracker::MarkAllCRCsVerified( bool bLockMutex )
|
||||
{
|
||||
if ( bLockMutex )
|
||||
m_Mutex.Lock();
|
||||
|
||||
FOR_EACH_LL( m_NeedsVerificationList, i )
|
||||
{
|
||||
m_NeedsVerificationList[i]->m_iNeedsVerificationListIndex = -1;
|
||||
}
|
||||
|
||||
m_NeedsVerificationList.Purge();
|
||||
|
||||
if ( bLockMutex )
|
||||
m_Mutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
int CFileTracker::GetUnverifiedCRCFiles( CUnverifiedCRCFile *pFiles, int nMaxFiles )
|
||||
{
|
||||
Assert( nMaxFiles > 0 );
|
||||
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
int iOutFile = 0;
|
||||
int iNext = 0;
|
||||
for ( int i=m_NeedsVerificationList.Head(); i != m_NeedsVerificationList.InvalidIndex(); i=iNext )
|
||||
{
|
||||
iNext = m_NeedsVerificationList.Next( i );
|
||||
|
||||
CFileInfo *pInfo = m_NeedsVerificationList[i];
|
||||
|
||||
// Remove this entry from the list.
|
||||
m_NeedsVerificationList.Remove( i );
|
||||
pInfo->m_iNeedsVerificationListIndex = -1;
|
||||
|
||||
// This can happen if a file that was in this list was loaded from Steam since it got added to the list.
|
||||
// In that case, just act like it's not in the list.
|
||||
if ( pInfo->m_Flags & k_eFileFlagsLoadedFromSteam )
|
||||
continue;
|
||||
|
||||
Assert( pInfo->m_Flags & k_eFileFlagsHasCRC );
|
||||
|
||||
// Add this file to their list.
|
||||
CUnverifiedCRCFile *pOutFile = &pFiles[iOutFile];
|
||||
|
||||
V_strncpy( pOutFile->m_Filename, pInfo->m_pFilename, sizeof( pOutFile->m_Filename ) );
|
||||
V_strncpy( pOutFile->m_PathID, pInfo->m_pPathIDFileList->m_PathID.String(), sizeof( pOutFile->m_PathID ) );
|
||||
pOutFile->m_CRC = pInfo->m_CRC;
|
||||
|
||||
|
||||
++iOutFile;
|
||||
if ( iOutFile >= nMaxFiles )
|
||||
return iOutFile;
|
||||
}
|
||||
|
||||
return iOutFile;
|
||||
}
|
||||
|
||||
|
||||
void CFileTracker::Clear()
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
m_PathIDs.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
CPathIDFileList* CFileTracker::GetPathIDFileList( const char *pPathID, bool bAutoAdd )
|
||||
{
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
if ( !pPathID )
|
||||
pPathID = "";
|
||||
|
||||
int i = m_PathIDs.Find( pPathID );
|
||||
if ( i == m_PathIDs.InvalidIndex() )
|
||||
{
|
||||
if ( bAutoAdd )
|
||||
{
|
||||
CPathIDFileList *pPath = new CPathIDFileList;
|
||||
pPath->m_PathID = pPathID;
|
||||
m_PathIDs.Insert( pPathID, pPath );
|
||||
return pPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_PathIDs[i];
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CFileInfo implementation.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CFileInfo::CFileInfo( const char *pFilename )
|
||||
{
|
||||
int len = V_strlen( pFilename ) + 1;
|
||||
m_pFilename = new char[ len ];
|
||||
Q_strncpy( m_pFilename, pFilename, len );
|
||||
m_iNeedsVerificationListIndex = -1;
|
||||
}
|
||||
|
||||
CFileInfo::~CFileInfo()
|
||||
{
|
||||
delete [] m_pFilename;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CPathIDFileList implementation..
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CPathIDFileList::~CPathIDFileList()
|
||||
{
|
||||
m_Files.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
CFileInfo* CPathIDFileList::FindFileInfo( const char *pFilename )
|
||||
{
|
||||
Assert( !V_IsAbsolutePath( pFilename ) );
|
||||
|
||||
FOR_EACH_LL( m_Files, i )
|
||||
{
|
||||
CFileInfo *pFileInfo = m_Files[i];
|
||||
|
||||
if ( CompareFilenames( pFilename, pFileInfo->GetFilename() ) )
|
||||
return m_Files[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFileInfo* CPathIDFileList::AddFileInfo( const char *pFilename )
|
||||
{
|
||||
Assert( !V_IsAbsolutePath( pFilename ) );
|
||||
|
||||
CFileInfo *pFileInfo = new CFileInfo( pFilename );
|
||||
pFileInfo->m_pPathIDFileList = this;
|
||||
m_Files.AddToTail( pFileInfo );
|
||||
return pFileInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
161
filesystem/filesystem_stdio/FileTracker.h
Normal file
161
filesystem/filesystem_stdio/FileTracker.h
Normal file
@ -0,0 +1,161 @@
|
||||
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef FILETRACKER_H
|
||||
#define FILETRACKER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "ifilelist.h"
|
||||
|
||||
|
||||
class CBaseFileSystem;
|
||||
class CFileHandle;
|
||||
|
||||
|
||||
enum EFileFlags
|
||||
{
|
||||
k_eFileFlagsLoadedFromSteam = 0x0001,
|
||||
|
||||
k_eFileFlagsHasCRC = 0x0002, // m_CRC represents the most recently-loaded version of the file. This might be
|
||||
// unset but m_CRC (and k_eFileFlagsGotCRCOnce) could be set, signifying that
|
||||
// the file has been opened since last time we calculated the CRC but we didn't
|
||||
// calculate a CRC for that file version.
|
||||
|
||||
k_eFileFlagsForcedLoadFromSteam = 0x0004, // Set if k_eFileFlagsLoadedFromSteam is set AND we forced Steam to not check the disk for this file.
|
||||
|
||||
k_eFileFlagsGotCRCOnce = 0x0008, // This is set if we EVER had k_eFileFlagsHasCRC set.. m_CRC will still be set in that case,
|
||||
// but it'll be the last CRC we calculated and not necessarily
|
||||
|
||||
k_eFileFlagsFailedToLoadLastTime = 0x0010 // This is used if we had a record of the file and the game tried to open it, but
|
||||
// it couldn't be opened. This will happen if the file was loaded from disk, then
|
||||
// sv_pure is turned on and the file is forced to come from Steam, but there is no
|
||||
// Steam version. In that case, the game should be told to retry the file
|
||||
// next time sv_pure is changed because if sv_pure goes back to 0 it -would- load
|
||||
// the file legitimately.
|
||||
};
|
||||
|
||||
|
||||
class CPathIDFileList;
|
||||
|
||||
|
||||
class CFileInfo
|
||||
{
|
||||
public:
|
||||
CFileInfo( const char *pFilename );
|
||||
~CFileInfo();
|
||||
|
||||
const char* GetFilename();
|
||||
const char* GetPathIDString();
|
||||
|
||||
public:
|
||||
//TODO: Optimize this. Probably should use a hierarchical structure with a list of files in each directory.
|
||||
char *m_pFilename;
|
||||
unsigned short m_Flags; // This is a combination of EFileFlags.
|
||||
CRC32_t m_CRC; // The CRC for this file.
|
||||
CPathIDFileList *m_pPathIDFileList;
|
||||
int m_iNeedsVerificationListIndex; // Index into m_NeedsVerificationList or -1 if not in the list.
|
||||
};
|
||||
|
||||
|
||||
// This tracks a list of files for the specified path ID.
|
||||
class CPathIDFileList
|
||||
{
|
||||
public:
|
||||
~CPathIDFileList();
|
||||
CFileInfo* FindFileInfo( const char *pFilename );
|
||||
CFileInfo* AddFileInfo( const char *pFilename );
|
||||
|
||||
public:
|
||||
CUtlSymbol m_PathID; // "" for a null path ID.
|
||||
CUtlLinkedList<CFileInfo*,int> m_Files;
|
||||
CUtlLinkedList<CFileInfo*,int> m_UnverifiedCRCFiles; // These are the files whose CRCs have not been verified yet.
|
||||
// These just point at entries in m_Files.
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This tracks the files that have been opened by the filesystem.
|
||||
// It remembers if they were loaded from Steam or off-disk.
|
||||
// If the filesystem is tracking CRCs, then it will calculate a CRC
|
||||
// for each file that came off disk.
|
||||
//
|
||||
// TODO: This is similar to CBaseFileSystem::m_OpenedFiles - it could probably
|
||||
// manage both sets of files in the same list. Having 2 separate lists might
|
||||
// be confusing.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFileTracker
|
||||
{
|
||||
public:
|
||||
CFileTracker( CBaseFileSystem *pFileSystem );
|
||||
~CFileTracker();
|
||||
|
||||
// If this is true, then we'll calculate CRCs for each file that came off disk.
|
||||
void SetWantFileCRCs( bool bWantCRCs );
|
||||
|
||||
// As files are opened, if it is calculating CRCs, it will add those files and their
|
||||
// CRCs to the "unverified CRC" list. The client can then ask the server to verify
|
||||
// those CRCs to make sure the client is "pure".
|
||||
void MarkAllCRCsUnverified();
|
||||
void MarkAllCRCsVerified( bool bLockMutex=true );
|
||||
|
||||
// Cache a file's CRC. Loads the file and calculates the CRC if we don't have it yet.
|
||||
void CacheFileCRC( const char *pPathID, const char *pRelativeFilename );
|
||||
EFileCRCStatus CheckCachedFileCRC( const char *pPathID, const char *pRelativeFilename, CRC32_t *pCRC );
|
||||
|
||||
// This is like CacheFileCRC, but it assumes that the same file would be found by pPathIDToCopyFrom, so it just
|
||||
// copies the CRC record from that path ID into the one in pPathID and avoids a redundant CRC calculation.
|
||||
void CacheFileCRC_Copy( const char *pPathID, const char *pRelativeFilename, const char *pPathIDToCopyFrom );
|
||||
|
||||
// When we don't have a whitelist, it loads files without bothering to calculate their CRCs (we'd only
|
||||
// need them on a pure server), but when we get a whitelist, we'll want the CRCs, so it goes back, opens those
|
||||
// files, and calculates the CRCs for them.
|
||||
void CalculateMissingCRCs( IFileList *pForceMatchList );
|
||||
|
||||
int GetUnverifiedCRCFiles( CUnverifiedCRCFile *pFiles, int nMaxFiles );
|
||||
|
||||
// Note that we just opened this file and calculate a CRC for it.
|
||||
void NoteFileLoadedFromDisk( const char *pFilename, const char *pPathID, FileHandle_t fp );
|
||||
void NoteFileLoadedFromSteam( const char *pFilename, const char *pPathID, bool bForcedLoadFromSteam );
|
||||
void NoteFileFailedToLoad( const char *pFilename, const char *pPathID );
|
||||
|
||||
// Get a file info from a specific path ID.
|
||||
CFileInfo* GetFileInfo( const char *pFilename, const char *pPathID );
|
||||
|
||||
// Get all file infos with the specified filename (i.e. in all path IDs).
|
||||
int GetFileInfos( CFileInfo **ppFileInfos, int nMaxFileInfos, const char *pFilename );
|
||||
|
||||
// Clear everything.
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
void CalculateMissingCRC( const char *pFilename, const char *pPathID );
|
||||
CPathIDFileList* GetPathIDFileList( const char *pPathID, bool bAutoAdd=true );
|
||||
|
||||
CRC32_t CalculateCRCForFile( FileHandle_t fp );
|
||||
|
||||
private:
|
||||
CUtlLinkedList<CFileInfo*> m_NeedsVerificationList; // The list of files that need CRCs verified.
|
||||
CUtlDict<CPathIDFileList*,int> m_PathIDs;
|
||||
CBaseFileSystem *m_pFileSystem;
|
||||
CThreadMutex m_Mutex; // Threads call into here, so we need to be safe.
|
||||
};
|
||||
|
||||
|
||||
inline const char* CFileInfo::GetFilename()
|
||||
{
|
||||
return m_pFilename;
|
||||
}
|
||||
|
||||
inline const char* CFileInfo::GetPathIDString()
|
||||
{
|
||||
return m_pPathIDFileList->m_PathID.String();
|
||||
}
|
||||
|
||||
|
||||
#endif // FILETRACKER_H
|
85
filesystem/filesystem_stdio/ThreadSafeRefCountedObject.h
Normal file
85
filesystem/filesystem_stdio/ThreadSafeRefCountedObject.h
Normal file
@ -0,0 +1,85 @@
|
||||
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef THREADSAFEREFCOUNTEDOBJECT_H
|
||||
#define THREADSAFEREFCOUNTEDOBJECT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
// This class can be used for fast access to an object from multiple threads,
|
||||
// and the main thread can wait until the threads are done using the object before it frees the object.
|
||||
template< class T >
|
||||
class CThreadSafeRefCountedObject
|
||||
{
|
||||
public:
|
||||
CThreadSafeRefCountedObject( T initVal )
|
||||
{
|
||||
m_RefCount = 0;
|
||||
m_pObject = initVal;
|
||||
m_RefCount = 0;
|
||||
}
|
||||
|
||||
void Init( T pObj )
|
||||
{
|
||||
Assert( ThreadInMainThread() );
|
||||
Assert( !m_pObject );
|
||||
m_RefCount = 0;
|
||||
m_pObject = pObj;
|
||||
m_RefCount = 1;
|
||||
}
|
||||
|
||||
// Threads that access the object need to use AddRef/Release to access it.
|
||||
T AddRef()
|
||||
{
|
||||
if ( ++m_RefCount > 1 )
|
||||
{
|
||||
return m_pObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the refcount was 0 when we called this, then the whitelist is about to be freed.
|
||||
--m_RefCount;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
void ReleaseRef( T pObj )
|
||||
{
|
||||
if ( --m_RefCount >= 1 )
|
||||
{
|
||||
Assert( m_pObject == pObj );
|
||||
}
|
||||
}
|
||||
|
||||
// The main thread can use this to access the object, since only it can Init() and Free() the object.
|
||||
T GetInMainThread()
|
||||
{
|
||||
Assert( ThreadInMainThread() );
|
||||
return m_pObject;
|
||||
}
|
||||
|
||||
// The main thread calls this after it has released its last reference to the object.
|
||||
void ResetWhenNoRemainingReferences( T newValue )
|
||||
{
|
||||
Assert( ThreadInMainThread() );
|
||||
|
||||
// Wait until we can free it.
|
||||
while ( m_RefCount > 0 )
|
||||
{
|
||||
CThread::Sleep( 20 );
|
||||
}
|
||||
|
||||
m_pObject = newValue;
|
||||
}
|
||||
|
||||
private:
|
||||
CInterlockedIntT<long> m_RefCount;
|
||||
T m_pObject;
|
||||
};
|
||||
|
||||
|
||||
#endif // THREADSAFEREFCOUNTEDOBJECT_H
|
Reference in New Issue
Block a user