uid issue
This commit is contained in:
356
utils/binlaunch/binlaunch.cpp
Normal file
356
utils/binlaunch/binlaunch.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/basetypes.h"
|
||||
#include "ilaunchabledll.h"
|
||||
|
||||
|
||||
#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#pragma warning(disable : 4127)
|
||||
#define CORRECT_PATH_SEPARATOR_S "\\"
|
||||
#define CORRECT_PATH_SEPARATOR '\\'
|
||||
#define INCORRECT_PATH_SEPARATOR '/'
|
||||
#else
|
||||
#define CORRECT_PATH_SEPARATOR '/'
|
||||
#define CORRECT_PATH_SEPARATOR_S "/"
|
||||
#define INCORRECT_PATH_SEPARATOR '\\'
|
||||
#endif
|
||||
|
||||
#undef stricmp
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#define V_stricmp stricmp
|
||||
#else
|
||||
#define V_stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
#define CREATEINTERFACE_PROCNAME "CreateInterface"
|
||||
typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode);
|
||||
|
||||
|
||||
static void V_strncpy( char *pDest, char const *pSrc, int maxLen )
|
||||
{
|
||||
strncpy( pDest, pSrc, maxLen );
|
||||
if ( maxLen > 0 )
|
||||
{
|
||||
pDest[maxLen-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int V_strlen( const char *pStr )
|
||||
{
|
||||
return (int)strlen( pStr );
|
||||
}
|
||||
|
||||
static void V_strncat( char *pDest, const char *pSrc, int destSize )
|
||||
{
|
||||
strncat( pDest, pSrc, destSize );
|
||||
pDest[destSize-1] = 0;
|
||||
}
|
||||
|
||||
static void V_AppendSlash( char *pStr, int strSize )
|
||||
{
|
||||
int len = V_strlen( pStr );
|
||||
if ( len > 0 && !PATHSEPARATOR(pStr[len-1]) )
|
||||
{
|
||||
if ( len+1 >= strSize )
|
||||
{
|
||||
fprintf( stderr, "V_AppendSlash: ran out of space on %s.", pStr );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
pStr[len] = CORRECT_PATH_SEPARATOR;
|
||||
pStr[len+1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void V_FixSlashes( char *pStr )
|
||||
{
|
||||
for ( ; *pStr; ++pStr )
|
||||
{
|
||||
if ( *pStr == INCORRECT_PATH_SEPARATOR )
|
||||
*pStr = CORRECT_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
static void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize )
|
||||
{
|
||||
V_strncpy( dest, path, destSize );
|
||||
V_AppendSlash( dest, destSize );
|
||||
V_strncat( dest, filename, destSize );
|
||||
V_FixSlashes( dest );
|
||||
}
|
||||
|
||||
static int V_snprintf( char *pDest, int maxLen, const char *pFormat, ... )
|
||||
{
|
||||
va_list marker;
|
||||
|
||||
va_start( marker, pFormat );
|
||||
#ifdef _WIN32
|
||||
int len = _vsnprintf( pDest, maxLen, pFormat, marker );
|
||||
#elif POSIX
|
||||
int len = vsnprintf( pDest, maxLen, pFormat, marker );
|
||||
#else
|
||||
#error "define vsnprintf type."
|
||||
#endif
|
||||
va_end( marker );
|
||||
|
||||
// Len < 0 represents an overflow
|
||||
if( len < 0 )
|
||||
{
|
||||
len = maxLen;
|
||||
pDest[maxLen-1] = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool V_StripLastDir( char *dirName, int maxlen )
|
||||
{
|
||||
if( dirName[0] == 0 || !V_stricmp( dirName, "./" ) || !V_stricmp( dirName, ".\\" ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = V_strlen( dirName );
|
||||
|
||||
// skip trailing slash
|
||||
if ( PATHSEPARATOR( dirName[len-1] ) )
|
||||
{
|
||||
len--;
|
||||
}
|
||||
|
||||
while ( len > 0 )
|
||||
{
|
||||
if ( PATHSEPARATOR( dirName[len-1] ) )
|
||||
{
|
||||
dirName[len] = 0;
|
||||
V_FixSlashes( dirName );
|
||||
return true;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
|
||||
// Allow it to return an empty string and true. This can happen if something like "tf2/" is passed in.
|
||||
// The correct behavior is to strip off the last directory ("tf2") and return true.
|
||||
if( len == 0 )
|
||||
{
|
||||
V_snprintf( dirName, maxlen, ".%c", CORRECT_PATH_SEPARATOR );
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef struct _REPARSE_DATA_BUFFER {
|
||||
ULONG ReparseTag;
|
||||
USHORT ReparseDataLength;
|
||||
USHORT Reserved;
|
||||
union {
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[1];
|
||||
} SymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
USHORT PrintNameOffset;
|
||||
USHORT PrintNameLength;
|
||||
WCHAR PathBuffer[1];
|
||||
} MountPointReparseBuffer;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
|
||||
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
|
||||
#define IO_REPARSE_TAG_SYMLINK 0xa0000003
|
||||
|
||||
void TranslateSymlink( const char *pInDir, char *pOutDir, int len )
|
||||
{
|
||||
// This is the default. If it's a reparse point, it'll get replaced below.
|
||||
V_strncpy( pOutDir, pInDir, len );
|
||||
|
||||
// The equivalent of symlinks in Win32 is "NTFS reparse points".
|
||||
DWORD nAttribs = GetFileAttributes( pInDir );
|
||||
if ( nAttribs & FILE_ATTRIBUTE_REPARSE_POINT )
|
||||
{
|
||||
HANDLE hDir = CreateFile( pInDir, FILE_READ_EA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL );
|
||||
if ( hDir )
|
||||
{
|
||||
DWORD dwBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
|
||||
REPARSE_DATA_BUFFER *pReparseData = (REPARSE_DATA_BUFFER*)malloc( dwBufSize );
|
||||
|
||||
DWORD nBytesReturned = 0;
|
||||
BOOL bSuccess = DeviceIoControl( hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, pReparseData, dwBufSize, &nBytesReturned, NULL );
|
||||
CloseHandle( hDir );
|
||||
|
||||
if ( bSuccess )
|
||||
{
|
||||
if ( IsReparseTagMicrosoft( pReparseData->ReparseTag ) )
|
||||
{
|
||||
if ( pReparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK )
|
||||
{
|
||||
REPARSE_DATA_BUFFER *rdata = pReparseData;
|
||||
|
||||
// Pull out the substitution name.
|
||||
char szSubName[MAX_PATH*2];
|
||||
wchar_t *pSrcString = &rdata->SymbolicLinkReparseBuffer.PathBuffer[rdata->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)];
|
||||
size_t nConvertedChars;
|
||||
wcstombs_s( &nConvertedChars, szSubName, wcslen( pSrcString ) + 1, pSrcString, _TRUNCATE );
|
||||
|
||||
// Look for the drive letter and start there.
|
||||
const char *pColon = strchr( szSubName, ':' );
|
||||
if ( pColon && pColon > szSubName )
|
||||
{
|
||||
const char *pRemappedName = ( pColon - 1 );
|
||||
V_strncpy( pOutDir, pRemappedName, len );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free( pReparseData );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Warning: Found a reparse point (ntfs symlink) for %s but CreateFile failed\n", pInDir );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
// Find the game\bin directory and setup the DLL path.
|
||||
char szModuleFilename[MAX_PATH], szModuleParts[MAX_PATH], szCurDir[MAX_PATH];
|
||||
#ifdef WIN32
|
||||
GetModuleFileName( NULL, szModuleFilename, sizeof( szModuleFilename ) );
|
||||
V_FixSlashes( szModuleFilename );
|
||||
#else
|
||||
V_strncpy( szModuleFilename, argv[0], sizeof(szModuleFilename) );
|
||||
#endif
|
||||
|
||||
V_strncpy( szModuleParts, szModuleFilename, sizeof( szModuleParts ) );
|
||||
char *pFilename = strrchr( szModuleParts, CORRECT_PATH_SEPARATOR );
|
||||
if ( !pFilename )
|
||||
{
|
||||
fprintf( stderr, "%s (binlaunch): Can't get filename from GetModuleFilename (%s).\n", argv[0], szModuleFilename );
|
||||
return 1;
|
||||
}
|
||||
|
||||
*pFilename = 0;
|
||||
++pFilename;
|
||||
const char *pBaseDir = szModuleParts;
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
TranslateSymlink( pBaseDir, szCurDir, sizeof( szCurDir ) );
|
||||
#else
|
||||
V_strncpy( szCurDir, pBaseDir, sizeof(szCurDir) );
|
||||
#endif
|
||||
|
||||
char szGameBinDir[MAX_PATH];
|
||||
while ( 1 )
|
||||
{
|
||||
V_ComposeFileName( szCurDir, "game" CORRECT_PATH_SEPARATOR_S "bin", szGameBinDir, sizeof( szGameBinDir ) );
|
||||
|
||||
// Look for stuff we know about in game\bin.
|
||||
char szTestFile1[MAX_PATH], szTestFile2[MAX_PATH];
|
||||
V_ComposeFileName( szGameBinDir, "tier0.dll", szTestFile1, sizeof( szTestFile1 ) );
|
||||
V_ComposeFileName( szGameBinDir, "vstdlib.dll", szTestFile2, sizeof( szTestFile2 ) );
|
||||
if ( _access( szTestFile1, 0 ) == 0 && _access( szTestFile2, 0 ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Backup a directory.
|
||||
if ( !V_StripLastDir( szCurDir, sizeof( szCurDir ) ) )
|
||||
{
|
||||
fprintf( stderr, "%s (binlaunch): Unable to find game\\bin directory anywhere up the tree from %s.\n", argv[0], pBaseDir );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Setup the path to include the specified directory.
|
||||
int nGameBinDirLen = V_strlen( szGameBinDir );
|
||||
char *pOldPath = getenv( "PATH" );
|
||||
int nNewLen = V_strlen( pOldPath ) + nGameBinDirLen + 5 + 1 + 1; // 5 for PATH=, 1 for the semicolon, and 1 for the null terminator.
|
||||
char *pNewPath = new char[nNewLen];
|
||||
V_snprintf( pNewPath, nNewLen, "PATH=%s;%s", szGameBinDir, pOldPath );
|
||||
_putenv( pNewPath );
|
||||
delete [] pNewPath;
|
||||
|
||||
|
||||
// Get rid of the file extension on our executable name.
|
||||
#ifdef WIN32
|
||||
char *pDot = strchr( &szModuleFilename[pFilename-szModuleParts], '.' );
|
||||
if ( !pDot )
|
||||
{
|
||||
fprintf( stderr, "%s (binlaunch): No dot character in the filename.\n", argv[0] );
|
||||
return 1;
|
||||
}
|
||||
*pDot = 0;
|
||||
#endif
|
||||
|
||||
char szDLLName[MAX_PATH];
|
||||
V_snprintf( szDLLName, sizeof( szDLLName ), "%s%s", szModuleFilename, DLL_EXT_STRING );
|
||||
|
||||
//
|
||||
// Now go load their DLL and launch it.
|
||||
//
|
||||
#ifdef WIN32
|
||||
HMODULE hModule = LoadLibrary( szDLLName );
|
||||
#else
|
||||
HMODULE hModule = dlopen( szDLLName, RTLD_NOW );
|
||||
#endif
|
||||
if ( !hModule )
|
||||
{
|
||||
fprintf( stderr, "%s (binlaunch): Unable to load module %s\n\n", argv[0], szDLLName );
|
||||
return 9998;
|
||||
}
|
||||
|
||||
CreateInterfaceFn fn = (CreateInterfaceFn)GetProcAddress( hModule, CREATEINTERFACE_PROCNAME );
|
||||
ILaunchableDLL *pLaunchable;
|
||||
if ( !fn )
|
||||
{
|
||||
fprintf( stderr, "%s (binlaunch): Can't get function %s from %s\n\n", argv[0], CREATEINTERFACE_PROCNAME, szDLLName );
|
||||
return 9997;
|
||||
}
|
||||
|
||||
pLaunchable = (ILaunchableDLL*)fn( LAUNCHABLE_DLL_INTERFACE_VERSION, NULL );
|
||||
if ( !pLaunchable )
|
||||
{
|
||||
fprintf( stderr, "%s (binlaunch): Can't get interface %s from from %s\n\n", argv[0], LAUNCHABLE_DLL_INTERFACE_VERSION, szDLLName );
|
||||
return 9996;
|
||||
}
|
||||
|
||||
return pLaunchable->main( argc, argv );
|
||||
}
|
||||
|
||||
|
56
utils/binlaunch/binlaunch.vpc
Normal file
56
utils/binlaunch/binlaunch.vpc
Normal file
@ -0,0 +1,56 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// BINLAUNCH.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR "..\.."
|
||||
$Macro OUTBINDIR "$SRCDIR\devtools\bin"
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_exe_con_win32_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$PostBuildEvent
|
||||
{
|
||||
// Various projects like vpc and remotemirror use copies of the binlaunch.exe, so when binlaunch is built,
|
||||
// it copies to those exes.
|
||||
$CommandLine "$BASE" "\n" \
|
||||
"\n" \
|
||||
"echo ... Copying BINLAUNCH.EXE to REMOTEMIRROR.EXE" "\n" \
|
||||
"call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $SRCDIR\devtools\bin\remotemirror.exe $SRCDIR" "\n" \
|
||||
"copy $OUTBINDIR\$(TargetFileName) $SRCDIR\devtools\bin\remotemirror.exe" "\n" \
|
||||
"if ERRORLEVEL 1 goto BinLaunchCopyFailed" "\n" \
|
||||
"\n" \
|
||||
"echo ... Copying BINLAUNCH.EXE to SCHEMACOMPILER.EXE" "\n" \
|
||||
"call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $SRCDIR\devtools\bin\schemacompiler.exe $SRCDIR" "\n" \
|
||||
"copy $OUTBINDIR\$(TargetFileName) $SRCDIR\devtools\bin\schemacompiler.exe" "\n" \
|
||||
"if ERRORLEVEL 1 goto BinLaunchCopyFailed" "\n" \
|
||||
"\n" \
|
||||
"goto BinLaunchCopyOK" "\n" \
|
||||
"\n" \
|
||||
":BinLaunchCopyFailed" "\n" \
|
||||
"echo *** ERROR! binlaunch copy step failed." "\n" \
|
||||
"del /q $QUOTE$(TargetDir)$QUOTE$(TargetFileName)" "\n" \
|
||||
"exit 1" "\n" \
|
||||
"\n" \
|
||||
":BinLaunchCopyOK" "\n" \
|
||||
"\n"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "binlaunch"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "binlaunch.cpp"
|
||||
-$File "$SRCDIR\public\tier0\memoverride.cpp"
|
||||
}
|
||||
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
-$ImpLib tier0
|
||||
-$Lib tier1
|
||||
-$ImpLib vstdlib
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user