uid issue

This commit is contained in:
KittenPopo
2021-07-24 21:11:47 -07:00
commit c2130ba4e9
13850 changed files with 6241419 additions and 0 deletions

2145
filesystem/QueuedLoader.cpp Normal file

File diff suppressed because it is too large Load Diff

1703
filesystem/XboxInstaller.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
// ----------------------------------------- //
// File generated by VPC //
// ----------------------------------------- //
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\basefilesystem.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\basefilesystem.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\basefilesystem.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\basefilesystemasync.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\basefilesystemasync.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\basefilesystemasync.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\common\debug_dll_check.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\common\debug_dll_check.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\common\debug_dll_check.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filesystem_stdio.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filesystem_stdio.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filesystem_stdio.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filesystemasync.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filesystemasync.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filesystemasync.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filetracker.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filetracker.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\filetracker.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\kevvaluescompiler.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\kevvaluescompiler.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\kevvaluescompiler.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\tier0\memoverride.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\tier0\memoverride.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\tier0\memoverride.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\QueuedLoader.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\QueuedLoader.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\filesystem\QueuedLoader.cpp
Containing unity file:
PCH file:
Source file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\zip_utils.cpp
Debug output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\zip_utils.cpp
Release output file: D:\Users\berta\Downloads\csgosourcecode\cstrike15_src\public\zip_utils.cpp
Containing unity file:
PCH file:

File diff suppressed because it is too large Load Diff

1396
filesystem/basefilesystem.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2060
filesystem/filegroup.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
//-----------------------------------------------------------------------------
// FILESYSTEM_STDIO.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR ".."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
$Configuration "Debug"
{
$General
{
$OutputDirectory "Debug_Stdio$PLATSUBDIR" [$WINDOWS]
$IntermediateDirectory "Debug_Stdio$PLATSUBDIR" [$WINDOWS]
$OutputDirectory "Debug_Stdio_360" [$X360]
$IntermediateDirectory "Debug_Stdio_360" [$X360]
}
}
$Configuration "Release"
{
$General
{
$OutputDirectory "Release_Stdio$PLATSUBDIR" [$WINDOWS]
$IntermediateDirectory "Release_Stdio$PLATSUBDIR" [$WINDOWS]
$OutputDirectory "Release_Stdio_360" [$X360]
$IntermediateDirectory "Release_Stdio_360" [$X360]
}
}
$Configuration
{
$Compiler
{
$PreprocessorDefinitions "$BASE;FILESYSTEM_STDIO_EXPORTS;DONT_PROTECT_FILEIO_FUNCTIONS;PROTECTED_THINGS_ENABLE"
$PreprocessorDefinitions "$BASE;_USE_32BIT_TIME_T" [$WIN32]
}
$Linker [!$PS3]
{
$SystemLibraries "iconv" [$OSXALL]
}
}
$Project "filesystem_stdio"
{
$Folder "Source Files"
{
$File "basefilesystem.cpp"
$File "basefilesystemasync.cpp"
$File "filetracker.cpp"
$File "filesystemasync.cpp" [!$PS3]
$File "filesystem_stdio.cpp"
$File "$SRCDIR\public\kevvaluescompiler.cpp" [!$PS3]
$File "$SRCDIR\public\zip_utils.cpp" [!$PS3]
$File "QueuedLoader.cpp"
$File "xboxinstaller.cpp" [$X360]
$File "linux_support.cpp" [$POSIX]
}
$Folder "Header Files"
{
$File "basefilesystem.h"
$File "filesystemasync.h"
$File "filetracker.h"
$File "threadsaferefcountedobject.h"
$File "$SRCDIR\public\tier0\basetypes.h"
$File "$SRCDIR\public\bspfile.h"
$File "$SRCDIR\public\bspflags.h"
$File "$SRCDIR\public\tier1\characterset.h"
$File "$SRCDIR\public\tier0\dbg.h"
$File "$SRCDIR\public\tier0\fasttimer.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\filesystem\iasyncfilesystem.h"
$File "$SRCDIR\public\ifilelist.h"
$File "$SRCDIR\public\appframework\iappsystem.h"
$File "$SRCDIR\public\tier1\interface.h"
$File "$SRCDIR\public\tier0\platform.h"
$File "$SRCDIR\public\tier1\strtools.h"
$File "$SRCDIR\public\tier1\utlmemory.h"
$File "$SRCDIR\public\tier1\utlrbtree.h"
$File "$SRCDIR\public\tier1\utlsymbol.h"
$File "$SRCDIR\public\tier1\utlvector.h"
$File "$SRCDIR\public\vstdlib\vstdlib.h"
$File "$SRCDIR\public\keyvaluescompiler.h"
$File "$SRCDIR\public\filesystem\IQueuedLoader.h"
}
$Folder "Link Libraries"
{
$lib tier2
$lib vpklib [!$X360 && !$PS3]
}
}

View File

@ -0,0 +1,13 @@
"vpc_cache"
{
"CacheVersion" "1"
"win32"
{
"CRCFile" "filesystem_stdio.vcxproj.vpc_crc"
"OutputFiles"
{
"0" "filesystem_stdio.vcxproj"
"1" "filesystem_stdio.vcxproj.filters"
}
}
}

View 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;
}

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,596 @@
//===== Copyright <20> 2009, Valve Corporation, All rights reserved. ======//
// filesyste_newasync.h
//
// Purpose:
//
// $NoKeywords: $async file system
//===========================================================================//
#include <limits.h>
#include "tier0/threadtools.h"
#include "tier0/memalloc.h"
#include "tier1/interface.h"
#include "tier1/utlsymbol.h"
#include "appframework/iappsystem.h"
#include "tier1/checksum_crc.h"
#include "filesystem/iasyncfilesystem.h"
#ifndef FILESYSTEMASYNC_H
#define FILESYSTEMASYNC_H
#ifdef _WIN32
#pragma once
#endif
#ifdef OSX
#pragma GCC diagnostic ignored "-Wreturn-type" // control reaches end of non-void function, for unsupported assignment operators below
#endif
class CAsyncGroupRequest;
struct CAsyncResultInfo_t
{
public:
void* m_pAllocatedBuffer;
int m_nBytesTransferred;
FSAsyncStatus_t m_ErrorCode;
CAsyncResultInfo_t() : m_pAllocatedBuffer(NULL), m_nBytesTransferred(0) {}
};
//-----------------------------------------------------------------------------
// CAsyncRequestBase - Common items to all async filesystem requests
//
// Allows the async filesystem to have a standard way to deal with different
// types of requests equally re: priority, callbacks, state, aborting, etc
//
//-----------------------------------------------------------------------------
class CAsyncRequestBase
{
public:
void* m_pOuter; // pointer to object containing this base
// -------------------------------------------------------
// Members to set by the user before submission
CFunctor* m_pCallback; // Optional Callback object (we own this)
CIOCompletionQueue* m_pResultQueue; // Message Queue object to send results to
AsyncFileOperation_t m_Operation; // operation to perform
int32 m_priority; // inter list priority, 0=lowest??
// -------------------------------------------------------
// Used internally by the filesystem to keep track of the request
CAsyncRequestBase* m_pNext; // used to maintain the priority linked list
CAsyncRequestBase* m_pPrev;
// -------------------------------------------------------
// Members which get set by the file system after submission
AsyncRequestState_t m_RequestState; // State of this request (which stage it is n)
AsyncRequestStatus_t m_RequestStatus; // Error/Success Status from the last operation attempted on this request
bool m_bAbortRequest; // Flag indicating this request is to be aborted
bool m_bProcessingCallback; // Flag indicating a callback is being processed
bool m_bDontAutoRelease; // Flag indicating not to automatically release the request once the callback finishes
// bool m_bIsAContainer
CThreadEvent* m_pSyncThreadEvent; // Thread event to signal in synchronous mode...
FSAsyncControl_t m_pOldAsyncControl; // old Async System control Handle
FSAsyncStatus_t m_pOldAsyncStatus; // old Async System IO Status
CAsyncGroupRequest* m_pGroup; // group this request belongs to
public:
CAsyncRequestBase(); // Default Constructor - We want NO implicit constructions
~CAsyncRequestBase(); // Destructor - not virtual anymore
void SetOuter( void* pOuter ) { m_pOuter = pOuter; }
void* GetOuter() { return m_pOuter; }
IAsyncRequestBase* GetInterfaceBase();
// functions to query operation
AsyncFileOperation_t GetAsyncOperationType() { return m_Operation; }
// Set completion options
void AssignCallback( CFunctor* pCallback ); // Add a completion callback to this request
void AssignResultQueue( CIOCompletionQueue* pMsgQueue ); // Send the results to this queue object
void AssignCallbackAndQueue( CIOCompletionQueue* pMsgQueue, CFunctor* pCallback );
// Completion processing functions
void ProcessCallback( bool bRelease = true ); // Execute the optional callback functor
void KeepRequestPostCallback() { m_bDontAutoRelease = true; } // User wants to keep request alive after the callback completes
void DontKeepRequestPostCallback() { m_bDontAutoRelease = false; } // User doesn't want to keep request after the callback completes
void Release(); // lets user manually release the async request (only valid when completed)
void DeleteOuter(); // Used by async filesystem to delete the containing object (as well as the CAsyncRequestBase)
// Priority Functions
void SetPriority( int32 nPriority );
int32 GetPriority() { return m_priority; }
// Status & Results functions
AsyncRequestState_t GetRequestState() { return m_RequestState; }
AsyncRequestStatus_t GetRequestStatus() { return m_RequestStatus; }
// --------------------------------------------------------------
// Gateway to outer's Public Methods not included in the interface, used by Async FileSystem
void AbortAfterServicing( CAsyncResultInfo_t& results ); // Handle a request that got aborted while being serviced
void UpdateAfterServicing( CAsyncResultInfo_t& results ); // Handle a request that got aborted while being serviced
AsyncRequestStatus_t ValidateSubmittedRequest( bool bPerformSync ); // Validates the derived object data at request submission
bool ValidateRequestModification(); // core check to determine if modification is allowed at this time
protected:
// Helper functions for repeated operations
void RefreshCallback( CFunctor* pCallback );
private:
explicit CAsyncRequestBase( const CAsyncRequestBase& rhs ); // copy constructor - NOT SUPPORTED
CAsyncRequestBase& operator=( const CAsyncRequestBase& rhs ); // assignment operator - NOT SUPPORTED
};
//-----------------------------------------------------------------------------
// CAsyncGroupRequest - Concrete implementation for a group of async requests
//
//
//
//-----------------------------------------------------------------------------
class CAsyncGroupRequest : public IAsyncGroupRequest
{
public:
CAsyncRequestBase m_Base; // Base request - we can't derive from due to multiple inheritance problems
CUtlVector<IAsyncRequestBase*> m_RequestList; // List of requests to process
CUtlVector<bool> m_ValidList; // List of requests which are valid
CInterlockedInt m_nNumRequestsOutstanding;
public:
CAsyncGroupRequest(); // Default Constructor - We want NO implicit constructions
virtual ~CAsyncGroupRequest(); // Destructor
// ---------------------------------------------------------
// methods from the IAsyncRequestBase Interface
// ---------------------------------------------------------
// functions to query operation
virtual AsyncFileOperation_t GetAsyncOperationType() { return m_Base.GetAsyncOperationType(); }
// Set completion options
virtual void AssignCallback( CFunctor* pCallback ) { m_Base.AssignCallback( pCallback ); }
virtual void AssignResultQueue( CIOCompletionQueue* pMsgQueue ) { m_Base.AssignResultQueue( pMsgQueue ); }
virtual void AssignCallbackAndQueue( CIOCompletionQueue* pMsgQueue, CFunctor* pCallback ) { m_Base.AssignCallbackAndQueue( pMsgQueue, pCallback); }
// Completion processing functions
virtual void ProcessCallback( bool bRelease = true ) { m_Base.ProcessCallback( bRelease ); }
virtual void KeepRequestPostCallback() { m_Base.KeepRequestPostCallback(); }
virtual void DontKeepRequestPostCallback() { m_Base.DontKeepRequestPostCallback(); }
virtual void Release() { m_Base.Release(); }
// Priority Functions
virtual void SetPriority( int32 nPriority ) { m_Base.SetPriority( nPriority ); }
virtual int32 GetPriority() { return m_Base.GetPriority(); }
// Status & Results functions
virtual AsyncRequestState_t GetRequestState() { return m_Base.GetRequestState(); }
virtual AsyncRequestStatus_t GetRequestStatus() { return m_Base.GetRequestStatus(); }
private:
virtual CAsyncRequestBase* GetBase() { return (CAsyncRequestBase*) &m_Base; }
// ----------------------------------------------------
// methods from the IAsyncGroupRequest Interface
// ----------------------------------------------------
public:
virtual void AddAsyncRequest( IAsyncRequestBase* pRequest );
virtual int32 GetAsyncRequestCount() { return m_RequestList.Count(); }
virtual IAsyncRequestBase* GetAsyncRequest( int32 nRNum );
virtual IAsyncFileRequest* GetAsyncFileRequest( int32 nRNum );
virtual IAsyncSearchRequest* GetAsyncSearchRequest( int32 nRNum );
virtual void ReleaseAsyncRequest( int32 nRNum );
void NotifyOfCompletion( IAsyncRequestBase* pRequest );
private:
explicit CAsyncGroupRequest( const CAsyncRequestBase& rhs ); // copy constructor - NOT SUPPORTED
CAsyncRequestBase& operator=( const CAsyncGroupRequest& rhs ); // assignment operator - NOT SUPPORTED
};
//-----------------------------------------------------------------------------
// CAsyncFileRequest - Concrete implementation for the IAsyncFileRequest interface
//
// Manages a read or write to file request
//
//-----------------------------------------------------------------------------
class CAsyncFileRequest : public IAsyncFileRequest
{
public:
CAsyncRequestBase m_Base; // Base request - we can't derive from due to multiple inheritance problems
// -------------------------------------------------------
// Members to set by the user before submission
const char* m_pFileName; // file system name (copy of string that we own)
void* m_pUserProvidedDataBuffer; // optional (if read op), system will alloc one if NULL/free if NULL
size_t m_nUserProvidedBufferSize; // size of the memory buffer
int64 m_nFileSeekOffset; // (optional) position in the file to seek to/begin xfer at, 0=beginning
int64 m_nMaxIOSizeInBytes; // optional read clamp, 0=full read
// -------------------------------------------------------
// Members which get set by the file system after submission
void* m_pResultsBuffer; // Buffer results were placed in, could be from user (or not)
size_t m_nResultsBufferSize; // size of results buffer
size_t m_nIOActualSize; // actual size of IO performed
bool m_bDeleteBufferMemory; // Flag indicating the memory holding the file data is deleted when the request is released
public:
CAsyncFileRequest(); // Default Constructor - We want NO implicit constructions
virtual ~CAsyncFileRequest(); // Destructor
// ---------------------------------------------------------
// methods from the IAsyncRequestBase Interface
// ---------------------------------------------------------
// functions to query operation
virtual AsyncFileOperation_t GetAsyncOperationType() { return m_Base.GetAsyncOperationType(); }
// Set completion options
virtual void AssignCallback( CFunctor* pCallback ) { m_Base.AssignCallback( pCallback ); }
virtual void AssignResultQueue( CIOCompletionQueue* pMsgQueue ) { m_Base.AssignResultQueue( pMsgQueue ); }
virtual void AssignCallbackAndQueue( CIOCompletionQueue* pMsgQueue, CFunctor* pCallback ) { m_Base.AssignCallbackAndQueue( pMsgQueue, pCallback); }
// Completion processing functions
virtual void ProcessCallback( bool bRelease = true ) { m_Base.ProcessCallback( bRelease ); }
virtual void KeepRequestPostCallback() { m_Base.KeepRequestPostCallback(); }
virtual void DontKeepRequestPostCallback() { m_Base.DontKeepRequestPostCallback(); }
virtual void Release() { m_Base.Release(); }
// Priority Functions
virtual void SetPriority( int32 nPriority ) { m_Base.SetPriority( nPriority ); }
virtual int32 GetPriority() { return m_Base.GetPriority(); }
// Status & Results functions
virtual AsyncRequestState_t GetRequestState() { return m_Base.GetRequestState(); }
virtual AsyncRequestStatus_t GetRequestStatus() { return m_Base.GetRequestStatus(); }
private:
virtual CAsyncRequestBase* GetBase() { return (CAsyncRequestBase*) &m_Base; }
// ----------------------------------------------------
// methods from the IAsyncFileRequest Interface
// ----------------------------------------------------
public:
// functions to set filename and operation
virtual void LoadFile( const char* pFileName ); // make this a 'read data from file' request
virtual void SaveFile( const char* pFileName ); // make this a 'write data to file' request
virtual void AppendFile( const char* pFileName ); // make this a 'append data to file' request
virtual void SetFileName( const char* pFileName ); // assign the filename to use
virtual const char* GetFileName() { return m_pFileName; } // get the filename we've assigned
// Buffer control functions
virtual void SetUserBuffer( void* pDataBuffer, size_t nBufferSize ); // User supplies a memory buffer to use, which they own the memory for
virtual void* GetUserBuffer() { return m_pUserProvidedDataBuffer; } // returns the address of the user supplied buffer
virtual size_t GetUserBufferSize() { return m_nUserProvidedBufferSize; } // returns the size of the user supplied buffer
virtual void ProvideDataBuffer(); // file system provide a buffer with the results
// returned buffer (read) functions
virtual void* GetResultBuffer() { return m_pResultsBuffer; } // Returns the address of the data transferred
virtual size_t GetResultBufferSize() { return m_nResultsBufferSize; } // Returns the size of the buffer holding the data transferred
virtual size_t GetIOTransferredSize() { return m_nIOActualSize; } // Returns the number of bytes of data actually transferred
// Memory control functions for buffers allocated by the async file system
virtual void KeepResultBuffer() { m_bDeleteBufferMemory = false; } // User wants to keeps buffer allocated by the file system
virtual void ReleaseResultBuffer() { m_bDeleteBufferMemory = true; } // User decides they want the request to take care of releasing the buffer
// file position functions
virtual void ReadFileDataAt( int64 nOffset, size_t nReadSize = 0 ); // Read file data starting at supplied offset, optional max size to read
virtual void WriteFileDataAt( int64 nOffset, size_t nWriteSize = 0 ); // Write data to file at supplied offset, optional size to write (max size of buffer)
// --------------------------------------------------------------
// Public Methods not included in the interface, used by Async FileSystem
void AbortAfterServicing( CAsyncResultInfo_t& results ); // Handle a request that got aborted while being serviced
void UpdateAfterServicing( CAsyncResultInfo_t& results ); // Handle a request that got aborted while being serviced
AsyncRequestStatus_t ValidateSubmittedRequest( bool bPerformSync ); // Validates the derived object data at request submission
bool ValidateRequestModification(); // Check to determine if modification is allowed at this time
protected:
// Helper functions for repeated operations
void RefreshFileName( const char* pNewFileName );
private:
// disabled functions
explicit CAsyncFileRequest( const CAsyncFileRequest& rhs ); // copy constructor - NOT SUPPORTED
CAsyncFileRequest& operator=( const CAsyncFileRequest& rhs ); // assignment operator - NOT SUPPORTED
};
//-----------------------------------------------------------------------------
// CAsyncSearchRequest - Implementation of the Interface for setting and reading
// the results of an asynchronous directory search request
//
//-----------------------------------------------------------------------------
class CAsyncSearchRequest : public IAsyncSearchRequest
{
public:
CAsyncRequestBase m_Base; // Base request - we can't derive from due to multiple inheritance problems
// CUtlStringList m_DirectoryList; // List of directories we have scanned
int32 m_nNumResults; // number of results
bool m_bRecurseSubdirs; // flag to activate recursing of subdirectories
CUtlVector<CDirectoryEntryInfo_t> m_Results; // Search results...
char m_FileSpec[MAX_PATH]; // filespec of the files we are looking for
char m_PathID[MAX_PATH];
char m_SearchPath[MAX_PATH];
char m_SearchSpec[MAX_PATH];
public:
CAsyncSearchRequest(); // Default Constructor - We want NO implicit constructions
virtual ~CAsyncSearchRequest(); // Destructor
// ---------------------------------------------------------
// methods from the IAsyncRequestBase Interface
// ---------------------------------------------------------
// functions to query operation
virtual AsyncFileOperation_t GetAsyncOperationType() { return m_Base.GetAsyncOperationType(); }
// Set completion options
virtual void AssignCallback( CFunctor* pCallback ) { m_Base.AssignCallback( pCallback ); }
virtual void AssignResultQueue( CIOCompletionQueue* pMsgQueue ) { m_Base.AssignResultQueue( pMsgQueue ); }
virtual void AssignCallbackAndQueue( CIOCompletionQueue* pMsgQueue, CFunctor* pCallback ) { m_Base.AssignCallbackAndQueue( pMsgQueue, pCallback); }
// Completion processing functions
virtual void ProcessCallback( bool bRelease = true ) { m_Base.ProcessCallback( bRelease ); }
virtual void KeepRequestPostCallback() { m_Base.KeepRequestPostCallback(); }
virtual void DontKeepRequestPostCallback() { m_Base.DontKeepRequestPostCallback(); }
virtual void Release() { m_Base.Release(); }
// Priority Functions
virtual void SetPriority( int32 nPriority ) { m_Base.SetPriority( nPriority ); }
virtual int32 GetPriority() { return m_Base.GetPriority(); }
// Status & Results functions
virtual AsyncRequestState_t GetRequestState() { return m_Base.GetRequestState(); }
virtual AsyncRequestStatus_t GetRequestStatus() { return m_Base.GetRequestStatus(); }
private:
virtual CAsyncRequestBase* GetBase() { return (CAsyncRequestBase*) &m_Base; }
// ---------------------------------------------------------
// methods from the IAsyncSearchRequest Interface
// ---------------------------------------------------------
public:
// functions to define the request
virtual void SetSearchFilespec( const char* pFullSearchSpec );
virtual void SetSearchPathAndFileSpec( const char* pPathId, const char* pRelativeSearchSpec );
virtual void SetSearchPathAndFileSpec( const char* pPathId, const char* pRelativeSearchPath, const char* pSearchSpec );
virtual void SetSubdirectoryScan( const bool bInclude );
virtual bool GetSubdirectoryScan() { return m_bRecurseSubdirs; }
// Functions to return the results.
virtual int GetResultCount() { return m_nNumResults; }
virtual CDirectoryEntryInfo_t* GetResult( int rNum = 0 );
virtual const char* GetMatchedFile( int rNum = 0 );
// --------------------------------------------------------------
// Public Methods not included in the interface, used by Async FileSystem
void AbortAfterServicing( CAsyncResultInfo_t& results ); // Handle a request that got aborted while being serviced
void UpdateAfterServicing( CAsyncResultInfo_t& results ); // Handle a request that got aborted while being serviced
AsyncRequestStatus_t ValidateSubmittedRequest( bool bPerformSync ); // Validates the derived object data at request submission
bool ValidateRequestModification(); // Check to determine if modification is allowed at this time
private:
// disabled functions
explicit CAsyncSearchRequest( const CAsyncSearchRequest& rhs ); // copy constructor - NOT SUPPORTED
CAsyncSearchRequest& operator=( const CAsyncSearchRequest& rhs ); // assignment operator - NOT SUPPORTED
};
//-----------------------------------------------------------------------------
// CAsyncRequestQueue
// Helper object for filesystem - Linked list of objects
// dreeived from CAsyncRequestBase
//-----------------------------------------------------------------------------
class CAsyncRequestQueue
{
private:
CThreadFastMutex m_Mutex;
int32 m_nQueueSize;
CAsyncRequestBase* m_pHead;
CAsyncRequestBase* m_pTail;
public:
CAsyncRequestQueue();
~CAsyncRequestQueue();
int32 GetSize() { return m_nQueueSize; }
bool IsInQueue( CAsyncRequestBase* pItem );
bool IsInQueueIp( const IAsyncRequestBase* pInterfaceBase );
void AddToHead( CAsyncRequestBase* pItem );
void AddToTail( CAsyncRequestBase* pItem );
void InsertBefore( CAsyncRequestBase* pItem, CAsyncRequestBase* pInsertAt );
void InsertAfter( CAsyncRequestBase* pItem, CAsyncRequestBase* pInsertAt );
void PriorityInsert( CAsyncRequestBase* pItem );
void Remove( CAsyncRequestBase* pItem );
CAsyncRequestBase* RemoveHead();
};
//-----------------------------------------------------------------------------
// CAsyncFileSystem - implements IAsyncFileSystem interface
//
//-----------------------------------------------------------------------------
class CAsyncFileSystem : public CTier2AppSystem< IAsyncFileSystem >
{
typedef CTier2AppSystem< IAsyncFileSystem > BaseClass;
friend class CAsyncGroupRequest;
public:
static const int s_MaxPlatformFileNameLength = 40;
public:
CAsyncFileSystem();
~CAsyncFileSystem();
//--------------------------------------------------
// Interface methods exposed with IAsyncFileSystem
//--------------------------------------------------
virtual AsyncRequestStatus_t SubmitAsyncFileRequest( const IAsyncRequestBase* pRequest );
virtual AsyncRequestStatus_t SubmitSyncFileRequest( const IAsyncRequestBase* pRequest );
virtual AsyncRequestStatus_t GetAsyncFileRequestStatus( const IAsyncRequestBase* pRequest );
virtual AsyncRequestStatus_t AbortAsyncFileRequest( const IAsyncRequestBase* pRequest );
virtual void SuspendAllAsyncIO( bool bWaitForIOCompletion = true );
virtual void ResumeAllAsyncIO();
virtual AsyncRequestStatus_t AbortAllAsyncIO( bool bWaitForIOCompletion = true );
virtual IAsyncFileRequest* CreateNewFileRequest();
virtual IAsyncSearchRequest* CreateNewSearchRequest();
virtual IAsyncGroupRequest* CreateNewAsyncRequestGroup();
virtual void ReleaseAsyncRequest( const IAsyncRequestBase* pRequest );
virtual bool BlockUntilAsyncIOComplete( const IAsyncRequestBase* pRequest );
virtual void* AllocateBuffer( size_t nBufferSize, int nAlignment = 4 );
virtual void ReleaseBuffer( void* pBuffer );
//--------------------------------------------------
// Public Methods used inside the filesystem
//--------------------------------------------------
void* QueryInterface( const char *pInterfaceName );
void RemoveRequest( CAsyncRequestBase* pRequest );
bool ResolveAsyncRequest( const IAsyncRequestBase* pRequest, CAsyncRequestBase*& pRequestBase, AsyncRequestState_t& CurrentStage );
bool ValidateRequestPtr( CAsyncRequestBase* pRequest );
private:
CAsyncRequestQueue m_Composing; // requests in state: Composing
CAsyncRequestQueue m_Submitted; // requests in state: Submitted
CAsyncRequestQueue m_InFlight; // requests in state: Serviced
CAsyncRequestQueue m_Completed; // requests in state: Awaiting Finished, Completed*
CInterlockedInt m_nJobsInflight; // number of requests currently being serviced by the old system
CInterlockedInt m_nSuspendCount; // number of requests to suspend all Async IO outstanding (nested request support)
bool m_bIOSuspended;
#if defined(_DEBUG)
CThreadFastMutex m_MemoryTrackMutex;
CUtlVector<void*> m_AllocList; // Debug build - track allocations
#endif
CThreadFastMutex m_AsyncStateUpdateMutex;
CThreadEvent m_CompletionSignal; // Used to signal the completion of an IO
AsyncRequestStatus_t ValidateRequest( CAsyncRequestBase* pRequest, bool bPerformSync = false );
void KickOffFileJobs();
void WaitForServincingIOCompletion(); // Pauses until all jobs being serviced are complete
static void* OldAsyncAllocatorCallback( const char *pszFilename, unsigned nBytes );
static void AsyncIOCallbackGateway(const FileAsyncRequest_t &request, int nBytesRead, FSAsyncStatus_t err);
static void AsyncSearchCallbackAddItem( void* pContext, char* pFoundPath, char* pFoundFile );
static void AsyncSearchCallbackGateway( void* pContext, FSAsyncStatus_t err );
void AsyncIOCallBackHandler(CAsyncRequestBase* pRequest, CAsyncResultInfo_t& results );
void NotifyMessageQueueOrCallback( CAsyncRequestBase* pRequest );
};
//-----------------------------------------------------------------------------
// Utility functions
//
//-----------------------------------------------------------------------------
AsyncRequestStatus_t ValidateFileName( const char* pFileName );
#endif

1263
filesystem/filetracker.cpp Normal file

File diff suppressed because it is too large Load Diff

390
filesystem/filetracker.h Normal file
View File

@ -0,0 +1,390 @@
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef FILETRACKER_H
#define FILETRACKER_H
#ifdef _WIN32
#pragma once
#endif
#include "ifilelist.h"
#include "tier1/utldict.h"
class CBaseFileSystem;
class CFileHandle;
enum EFileFlags
{
k_eFileFlags_None = 0x0000,
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();
~CFileInfo();
const char* GetFilename();
const char* GetPathIDString();
public:
unsigned short m_Flags; // This is a combination of EFileFlags.
CRC32_t m_CRC; // The CRC for this file.
CPathIDFileList *m_pPathIDFileList;
int m_PathIDFileListDictIndex; // Our index into m_pPathIDFileList->m_Files
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();
~CPathIDFileList();
CFileInfo* FindFileInfo( const char *pFilename );
CFileInfo* AddFileInfo( const char *pFilename );
public:
CUtlSymbol m_PathID; // "" for a null path ID.
CUtlDict<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_pPathIDFileList->m_Files.GetElementName( m_PathIDFileListDictIndex );
}
inline const char* CFileInfo::GetPathIDString()
{
return m_pPathIDFileList->m_PathID.String();
}
struct TrackedFile_t
{
TrackedFile_t()
{
m_nFileFraction = 0;
m_nFilePos = 0;
m_nLength = 0;
m_cubSequentialRead = 0;
m_PackFileID = 0;
m_nPackFileNumber = 0;
m_bPackOrVPKFile = false;
m_bFileInVPK = false;
m_cubTotalRead = 0;
}
CRC32_t m_crcIdentifier;
CUtlString m_filename;
CUtlString m_path;
int m_nFileFraction;
MD5Context_t m_md5ctx;
FileHash_t m_filehashFinal;
FileHash_t m_filehashInProgress;
int m_cubTotalRead;
int64 m_nFilePos;
int64 m_nLength;
int64 m_cubSequentialRead;
int m_idxRecentFileList;
int m_PackFileID;
int m_nPackFileNumber;
bool m_bPackOrVPKFile;
bool m_bFileInVPK;
void RebuildFileName( const char *pFilename, const char *pPathID )
{
m_filename = pFilename;
m_path = pPathID;
CRC32_t crcFilename;
CRC32_Init( &crcFilename );
CRC32_ProcessBuffer( &crcFilename, pFilename, Q_strlen( pFilename ) );
if ( pPathID )
CRC32_ProcessBuffer( &crcFilename, pPathID, Q_strlen( pPathID ) );
CRC32_Final( &crcFilename );
m_crcIdentifier = crcFilename;
}
static bool Less( const TrackedFile_t& lhs, const TrackedFile_t& rhs )
{
if ( lhs.m_crcIdentifier < rhs.m_crcIdentifier )
return true;
if ( lhs.m_crcIdentifier > rhs.m_crcIdentifier )
return false;
if ( lhs.m_nFileFraction < rhs.m_nFileFraction )
return true;
if ( lhs.m_nFileFraction > rhs.m_nFileFraction )
return false;
int nCmp = Q_strcmp( lhs.m_filename.String(), rhs.m_filename.String() );
if ( nCmp < 0 )
return true;
if ( nCmp > 0 )
return false;
nCmp = Q_strcmp( lhs.m_path.String(), rhs.m_path.String() );
if ( nCmp < 0 )
return true;
return false;
}
bool GetCRCValues( FileHash_t *pFileHash );
void ProcessFileRead( void *dest, size_t nBytesRead );
};
struct FileInVPK_t
{
FileInVPK_t()
{
m_PackFileID = 0;
m_nPackFileNumber = 0;
m_nFileOffset = 0;
}
int m_PackFileID;
int m_nPackFileNumber;
int m_nFileOffset;
int m_idxAllOpenedFiles;
static bool Less( const FileInVPK_t& lhs, const FileInVPK_t& rhs )
{
if ( lhs.m_nFileOffset < rhs.m_nFileOffset )
return true;
if ( lhs.m_nFileOffset > rhs.m_nFileOffset )
return false;
if ( lhs.m_nPackFileNumber < rhs.m_nPackFileNumber )
return true;
if ( lhs.m_nPackFileNumber > rhs.m_nPackFileNumber )
return false;
if ( lhs.m_PackFileID < rhs.m_PackFileID )
return true;
if ( lhs.m_PackFileID > rhs.m_PackFileID )
return false;
return false;
}
};
struct TrackedVPKFile_t
{
TrackedVPKFile_t()
{
m_PackFileID = 0;
m_nPackFileNumber = 0;
}
int m_PackFileID;
int m_nPackFileNumber;
int m_nFileFraction;
int m_idxAllOpenedFiles;
static bool Less( const TrackedVPKFile_t& lhs, const TrackedVPKFile_t& rhs )
{
if ( lhs.m_nPackFileNumber < rhs.m_nPackFileNumber )
return true;
if ( lhs.m_nPackFileNumber > rhs.m_nPackFileNumber )
return false;
if ( lhs.m_nFileFraction < rhs.m_nFileFraction )
return true;
if ( lhs.m_nFileFraction > rhs.m_nFileFraction )
return false;
if ( lhs.m_PackFileID < rhs.m_PackFileID )
return true;
if ( lhs.m_PackFileID > rhs.m_PackFileID )
return false;
return false;
}
};
class StuffToMD5_t
{
public:
uint8 *m_pubBuffer;
int m_cubBuffer;
MD5Value_t m_md5Value;
int m_PackFileID;
int m_nPackFileNumber;
int m_nPackFileFraction;
int m_idxListSubmittedJobs;
};
class SubmittedMd5Job_t
{
public:
bool m_bFinished;
MD5Value_t m_md5Value;
};
class CFileTracker2
#ifdef SUPPORT_VPK
: IThreadedFileMD5Processor
#endif
{
public:
CFileTracker2( CBaseFileSystem *pFileSystem );
~CFileTracker2();
void InitAsyncThread();
void ShutdownAsync();
void MarkAllCRCsUnverified();
int GetUnverifiedFileHashes( CUnverifiedFileHash *pFiles, int nMaxFiles );
EFileCRCStatus CheckCachedFileHash( const char *pPathID, const char *pRelativeFilename, int nFileFraction, FileHash_t *pFileHash );
#ifdef SUPPORT_VPK
unsigned ThreadedProcessMD5Requests();
virtual int SubmitThreadedMD5Request( uint8 *pubBuffer, int cubBuffer, int PackFileID, int nPackFileNumber, int nPackFileFraction );
virtual bool BlockUntilMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut );
virtual bool IsMD5RequestComplete( int iRequest, MD5Value_t *pMd5ValueOut );
int NotePackFileOpened( const char *pRawFileName, const char *pFilename, const char *pPathID, int64 nLength );
void NotePackFileAccess( const char *pFilename, const char *pPathID, CPackedStoreFileHandle &VPKHandle );
void NotePackFileRead( CPackedStoreFileHandle &VPKHandle, void *pBuffer, int nReadLength );
void AddFileHashForVPKFile( int nPackFileNumber, int nFileFraction, int cbFileLen, MD5Value_t &md5, CPackedStoreFileHandle &fhandle );
#endif
void NoteFileLoadedFromDisk( const char *pFilename, const char *pPathID, FILE *fp, int64 nLength );
void RecordFileSeek( FILE *fp, int64 pos, int seekType );
void RecordFileClose( FILE *fp );
void RecordFileRead( void *dest, size_t nBytesRead, size_t nBytesRequested, FILE *fp );
int ListOpenedFiles( bool bListAll, const char *pchFilenameFind, bool bListRecentFiles );
private:
int IdxFileFromName( const char *pFilename, const char *pPathID, int nFileFraction, int64 nLength, bool bPackOrVPKFile, bool bRecordInRecentList );
static const int k_nFileFractionSize = 0x00100000; // 1 MB
static const int k_nFileFractionMask = 0xFFF00000; // 1 MB
CUtlRBTree< TrackedFile_t, int > m_treeAllOpenedFiles;
CUtlMap< FILE *, int, int > m_mapAllOpenFiles; // points into m_treeAllOpenedFiles
CUtlRBTree< FileInVPK_t, int > m_treeFileInVPK;
CUtlRBTree< TrackedVPKFile_t, int > m_treeTrackedVPKFiles;
CUtlLinkedList<int> m_RecentFileList; // points into m_treeAllOpenedFiles
int m_cMissedReads;
CBaseFileSystem *m_pFileSystem;
CThreadMutex m_Mutex; // Threads call into here, so we need to be safe.
bool m_bComputeFileHashes;
CThreadEvent m_threadEventWorkToDo;
CThreadEvent m_threadEventWorkCompleted;
volatile bool m_bThreadShouldRun;
ThreadHandle_t m_hWorkThread;
CTSQueue< StuffToMD5_t > m_PendingJobs;
CTSQueue< StuffToMD5_t > m_CompletedJobs;
CUtlLinkedList< SubmittedMd5Job_t > m_SubmittedJobs;
// just stats
int m_cThreadBlocks;
};
#endif // FILETRACKER_H

View File

@ -0,0 +1,261 @@
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include <dirent.h>
#include "tier1/strtools.h"
#include "tier0/memdbgoff.h"
#include "linux_support.h"
#ifdef OSX
#include <AvailabilityMacros.h>
#endif
char selectBuf[PATH_MAX];
#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_9)
int FileSelect(struct dirent *ent)
#else
int FileSelect(const struct dirent *ent)
#endif
{
const char *mask=selectBuf;
const char *name=ent->d_name;
//printf("Test:%s %s\n",mask,name);
if(!strcmp(name,".") || !strcmp(name,"..") ) return 0;
if(!strcmp(selectBuf,"*.*")) return 1;
while( *mask && *name )
{
if(*mask=='*')
{
mask++; // move to the next char in the mask
if(!*mask) // if this is the end of the mask its a match
{
return 1;
}
while(*name && toupper(*name)!=toupper(*mask))
{ // while the two don't meet up again
name++;
}
if(!*name)
{ // end of the name
break;
}
}
else if (*mask!='?')
{
if( toupper(*mask) != toupper(*name) )
{ // mismatched!
return 0;
}
else
{
mask++;
name++;
if( !*mask && !*name)
{ // if its at the end of the buffer
return 1;
}
}
}
else /* mask is "?", we don't care*/
{
mask++;
name++;
}
}
return( !*mask && !*name ); // both of the strings are at the end
}
int FillDataStruct(FIND_DATA *dat)
{
struct stat fileStat;
if(dat->numMatches<0)
return -1;
char szFullPath[MAX_PATH];
Q_snprintf( szFullPath, sizeof(szFullPath), "%s/%s", dat->cBaseDir, dat->namelist[dat->numMatches]->d_name );
if(!stat(szFullPath,&fileStat))
{
dat->dwFileAttributes=fileStat.st_mode;
}
else
{
dat->dwFileAttributes=0;
}
// now just put the filename in the output data
Q_snprintf( dat->cFileName, sizeof(dat->cFileName), "%s", dat->namelist[dat->numMatches]->d_name );
//printf("%s\n", dat->namelist[dat->numMatches]->d_name);
free(dat->namelist[dat->numMatches]);
dat->numMatches--;
return 1;
}
HANDLE FindFirstFile( const char *fileName, FIND_DATA *dat)
{
char nameStore[PATH_MAX];
char *dir=NULL;
int n,iret=-1;
Q_strncpy(nameStore,fileName, sizeof( nameStore ) );
if(strrchr(nameStore,'/') )
{
dir=nameStore;
while(strrchr(dir,'/') )
{
struct stat dirChk;
// zero this with the dir name
dir=strrchr(nameStore,'/');
*dir='\0';
dir=nameStore;
stat(dir,&dirChk);
if( S_ISDIR( dirChk.st_mode ) )
{
break;
}
}
}
else
{
// couldn't find a dir seperator...
return (HANDLE)-1;
}
if( strlen(dir)>0 )
{
Q_strncpy(selectBuf,fileName+strlen(dir)+1, sizeof( selectBuf ) );
Q_strncpy(dat->cBaseDir,dir, sizeof( dat->cBaseDir ) );
dat->namelist = NULL;
n = scandir(dir, &dat->namelist, FileSelect, alphasort);
if (n < 0)
{
// silently return, nothing interesting
dat->namelist = NULL;
}
else
{
dat->numMatches=n-1; // n is the number of matches
iret=FillDataStruct(dat);
if ( ( iret<0 ) && dat->namelist )
{
free(dat->namelist);
dat->namelist = NULL;
}
}
}
// printf("Returning: %i \n",iret);
return (HANDLE)(intp)iret;
}
bool FindNextFile(HANDLE handle, FIND_DATA *dat)
{
if(dat->numMatches<0)
{
if ( dat->namelist != NULL )
{
free( dat->namelist );
dat->namelist = NULL;
}
return false; // no matches left
}
FillDataStruct(dat);
return true;
}
bool FindClose(HANDLE handle)
{
return true;
}
static char fileName[MAX_PATH];
#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_9)
int CheckName(struct dirent *dir)
#else
int CheckName(const struct dirent *dir)
#endif
{
return !strcasecmp( dir->d_name, fileName );
}
const char *findFileInDirCaseInsensitive(const char *file, char *pFileNameOut)
{
const char *dirSep = strrchr(file,'/');
if( !dirSep )
{
dirSep=strrchr(file,'\\');
if( !dirSep )
{
return NULL;
}
}
char *dirName = static_cast<char *>( alloca( ( dirSep - file ) +1 ) );
if( !dirName )
return NULL;
strncpy( dirName , file, dirSep - file );
dirName[ dirSep - file ] = '\0';
struct dirent **namelist = NULL;
strncpy( fileName, dirSep + 1, MAX_PATH );
int n = scandir( dirName , &namelist, CheckName, alphasort );
// Free all entries beyond the first one, we don't care about them
while ( n > 1 )
{
-- n;
free( namelist[n] );
}
if ( n > 0 )
{
Q_snprintf( pFileNameOut, sizeof( fileName ), "%s/%s", dirName, namelist[0]->d_name );
free( namelist[0] );
n = 0;
}
else
{
Q_strncpy( pFileNameOut, file, MAX_PATH );
Q_strlower( pFileNameOut );
}
if ( ( n >= 0 ) && namelist )
{
free( namelist );
}
return pFileNameOut;
}

View File

@ -0,0 +1,40 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef LINUX_SUPPORT_H
#define LINUX_SUPPORT_H
#include <ctype.h> // tolower()
#include <limits.h> // PATH_MAX define
#include <string.h> //strcmp, strcpy
#include <sys/stat.h> // stat()
#include <unistd.h>
#include <dirent.h> // scandir()
#include <stdlib.h>
#include <stdio.h>
#include "tier0/platform.h"
#define FILE_ATTRIBUTE_DIRECTORY S_IFDIR
typedef struct
{
// public data
int dwFileAttributes;
char cFileName[PATH_MAX]; // the file name returned from the call
char cBaseDir[PATH_MAX]; // the root dir for this find
int numMatches;
struct dirent **namelist;
} FIND_DATA;
#define WIN32_FIND_DATA FIND_DATA
HANDLE FindFirstFile( const char *findName, FIND_DATA *dat);
bool FindNextFile(HANDLE handle, FIND_DATA *dat);
bool FindClose(HANDLE handle);
const char *findFileInDirCaseInsensitive(const char* path, char *file);
#endif // LINUX_SUPPORT_H

View 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

1
filesystem/vsi.nul Normal file
View File

@ -0,0 +1 @@
IMPORTANT: Do not remove the custom build step for this file

3
filesystem/xbox/xbox.def Normal file
View File

@ -0,0 +1,3 @@
LIBRARY filesystem_stdio_360.dll
EXPORTS
CreateInterface @1