source-engine/utils/itemtest_lib/systemutils.cpp

265 lines
7.3 KiB
C++
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Stuff which interacts with system libraries
//
//=============================================================================
// Windows includes
#include <windows.h>
#include <direct.h>
// Valve includes
#include "itemtest/itemtest.h"
#include "tier1/fmtstr.h"
// Last include
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;
#define BUFSIZE 4096
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CItemUpload::CreateDirectory( const char *pszDirectory )
{
char szBuf[ BUFSIZE ];
V_strncpy( szBuf, pszDirectory, 1024 );
for ( int i = 0; i < V_strlen( szBuf ); ++i )
{
if ( szBuf[i] == '/' || szBuf[i] == '\\' )
{
szBuf[i] = '\0';
mkdir( szBuf );
szBuf[i] = CORRECT_PATH_SEPARATOR;
}
}
mkdir( szBuf );
return true;
}
//-----------------------------------------------------------------------------
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
//-----------------------------------------------------------------------------
static void ReadFromPipe( CItemLog *pLog )
{
DWORD dwRead;
char chBuf[BUFSIZE + 1];
BOOL bSuccess = FALSE;
// Close the write end of the pipe before reading from the
// read end of the pipe, to control child process execution.
// The pipe is assumed to have enough buffer space to hold the
// data the child process has already written to it.
if ( !CloseHandle( g_hChildStd_OUT_Wr ) )
return;
// TODO: Prefix each line, print in color?
for (;;)
{
// This can hang if the process is waiting for input, for example...
bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL );
if ( !bSuccess || dwRead == 0 )
break;
chBuf[dwRead] = '\0';
pLog->Warning( chBuf );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CItemUpload::RunCommandLine( const char *pszCmdLine, const char *pszWorkingDir, CItemLog *pLog )
{
bool bOk = false;
Msg( "Launching: %s\n", pszCmdLine );
Msg( "Directory: %s\n", pszWorkingDir );
if ( pLog )
{
SECURITY_ATTRIBUTES saAttr;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if ( !CreatePipe( &g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0 ) )
return false;
// Ensure the read handle to the pipe for STDOUT is not inherited.
if ( !SetHandleInformation( g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0 ) )
return false;
}
// Create the child process.
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
// Set up members of the PROCESS_INFORMATION structure.
V_memset( &piProcInfo, 0, sizeof( PROCESS_INFORMATION ) );
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
V_memset( &siStartInfo, 0, sizeof( STARTUPINFO ) );
siStartInfo.cb = sizeof( STARTUPINFO );
if ( pLog )
{
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
}
// Create the child process.
const BOOL bSuccess = CreateProcess(NULL,
const_cast< char * >( pszCmdLine ), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NO_WINDOW, // creation flags
NULL, // use parent's environment
pszWorkingDir, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo ); // receives PROCESS_INFORMATION
// If an error occurs, return
if ( !bSuccess )
return false;
if ( pLog )
{
ReadFromPipe( pLog );
WaitForSingleObject( piProcInfo.hProcess, INFINITE );
bOk = false;
DWORD nExitCode = 0;
if ( GetExitCodeProcess( piProcInfo.hProcess, &nExitCode ) )
{
bOk = ( nExitCode == 0 );
}
CloseHandle( piProcInfo.hProcess );
CloseHandle( piProcInfo.hThread );
}
else
{
bOk = true;
}
return bOk;
}
//-----------------------------------------------------------------------------
// Determine if 2 paths point ot the same file...
// Note: This only works if the file exists
//-----------------------------------------------------------------------------
bool CItemUpload::IsSameFile( const char *szPath1, const char *szPath2 )
{
if ( !szPath1 || !szPath2 )
return false;
HANDLE handle1 = ::CreateFile( szPath1, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
HANDLE handle2 = ::CreateFile( szPath2, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
bool bResult = false;
if ( handle1 != NULL && handle2 != NULL )
{
BY_HANDLE_FILE_INFORMATION fileInfo1;
BY_HANDLE_FILE_INFORMATION fileInfo2;
if ( ::GetFileInformationByHandle( handle1, &fileInfo1 ) && ::GetFileInformationByHandle( handle2, &fileInfo2 ) )
{
bResult = fileInfo1.dwVolumeSerialNumber == fileInfo2.dwVolumeSerialNumber &&
fileInfo1.nFileIndexHigh == fileInfo2.nFileIndexHigh &&
fileInfo1.nFileIndexLow == fileInfo2.nFileIndexLow;
}
}
if ( handle1 != NULL )
{
::CloseHandle(handle1);
}
if ( handle2 != NULL )
{
::CloseHandle( handle2 );
}
return bResult;
}
//-----------------------------------------------------------------------------
// Gets the filename to the current executable
//-----------------------------------------------------------------------------
bool CItemUpload::GetCurrentExecutableFileName( CUtlString &sCurrentExecutableFileName )
{
char szModuleFileName[MAX_PATH];
szModuleFileName[0] = '\0';
if ( !::GetModuleFileName( (HMODULE)NULL, szModuleFileName, ARRAYSIZE( szModuleFileName ) ) )
return false;
sCurrentExecutableFileName = szModuleFileName;
return true;
}
//-----------------------------------------------------------------------------
// Get the install location of the app from the registry via
//
// HKEY_LOCAL_MACHINE :
// "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App %d"
//
//-----------------------------------------------------------------------------
bool CItemUpload::GetSteamAppInstallLocation( CUtlString &sSteamAppInstallLocation, int nAppId )
{
HKEY hKey;
char szSteamAppInstallLocation[ 65536 ] = "";
const CFmtStr sRegKey( "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App %d", nAppId );
if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, sRegKey.String(), &hKey ) )
{
DWORD dwSize = sizeof( szSteamAppInstallLocation );
RegQueryValueEx( hKey, "InstallLocation", NULL, NULL, (LPBYTE)szSteamAppInstallLocation, &dwSize );
RegCloseKey( hKey );
sSteamAppInstallLocation = szSteamAppInstallLocation;
return true;
}
return false;
}