Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
9.1 KiB

  1. //================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
  2. //
  3. //
  4. //
  5. //==================================================================================================
  6. #ifdef _WIN32
  7. #define _WIN32_WINNT 0x0500
  8. #include <windows.h>
  9. #include <io.h>
  10. #else
  11. #include <stdarg.h>
  12. #include <dlfcn.h>
  13. #endif
  14. #include <stdio.h>
  15. #include "tier0/platform.h"
  16. #include "tier0/basetypes.h"
  17. #include "ilaunchabledll.h"
  18. #define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
  19. #ifdef PLATFORM_WINDOWS
  20. #pragma warning(disable : 4127)
  21. #define CORRECT_PATH_SEPARATOR_S "\\"
  22. #define CORRECT_PATH_SEPARATOR '\\'
  23. #define INCORRECT_PATH_SEPARATOR '/'
  24. #else
  25. #define CORRECT_PATH_SEPARATOR '/'
  26. #define CORRECT_PATH_SEPARATOR_S "/"
  27. #define INCORRECT_PATH_SEPARATOR '\\'
  28. #endif
  29. #undef stricmp
  30. #ifdef COMPILER_MSVC
  31. #define V_stricmp stricmp
  32. #else
  33. #define V_stricmp strcasecmp
  34. #endif
  35. #define CREATEINTERFACE_PROCNAME "CreateInterface"
  36. typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode);
  37. static void V_strncpy( char *pDest, char const *pSrc, int maxLen )
  38. {
  39. strncpy( pDest, pSrc, maxLen );
  40. if ( maxLen > 0 )
  41. {
  42. pDest[maxLen-1] = 0;
  43. }
  44. }
  45. static int V_strlen( const char *pStr )
  46. {
  47. return (int)strlen( pStr );
  48. }
  49. static void V_strncat( char *pDest, const char *pSrc, int destSize )
  50. {
  51. strncat( pDest, pSrc, destSize );
  52. pDest[destSize-1] = 0;
  53. }
  54. static void V_AppendSlash( char *pStr, int strSize )
  55. {
  56. int len = V_strlen( pStr );
  57. if ( len > 0 && !PATHSEPARATOR(pStr[len-1]) )
  58. {
  59. if ( len+1 >= strSize )
  60. {
  61. fprintf( stderr, "V_AppendSlash: ran out of space on %s.", pStr );
  62. exit( 1 );
  63. }
  64. pStr[len] = CORRECT_PATH_SEPARATOR;
  65. pStr[len+1] = 0;
  66. }
  67. }
  68. static void V_FixSlashes( char *pStr )
  69. {
  70. for ( ; *pStr; ++pStr )
  71. {
  72. if ( *pStr == INCORRECT_PATH_SEPARATOR )
  73. *pStr = CORRECT_PATH_SEPARATOR;
  74. }
  75. }
  76. static void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize )
  77. {
  78. V_strncpy( dest, path, destSize );
  79. V_AppendSlash( dest, destSize );
  80. V_strncat( dest, filename, destSize );
  81. V_FixSlashes( dest );
  82. }
  83. static int V_snprintf( char *pDest, int maxLen, const char *pFormat, ... )
  84. {
  85. va_list marker;
  86. va_start( marker, pFormat );
  87. #ifdef _WIN32
  88. int len = _vsnprintf( pDest, maxLen, pFormat, marker );
  89. #elif POSIX
  90. int len = vsnprintf( pDest, maxLen, pFormat, marker );
  91. #else
  92. #error "define vsnprintf type."
  93. #endif
  94. va_end( marker );
  95. // Len < 0 represents an overflow
  96. if( len < 0 )
  97. {
  98. len = maxLen;
  99. pDest[maxLen-1] = 0;
  100. }
  101. return len;
  102. }
  103. static bool V_StripLastDir( char *dirName, int maxlen )
  104. {
  105. if( dirName[0] == 0 || !V_stricmp( dirName, "./" ) || !V_stricmp( dirName, ".\\" ) )
  106. {
  107. return false;
  108. }
  109. int len = V_strlen( dirName );
  110. // skip trailing slash
  111. if ( PATHSEPARATOR( dirName[len-1] ) )
  112. {
  113. len--;
  114. }
  115. while ( len > 0 )
  116. {
  117. if ( PATHSEPARATOR( dirName[len-1] ) )
  118. {
  119. dirName[len] = 0;
  120. V_FixSlashes( dirName );
  121. return true;
  122. }
  123. len--;
  124. }
  125. // Allow it to return an empty string and true. This can happen if something like "tf2/" is passed in.
  126. // The correct behavior is to strip off the last directory ("tf2") and return true.
  127. if( len == 0 )
  128. {
  129. V_snprintf( dirName, maxlen, ".%c", CORRECT_PATH_SEPARATOR );
  130. return true;
  131. }
  132. return true;
  133. }
  134. #ifdef _WIN32
  135. typedef struct _REPARSE_DATA_BUFFER {
  136. ULONG ReparseTag;
  137. USHORT ReparseDataLength;
  138. USHORT Reserved;
  139. union {
  140. struct {
  141. USHORT SubstituteNameOffset;
  142. USHORT SubstituteNameLength;
  143. USHORT PrintNameOffset;
  144. USHORT PrintNameLength;
  145. ULONG Flags;
  146. WCHAR PathBuffer[1];
  147. } SymbolicLinkReparseBuffer;
  148. struct {
  149. USHORT SubstituteNameOffset;
  150. USHORT SubstituteNameLength;
  151. USHORT PrintNameOffset;
  152. USHORT PrintNameLength;
  153. WCHAR PathBuffer[1];
  154. } MountPointReparseBuffer;
  155. struct {
  156. UCHAR DataBuffer[1];
  157. } GenericReparseBuffer;
  158. };
  159. } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
  160. #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
  161. #define IO_REPARSE_TAG_SYMLINK 0xa0000003
  162. void TranslateSymlink( const char *pInDir, char *pOutDir, int len )
  163. {
  164. // This is the default. If it's a reparse point, it'll get replaced below.
  165. V_strncpy( pOutDir, pInDir, len );
  166. // The equivalent of symlinks in Win32 is "NTFS reparse points".
  167. DWORD nAttribs = GetFileAttributes( pInDir );
  168. if ( nAttribs & FILE_ATTRIBUTE_REPARSE_POINT )
  169. {
  170. 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 );
  171. if ( hDir )
  172. {
  173. DWORD dwBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
  174. REPARSE_DATA_BUFFER *pReparseData = (REPARSE_DATA_BUFFER*)malloc( dwBufSize );
  175. DWORD nBytesReturned = 0;
  176. BOOL bSuccess = DeviceIoControl( hDir, FSCTL_GET_REPARSE_POINT, NULL, 0, pReparseData, dwBufSize, &nBytesReturned, NULL );
  177. CloseHandle( hDir );
  178. if ( bSuccess )
  179. {
  180. if ( IsReparseTagMicrosoft( pReparseData->ReparseTag ) )
  181. {
  182. if ( pReparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK )
  183. {
  184. REPARSE_DATA_BUFFER *rdata = pReparseData;
  185. // Pull out the substitution name.
  186. char szSubName[MAX_PATH*2];
  187. wchar_t *pSrcString = &rdata->SymbolicLinkReparseBuffer.PathBuffer[rdata->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)];
  188. size_t nConvertedChars;
  189. wcstombs_s( &nConvertedChars, szSubName, wcslen( pSrcString ) + 1, pSrcString, _TRUNCATE );
  190. // Look for the drive letter and start there.
  191. const char *pColon = strchr( szSubName, ':' );
  192. if ( pColon && pColon > szSubName )
  193. {
  194. const char *pRemappedName = ( pColon - 1 );
  195. V_strncpy( pOutDir, pRemappedName, len );
  196. }
  197. }
  198. }
  199. }
  200. free( pReparseData );
  201. }
  202. else
  203. {
  204. printf( "Warning: Found a reparse point (ntfs symlink) for %s but CreateFile failed\n", pInDir );
  205. }
  206. }
  207. }
  208. #endif
  209. int main( int argc, char **argv )
  210. {
  211. // Find the game\bin directory and setup the DLL path.
  212. char szModuleFilename[MAX_PATH], szModuleParts[MAX_PATH], szCurDir[MAX_PATH];
  213. #ifdef WIN32
  214. GetModuleFileName( NULL, szModuleFilename, sizeof( szModuleFilename ) );
  215. V_FixSlashes( szModuleFilename );
  216. #else
  217. V_strncpy( szModuleFilename, argv[0], sizeof(szModuleFilename) );
  218. #endif
  219. V_strncpy( szModuleParts, szModuleFilename, sizeof( szModuleParts ) );
  220. char *pFilename = strrchr( szModuleParts, CORRECT_PATH_SEPARATOR );
  221. if ( !pFilename )
  222. {
  223. fprintf( stderr, "%s (binlaunch): Can't get filename from GetModuleFilename (%s).\n", argv[0], szModuleFilename );
  224. return 1;
  225. }
  226. *pFilename = 0;
  227. ++pFilename;
  228. const char *pBaseDir = szModuleParts;
  229. #ifdef WIN32
  230. TranslateSymlink( pBaseDir, szCurDir, sizeof( szCurDir ) );
  231. #else
  232. V_strncpy( szCurDir, pBaseDir, sizeof(szCurDir) );
  233. #endif
  234. char szGameBinDir[MAX_PATH];
  235. while ( 1 )
  236. {
  237. V_ComposeFileName( szCurDir, "game" CORRECT_PATH_SEPARATOR_S "bin", szGameBinDir, sizeof( szGameBinDir ) );
  238. // Look for stuff we know about in game\bin.
  239. char szTestFile1[MAX_PATH], szTestFile2[MAX_PATH];
  240. V_ComposeFileName( szGameBinDir, "tier0.dll", szTestFile1, sizeof( szTestFile1 ) );
  241. V_ComposeFileName( szGameBinDir, "vstdlib.dll", szTestFile2, sizeof( szTestFile2 ) );
  242. if ( _access( szTestFile1, 0 ) == 0 && _access( szTestFile2, 0 ) == 0 )
  243. {
  244. break;
  245. }
  246. // Backup a directory.
  247. if ( !V_StripLastDir( szCurDir, sizeof( szCurDir ) ) )
  248. {
  249. fprintf( stderr, "%s (binlaunch): Unable to find game\\bin directory anywhere up the tree from %s.\n", argv[0], pBaseDir );
  250. return 1;
  251. }
  252. }
  253. // Setup the path to include the specified directory.
  254. int nGameBinDirLen = V_strlen( szGameBinDir );
  255. char *pOldPath = getenv( "PATH" );
  256. int nNewLen = V_strlen( pOldPath ) + nGameBinDirLen + 5 + 1 + 1; // 5 for PATH=, 1 for the semicolon, and 1 for the null terminator.
  257. char *pNewPath = new char[nNewLen];
  258. V_snprintf( pNewPath, nNewLen, "PATH=%s;%s", szGameBinDir, pOldPath );
  259. _putenv( pNewPath );
  260. delete [] pNewPath;
  261. // Get rid of the file extension on our executable name.
  262. #ifdef WIN32
  263. char *pDot = strchr( &szModuleFilename[pFilename-szModuleParts], '.' );
  264. if ( !pDot )
  265. {
  266. fprintf( stderr, "%s (binlaunch): No dot character in the filename.\n", argv[0] );
  267. return 1;
  268. }
  269. *pDot = 0;
  270. #endif
  271. char szDLLName[MAX_PATH];
  272. V_snprintf( szDLLName, sizeof( szDLLName ), "%s%s", szModuleFilename, DLL_EXT_STRING );
  273. //
  274. // Now go load their DLL and launch it.
  275. //
  276. #ifdef WIN32
  277. HMODULE hModule = LoadLibrary( szDLLName );
  278. #else
  279. HMODULE hModule = dlopen( szDLLName, RTLD_NOW );
  280. #endif
  281. if ( !hModule )
  282. {
  283. fprintf( stderr, "%s (binlaunch): Unable to load module %s\n\n", argv[0], szDLLName );
  284. return 9998;
  285. }
  286. CreateInterfaceFn fn = (CreateInterfaceFn)GetProcAddress( hModule, CREATEINTERFACE_PROCNAME );
  287. ILaunchableDLL *pLaunchable;
  288. if ( !fn )
  289. {
  290. fprintf( stderr, "%s (binlaunch): Can't get function %s from %s\n\n", argv[0], CREATEINTERFACE_PROCNAME, szDLLName );
  291. return 9997;
  292. }
  293. pLaunchable = (ILaunchableDLL*)fn( LAUNCHABLE_DLL_INTERFACE_VERSION, NULL );
  294. if ( !pLaunchable )
  295. {
  296. fprintf( stderr, "%s (binlaunch): Can't get interface %s from from %s\n\n", argv[0], LAUNCHABLE_DLL_INTERFACE_VERSION, szDLLName );
  297. return 9996;
  298. }
  299. return pLaunchable->main( argc, argv );
  300. }