4574 lines
		
	
	
		
			129 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			4574 lines
		
	
	
		
			129 KiB
		
	
	
	
		
			C++
		
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| //  Detours Test Program (trcbld.cpp of trcbld.dll)
 | |
| //
 | |
| //  Microsoft Research Detours Package
 | |
| //
 | |
| //  Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| //
 | |
| 
 | |
| #define _WIN32_WINNT        0x0500
 | |
| #define WIN32
 | |
| #define NT
 | |
| 
 | |
| #define DBG_TRACE   0
 | |
| 
 | |
| #include <windows.h>
 | |
| #include <stdio.h>
 | |
| #pragma warning(push)
 | |
| #if _MSC_VER > 1400
 | |
| #pragma warning(disable:6102 6103) // /analyze warnings
 | |
| #endif
 | |
| #include <strsafe.h>
 | |
| #pragma warning(pop)
 | |
| #include "detours.h"
 | |
| #include "tracebld.h"
 | |
| 
 | |
| #define PULONG_PTR          PVOID
 | |
| #define PLONG_PTR           PVOID
 | |
| #define ULONG_PTR           PVOID
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #pragma warning(disable:4127)   // Many of our asserts are constants.
 | |
| 
 | |
| #define DEBUG_BREAK() DebugBreak()
 | |
| 
 | |
| #define ASSERT_ALWAYS(x)   \
 | |
|     do {                                                        \
 | |
|         if (!(x)) {                                             \
 | |
|             AssertFailed(#x, __FILE__, __LINE__);               \
 | |
|             DebugBreak();                                       \
 | |
|         }                                                       \
 | |
|     } while (0)
 | |
| 
 | |
| #ifndef NDEBUG
 | |
| #define ASSERT(x)           ASSERT_ALWAYS(x)
 | |
| #else
 | |
| #define ASSERT(x)
 | |
| #endif
 | |
| 
 | |
| #define UNUSED(c)       (c) = (c)
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| static HMODULE s_hInst = NULL;
 | |
| static HMODULE s_hKernel32 = NULL;
 | |
| static CHAR s_szDllPath[MAX_PATH];
 | |
| static TBLOG_PAYLOAD s_Payload;
 | |
| static TBLOG_PAYLOAD s_ChildPayload;
 | |
| static CRITICAL_SECTION s_csChildPayload;
 | |
| static DWORD s_nTraceProcessId = 0;
 | |
| static LONG s_nChildCnt = 0;
 | |
| 
 | |
| static CRITICAL_SECTION s_csPipe;                       // Guards access to hPipe.
 | |
| static HANDLE           s_hPipe = INVALID_HANDLE_VALUE;
 | |
| static TBLOG_MESSAGE    s_rMessage;
 | |
| 
 | |
| // Logging Functions.
 | |
| //
 | |
| VOID Tblog(PCSTR pszMsgf, ...);
 | |
| VOID TblogV(PCSTR pszMsgf, va_list args);
 | |
| 
 | |
| VOID VSafePrintf(PCSTR pszMsg, va_list args, PCHAR pszBuffer, LONG cbBuffer);
 | |
| PCHAR SafePrintf(PCHAR pszBuffer, LONG cbBuffer, PCSTR pszMsg, ...);
 | |
| 
 | |
| LONG EnterFunc();
 | |
| VOID ExitFunc();
 | |
| VOID Print(PCSTR psz, ...);
 | |
| VOID NoteRead(PCSTR psz);
 | |
| VOID NoteRead(PCWSTR pwz);
 | |
| VOID NoteWrite(PCSTR psz);
 | |
| VOID NoteWrite(PCWSTR pwz);
 | |
| VOID NoteDelete(PCSTR psz);
 | |
| VOID NoteDelete(PCWSTR pwz);
 | |
| VOID NoteCleanup(PCSTR psz);
 | |
| VOID NoteCleanup(PCWSTR pwz);
 | |
| 
 | |
| PBYTE LoadFile(HANDLE hFile, DWORD cbFile);
 | |
| static PCHAR RemoveReturns(PCHAR pszBuffer);
 | |
| static PWCHAR RemoveReturns(PWCHAR pwzBuffer);
 | |
| 
 | |
| VOID AssertFailed(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine);
 | |
| 
 | |
| int WINAPI Mine_EntryPoint(VOID);
 | |
| VOID WINAPI Mine_ExitProcess(UINT a0);
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| int (WINAPI * Real_EntryPoint)(VOID)
 | |
|     = NULL;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreateDirectoryW)(LPCWSTR a0,
 | |
|                                       LPSECURITY_ATTRIBUTES a1)
 | |
|     = CreateDirectoryW;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreateDirectoryExW)(LPCWSTR a0,
 | |
|                                         LPCWSTR a1,
 | |
|                                         LPSECURITY_ATTRIBUTES a2)
 | |
|     = CreateDirectoryExW;
 | |
| 
 | |
| HANDLE (WINAPI * Real_CreateFileW)(LPCWSTR a0,
 | |
|                                    DWORD a1,
 | |
|                                    DWORD a2,
 | |
|                                    LPSECURITY_ATTRIBUTES a3,
 | |
|                                    DWORD a4,
 | |
|                                    DWORD a5,
 | |
|                                    HANDLE a6)
 | |
|     = CreateFileW;
 | |
| 
 | |
| HANDLE (WINAPI * Real_CreateFileMappingW)(HANDLE hFile,
 | |
|                                          LPSECURITY_ATTRIBUTES lpAttributes,
 | |
|                                          DWORD flProtect,
 | |
|                                          DWORD dwMaximumSizeHigh,
 | |
|                                          DWORD dwMaximumSizeLow,
 | |
|                                          LPCWSTR lpName
 | |
|                                         )
 | |
|     = CreateFileMappingW;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreatePipe)(PHANDLE hReadPipe,
 | |
|                                 PHANDLE hWritePipe,
 | |
|                                 LPSECURITY_ATTRIBUTES lpPipeAttributes,
 | |
|                                 DWORD nSize)
 | |
|     = CreatePipe;
 | |
| 
 | |
| BOOL (WINAPI * Real_CloseHandle)(HANDLE a0)
 | |
|     = CloseHandle;
 | |
| 
 | |
| BOOL (WINAPI * Real_DuplicateHandle)(HANDLE hSourceProcessHandle,
 | |
|                                      HANDLE hSourceHandle,
 | |
|                                      HANDLE hTargetProcessHandle,
 | |
|                                      LPHANDLE lpTargetHandle,
 | |
|                                      DWORD dwDesiredAccess,
 | |
|                                      BOOL bInheritHandle,
 | |
|                                      DWORD dwOptions)
 | |
|     = DuplicateHandle;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreateProcessW)(LPCWSTR lpApplicationName,
 | |
|                                     LPWSTR lpCommandLine,
 | |
|                                     LPSECURITY_ATTRIBUTES lpProcessAttributes,
 | |
|                                     LPSECURITY_ATTRIBUTES lpThreadAttributes,
 | |
|                                     BOOL bInheritHandles,
 | |
|                                     DWORD dwCreationFlags,
 | |
|                                     LPVOID lpEnvironment,
 | |
|                                     LPCWSTR lpCurrentDirectory,
 | |
|                                     LPSTARTUPINFOW lpStartupInfo,
 | |
|                                     LPPROCESS_INFORMATION lpProcessInformation)
 | |
|     = CreateProcessW;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreateProcessA)(LPCSTR lpApplicationName,
 | |
|                                     LPSTR lpCommandLine,
 | |
|                                     LPSECURITY_ATTRIBUTES lpProcessAttributes,
 | |
|                                     LPSECURITY_ATTRIBUTES lpThreadAttributes,
 | |
|                                     BOOL bInheritHandles,
 | |
|                                     DWORD dwCreationFlags,
 | |
|                                     LPVOID lpEnvironment,
 | |
|                                     LPCSTR lpCurrentDirectory,
 | |
|                                     LPSTARTUPINFOA lpStartupInfo,
 | |
|                                     LPPROCESS_INFORMATION lpProcessInformation)
 | |
|     = CreateProcessA;
 | |
| 
 | |
| BOOL (WINAPI * Real_DeleteFileW)(LPCWSTR a0)
 | |
|     = DeleteFileW;
 | |
| BOOL (WINAPI * Real_DeviceIoControl)(HANDLE a0,
 | |
|                                      DWORD dwIoControlCode,
 | |
|                                      LPVOID lpInBuffer,
 | |
|                                      DWORD nInBufferSize,
 | |
|                                      LPVOID lpOutBuffer,
 | |
|                                      DWORD nOutBufferSize,
 | |
|                                      LPDWORD lpBytesReturned,
 | |
|                                      LPOVERLAPPED lpOverlapped)
 | |
|     = DeviceIoControl;
 | |
| 
 | |
| DWORD (WINAPI * Real_GetFileAttributesW)(LPCWSTR a0)
 | |
|     = GetFileAttributesW;
 | |
| 
 | |
| BOOL (WINAPI * Real_MoveFileWithProgressW)(LPCWSTR lpExistingFileName,
 | |
|                                            LPCWSTR lpNewFileName,
 | |
|                                            LPPROGRESS_ROUTINE lpProgressRoutine,
 | |
|                                            LPVOID lpData,
 | |
|                                            DWORD dwFlags)
 | |
|     = MoveFileWithProgressW;
 | |
| 
 | |
| BOOL (WINAPI * Real_MoveFileA)(LPCSTR a0,
 | |
|                                LPCSTR a1)
 | |
|     = MoveFileA;
 | |
| 
 | |
| BOOL (WINAPI * Real_MoveFileW)(LPCWSTR a0,
 | |
|                                LPCWSTR a12)
 | |
|     = MoveFileW;
 | |
| 
 | |
| BOOL (WINAPI * Real_MoveFileExA)(LPCSTR a0,
 | |
|                                  LPCSTR a1,
 | |
|                                  DWORD a2)
 | |
|     = MoveFileExA;
 | |
| 
 | |
| BOOL (WINAPI * Real_MoveFileExW)(LPCWSTR a0,
 | |
|                                  LPCWSTR a1,
 | |
|                                  DWORD a2)
 | |
|     = MoveFileExW;
 | |
| 
 | |
| BOOL (WINAPI * Real_CopyFileExA)(LPCSTR a0,
 | |
|                                  LPCSTR a1,
 | |
|                                  LPPROGRESS_ROUTINE a2,
 | |
|                                  LPVOID a4,
 | |
|                                  LPBOOL a5,
 | |
|                                  DWORD a6)
 | |
|     = CopyFileExA;
 | |
| 
 | |
| BOOL (WINAPI * Real_CopyFileExW)(LPCWSTR a0,
 | |
|                                  LPCWSTR a1,
 | |
|                                  LPPROGRESS_ROUTINE a2,
 | |
|                                  LPVOID a4,
 | |
|                                  LPBOOL a5,
 | |
|                                  DWORD a6)
 | |
|     = CopyFileExW;
 | |
| 
 | |
| BOOL (WINAPI * Real_PrivCopyFileExW)(LPCWSTR  lpExistingFileName,
 | |
|                                      LPCWSTR  lpNewFileName,
 | |
|                                      LPPROGRESS_ROUTINE  lpProgressRoutine,
 | |
|                                      LPVOID  lpData,
 | |
|                                      LPBOOL  pbCancel,
 | |
|                                      DWORD  dwCopyFlags)
 | |
|     = NULL;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreateHardLinkA)(LPCSTR a0,
 | |
|                                      LPCSTR a1,
 | |
|                                      LPSECURITY_ATTRIBUTES a2)
 | |
|     = CreateHardLinkA;
 | |
| 
 | |
| BOOL (WINAPI * Real_CreateHardLinkW)(LPCWSTR a0,
 | |
|                                      LPCWSTR a1,
 | |
|                                      LPSECURITY_ATTRIBUTES a2)
 | |
|     = CreateHardLinkW;
 | |
| 
 | |
| BOOL (WINAPI * Real_SetStdHandle)(DWORD a0,
 | |
|                                   HANDLE a1)
 | |
|     = SetStdHandle;
 | |
| 
 | |
| HMODULE (WINAPI * Real_LoadLibraryA)(LPCSTR a0)
 | |
|     = LoadLibraryA;
 | |
| 
 | |
| HMODULE (WINAPI * Real_LoadLibraryW)(LPCWSTR a0)
 | |
|     = LoadLibraryW;
 | |
| 
 | |
| HMODULE (WINAPI * Real_LoadLibraryExA)(LPCSTR a0,
 | |
|                                        HANDLE a1,
 | |
|                                        DWORD a2)
 | |
|     = LoadLibraryExA;
 | |
| 
 | |
| HMODULE (WINAPI * Real_LoadLibraryExW)(LPCWSTR a0,
 | |
|                                        HANDLE a1,
 | |
|                                        DWORD a2)
 | |
|     = LoadLibraryExW;
 | |
| 
 | |
| DWORD (WINAPI * Real_SetFilePointer)(HANDLE hFile,
 | |
|                                      LONG lDistanceToMove,
 | |
|                                      PLONG lpDistanceToMoveHigh,
 | |
|                                      DWORD dwMoveMethod)
 | |
|     = SetFilePointer;
 | |
| 
 | |
| BOOL (WINAPI * Real_SetFilePointerEx)(HANDLE hFile,
 | |
|                                       LARGE_INTEGER liDistanceToMove,
 | |
|                                       PLARGE_INTEGER lpNewFilePointer,
 | |
|                                       DWORD dwMoveMethod)
 | |
|     = SetFilePointerEx;
 | |
| 
 | |
| BOOL (WINAPI * Real_ReadFile)(HANDLE a0,
 | |
|                                  LPVOID a1,
 | |
|                                  DWORD a2,
 | |
|                                  LPDWORD a3,
 | |
|                                  LPOVERLAPPED a4)
 | |
|     = ReadFile;
 | |
| 
 | |
| BOOL (WINAPI * Real_ReadFileEx)(HANDLE a0,
 | |
|                                    LPVOID a1,
 | |
|                                    DWORD a2,
 | |
|                                    LPOVERLAPPED a3,
 | |
|                                    LPOVERLAPPED_COMPLETION_ROUTINE a4)
 | |
|     = ReadFileEx;
 | |
| 
 | |
| BOOL (WINAPI * Real_WriteFile)(HANDLE a0,
 | |
|                                   LPCVOID a1,
 | |
|                                   DWORD a2,
 | |
|                                   LPDWORD a3,
 | |
|                                   LPOVERLAPPED a4)
 | |
|     = WriteFile;
 | |
| 
 | |
| BOOL (WINAPI * Real_WriteFileEx)(HANDLE a0,
 | |
|                                     LPCVOID a1,
 | |
|                                     DWORD a2,
 | |
|                                     LPOVERLAPPED a3,
 | |
|                                     LPOVERLAPPED_COMPLETION_ROUTINE a4)
 | |
|     = WriteFileEx;
 | |
| 
 | |
| BOOL (WINAPI * Real_WriteConsoleA)(HANDLE a0,
 | |
|                                       const VOID* a1,
 | |
|                                       DWORD a2,
 | |
|                                       LPDWORD a3,
 | |
|                                       LPVOID a4)
 | |
|     = WriteConsoleA;
 | |
| 
 | |
| BOOL (WINAPI * Real_WriteConsoleW)(HANDLE a0,
 | |
|                                       const VOID* a1,
 | |
|                                       DWORD a2,
 | |
|                                       LPDWORD a3,
 | |
|                                       LPVOID a4)
 | |
|     = WriteConsoleW;
 | |
| 
 | |
| VOID (WINAPI * Real_ExitProcess)(UINT a0)
 | |
|     = ExitProcess;
 | |
| 
 | |
| DWORD (WINAPI * Real_ExpandEnvironmentStringsA)(PCSTR lpSrc, PCHAR lpDst, DWORD nSize)
 | |
|     = ExpandEnvironmentStringsA;
 | |
| 
 | |
| DWORD (WINAPI * Real_ExpandEnvironmentStringsW)(PCWSTR lpSrc, PWCHAR lpDst, DWORD nSize)
 | |
|     = ExpandEnvironmentStringsW;
 | |
| 
 | |
| DWORD (WINAPI * Real_GetEnvironmentVariableA)(PCSTR lpName, PCHAR lpBuffer, DWORD nSize)
 | |
|     = GetEnvironmentVariableA;
 | |
| 
 | |
| DWORD (WINAPI * Real_GetEnvironmentVariableW)(PCWSTR lpName, PWCHAR lpBuffer, DWORD nSize)
 | |
|     = GetEnvironmentVariableW;
 | |
| 
 | |
| PCWSTR (CDECL * Real_wgetenv)(PCWSTR var) = NULL;
 | |
| PCSTR (CDECL * Real_getenv)(PCSTR var) = NULL;
 | |
| DWORD (CDECL * Real_getenv_s)(DWORD *pValue, PCHAR pBuffer, DWORD cBuffer, PCSTR varname) = NULL;
 | |
| DWORD (CDECL * Real_wgetenv_s)(DWORD *pValue, PWCHAR pBuffer, DWORD cBuffer, PCWSTR varname) = NULL;
 | |
| DWORD (CDECL * Real_dupenv_s)(PCHAR *ppBuffer, DWORD *pcBuffer, PCSTR varname) = NULL;
 | |
| DWORD (CDECL * Real_wdupenv_s)(PWCHAR *ppBuffer, DWORD *pcBuffer, PCWSTR varname) = NULL;
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| static VOID Copy(PWCHAR pwzDst, PCWSTR pwzSrc)
 | |
| {
 | |
|     while (*pwzSrc) {
 | |
|         *pwzDst++ = *pwzSrc++;
 | |
|     }
 | |
|     *pwzDst = '\0';
 | |
| }
 | |
| 
 | |
| static DWORD Size(PCWSTR pwzSrc)
 | |
| {
 | |
|     DWORD c = 0;
 | |
|     while (pwzSrc[c]) {
 | |
|         c++;
 | |
|     }
 | |
|     return c;
 | |
| }
 | |
| 
 | |
| static PCWSTR Save(PCWSTR pwzSrc)
 | |
| {
 | |
|     DWORD c = (Size(pwzSrc) + 1) * sizeof(WCHAR);
 | |
|     PWCHAR pwzDst = (PWCHAR)GlobalAlloc(GPTR, c);
 | |
|     CopyMemory(pwzDst, pwzSrc, c);
 | |
| 
 | |
|     return pwzDst;
 | |
| }
 | |
| 
 | |
| static BOOL HasSpace(PCWSTR pwz)
 | |
| {
 | |
|     for (; *pwz; pwz++) {
 | |
|         if (*pwz == ' ' || *pwz == '\t' || *pwz == '\r' || *pwz == '\n') {
 | |
|             return TRUE;
 | |
|         }
 | |
|     }
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static BOOL HasChar(PCWSTR pwz, WCHAR w)
 | |
| {
 | |
|     for (; *pwz; pwz++) {
 | |
|         if (*pwz == w) {
 | |
|             return TRUE;
 | |
|         }
 | |
|     }
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static DWORD Compare(PCWSTR pwzA, PCWSTR pwzB)
 | |
| {
 | |
|     for (;;) {
 | |
|         WCHAR cA = *pwzA++;
 | |
|         WCHAR cB = *pwzB++;
 | |
| 
 | |
|         if (cA >= 'A' && cA <= 'Z') {
 | |
|             cA += ('a' - 'A');
 | |
|         }
 | |
|         if (cB >= 'A' && cB <= 'Z') {
 | |
|             cB += ('a' - 'A');
 | |
|         }
 | |
| 
 | |
|         if (cA == 0 && cB == 0) {
 | |
|             return 0;
 | |
|         }
 | |
|         if (cA != cB) {
 | |
|             return cA - cB;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static DWORD Compare(PCWSTR pwzA, PCSTR pszB)
 | |
| {
 | |
|     for (;;) {
 | |
|         WCHAR cA = *pwzA++;
 | |
|         WCHAR cB = *pszB++;
 | |
| 
 | |
|         if (cA >= 'A' && cA <= 'Z') {
 | |
|             cA += ('a' - 'A');
 | |
|         }
 | |
|         if (cB >= 'A' && cB <= 'Z') {
 | |
|             cB += ('a' - 'A');
 | |
|         }
 | |
| 
 | |
|         if (cA == 0 && cB == 0) {
 | |
|             return 0;
 | |
|         }
 | |
|         if (cA != cB) {
 | |
|             return cA - cB;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static DWORD Compare(PCSTR pszA, PCSTR pszB)
 | |
| {
 | |
|     for (;;) {
 | |
|         CHAR cA = *pszA++;
 | |
|         CHAR cB = *pszB++;
 | |
| 
 | |
|         if (cA >= 'A' && cA <= 'Z') {
 | |
|             cA += ('a' - 'A');
 | |
|         }
 | |
|         if (cB >= 'A' && cB <= 'Z') {
 | |
|             cB += ('a' - 'A');
 | |
|         }
 | |
| 
 | |
|         if (cA == 0 && cB == 0) {
 | |
|             return 0;
 | |
|         }
 | |
|         if (cA != cB) {
 | |
|             return cA - cB;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| static PCSTR s_rpszMsvcrNames[] = {
 | |
|     "msvcr80.dll",
 | |
|     "msvcr80d.dll",
 | |
|     "msvcr71.dll",
 | |
|     "msvcr71d.dll",
 | |
|     "msvcr70.dll",
 | |
|     "msvcr70d.dll",
 | |
|     NULL
 | |
| };
 | |
| 
 | |
| HMODULE s_hMsvcr = NULL;
 | |
| PCSTR s_pszMsvcr = NULL;
 | |
| 
 | |
| static BOOL WINAPI ImportFileCallback(PVOID pContext, HMODULE hFile, PCSTR pszFile)
 | |
| {
 | |
|     UNUSED(pContext);
 | |
| 
 | |
|     if (pszFile != NULL) {
 | |
|         for (int i = 0; s_rpszMsvcrNames[i]; i++) {
 | |
|             if (Compare(pszFile, s_rpszMsvcrNames[i]) == 0) {
 | |
|                 s_hMsvcr = hFile;
 | |
|                 s_pszMsvcr = s_rpszMsvcrNames[i];
 | |
|                 return FALSE;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| BOOL FindMsvcr()
 | |
| {
 | |
|     DetourEnumerateImports(NULL, NULL, ImportFileCallback, NULL);
 | |
| 
 | |
|     if (s_hMsvcr != NULL) {
 | |
|         return TRUE;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| BOOL FindProc(PVOID * ppvCode, PCSTR pwzFunc)
 | |
| {
 | |
|     PVOID pv = GetProcAddress(s_hMsvcr, pwzFunc);
 | |
|     if (pv != NULL) {
 | |
|         *ppvCode = pv;
 | |
|         return TRUE;
 | |
|     }
 | |
|     else {
 | |
|         *ppvCode = NULL;
 | |
|         return FALSE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| struct EnvInfo
 | |
| {
 | |
|     DWORD   m_nHash;
 | |
|     DWORD   m_nIndex;
 | |
|     PCWSTR  m_pwzVar;
 | |
|     PCWSTR  m_pwzVal;
 | |
|     BOOL    m_fDefined;
 | |
|     BOOL    m_fUsed;
 | |
|     BOOL    m_fOriginal;
 | |
| };
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| class EnvVars
 | |
| {
 | |
|   private:
 | |
|     static CRITICAL_SECTION s_csLock;
 | |
|     static DWORD            s_nVars;
 | |
|     static DWORD            s_nCapacity;
 | |
|     static EnvInfo **       s_pVars;
 | |
| 
 | |
|   private:
 | |
|     static DWORD Hash(PCWSTR pwzVar)
 | |
|     {
 | |
|         DWORD hash = 5381;
 | |
|         while (*pwzVar != 0) {
 | |
|             WCHAR c = *pwzVar++;
 | |
|             if (c >= 'A' && c <= 'Z') {
 | |
|                 c += ('a' - 'A');
 | |
|             }
 | |
|             hash = ((hash << 5) + hash) + c;
 | |
|         }
 | |
|         return hash;
 | |
|     }
 | |
| 
 | |
|     static VOID LockAcquire()
 | |
|     {
 | |
|         EnterCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|     static VOID LockRelease()
 | |
|     {
 | |
|         LeaveCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|     static VOID Resize(DWORD nCapacity);
 | |
|     static VOID Set(EnvInfo *info);
 | |
|     static EnvInfo * Find(PCWSTR pwzVar);
 | |
| 
 | |
|   public:
 | |
|     static BOOL Equal(PCWSTR pwzA, PCWSTR pwzB)
 | |
|     {
 | |
|         return (Compare(pwzA, pwzB) == 0);
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     static VOID Initialize();
 | |
|     static VOID Dump();
 | |
| 
 | |
|     static VOID Add(PCWSTR pwzVar, PCWSTR pwzVal);
 | |
| 
 | |
|     static VOID Used(PCWSTR pwzVar);
 | |
|     static VOID Used(PCSTR pszVar);
 | |
| };
 | |
| 
 | |
| CRITICAL_SECTION    EnvVars::s_csLock;
 | |
| DWORD               EnvVars::s_nVars = 0;
 | |
| DWORD               EnvVars::s_nCapacity = 0;
 | |
| EnvInfo **          EnvVars::s_pVars = NULL;
 | |
| 
 | |
| VOID EnvVars::Initialize()
 | |
| {
 | |
|     InitializeCriticalSection(&s_csLock);
 | |
| 
 | |
|     Resize(919);
 | |
| }
 | |
| 
 | |
| VOID EnvVars::Resize(DWORD nCapacity)
 | |
| {
 | |
|     if (nCapacity > s_nCapacity) {
 | |
|         DWORD nOld = s_nCapacity;
 | |
|         EnvInfo ** pOld = s_pVars;
 | |
| 
 | |
|         // DEBUG_BREAK();
 | |
| 
 | |
|         s_pVars = (EnvInfo **)GlobalAlloc(GPTR, nCapacity * sizeof(EnvInfo *));
 | |
|         s_nCapacity = nCapacity;
 | |
| 
 | |
|         if (pOld != NULL) {
 | |
|             for (DWORD n = 0; n < nOld; n++) {
 | |
|                 if (pOld[n] != NULL) {
 | |
|                     Set(pOld[n]);
 | |
|                 }
 | |
|             }
 | |
|             GlobalFree((HGLOBAL)pOld);
 | |
|             pOld = NULL;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID EnvVars::Set(EnvInfo *info)
 | |
| {
 | |
|     DWORD hash = info->m_nHash;
 | |
|     DWORD slot = hash % s_nCapacity;
 | |
|     DWORD death = 0;
 | |
| 
 | |
|     // Find an empty slot.
 | |
|     for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
 | |
|         if (++death > s_nCapacity) {
 | |
|             // We should have dropped out at some point...
 | |
|             DEBUG_BREAK();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     s_pVars[slot] = info;
 | |
| }
 | |
| 
 | |
| EnvInfo * EnvVars::Find(PCWSTR pwzVar)
 | |
| {
 | |
|     DWORD hash = Hash(pwzVar);
 | |
|     DWORD slot = hash % s_nCapacity;
 | |
| 
 | |
|     LockAcquire();
 | |
| 
 | |
|     // Find the the matching slot, or an empty one.
 | |
|     for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
 | |
|         if (Equal(s_pVars[slot]->m_pwzVar, pwzVar)) {
 | |
|             LockRelease();
 | |
|             return s_pVars[slot];
 | |
|         }
 | |
|     }
 | |
|     LockRelease();
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| VOID EnvVars::Add(PCWSTR pwzVar, PCWSTR pwzVal)
 | |
| {
 | |
|     if (pwzVar == NULL) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     WCHAR wzVar[MAX_PATH];
 | |
|     PWCHAR pwzDst = wzVar;
 | |
|     while (*pwzVar) {
 | |
|         if (*pwzVar >= 'a' && *pwzVar <= 'z') {
 | |
|             *pwzDst++ = *pwzVar - ('a' - 'A');
 | |
|         }
 | |
|         else {
 | |
|             *pwzDst++ = *pwzVar;
 | |
|         }
 | |
|         pwzVar++;
 | |
|     }
 | |
|     *pwzDst = '\0';
 | |
|     pwzVar = wzVar;
 | |
| 
 | |
|     WCHAR wzVal[] = L"";
 | |
|     if (pwzVal != NULL) {
 | |
|         while (*pwzVal == ' ' || *pwzVal == '\t') {
 | |
|             *pwzVal++;
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         pwzVal = wzVal;
 | |
|     }
 | |
| 
 | |
|     // Tblog("<!-- ::Add var=[%le] val=[%le] -->\n", pwzVar, pwzVal);
 | |
|     LockAcquire();
 | |
| 
 | |
|     // DEBUG_BREAK();
 | |
| 
 | |
|     DWORD hash = Hash(pwzVar);
 | |
|     DWORD slot = hash % s_nCapacity;
 | |
|     EnvInfo *info = NULL;
 | |
|     DWORD death = 0;
 | |
| 
 | |
|     // Find the the matching slot, or an empty one.
 | |
|     for (; s_pVars[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
 | |
|         if (Equal(s_pVars[slot]->m_pwzVar, pwzVar)) {
 | |
|             LockRelease();
 | |
|             return;
 | |
|         }
 | |
|         if (++death > s_nCapacity) {
 | |
|             // We should have dropped out at some point...
 | |
|             DEBUG_BREAK();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Add the var to list of known vars.
 | |
|     info = (EnvInfo *)GlobalAlloc(GPTR, sizeof(EnvInfo));
 | |
|     info->m_nHash = hash;
 | |
|     info->m_nIndex = s_nVars++;
 | |
|     info->m_pwzVar = Save(pwzVar);
 | |
|     info->m_pwzVal = Save(pwzVal);
 | |
|     if (pwzVal[0] == '\0') {
 | |
|         info->m_fDefined = FALSE;
 | |
|         info->m_fUsed = TRUE;
 | |
|     }
 | |
|     else {
 | |
|         info->m_fDefined = TRUE;
 | |
|     }
 | |
|     s_pVars[slot] = info;
 | |
| 
 | |
|     // Check if we should grow the table.
 | |
|     if (s_nVars > (s_nCapacity / 2)) {
 | |
|         Resize(s_nCapacity * 2 - 1);
 | |
|     }
 | |
| 
 | |
|     LockRelease();
 | |
| }
 | |
| 
 | |
| VOID EnvVars::Used(PCWSTR pwzVar)
 | |
| {
 | |
|     if (pwzVar != NULL) {
 | |
|         // Tblog("<!-- Used [%le] -->\n", pwzVar);
 | |
|         EnvInfo *pInfo = Find(pwzVar);
 | |
|         if (pInfo) {
 | |
|             pInfo->m_fUsed = TRUE;
 | |
|         }
 | |
| #if 0
 | |
|         else {
 | |
|             Add(pwzVar, NULL);
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID EnvVars::Used(PCSTR pszVar)
 | |
| {
 | |
|     if (pszVar != NULL) {
 | |
|         WCHAR wzVar[MAX_PATH];
 | |
|         PWCHAR pwzVar = wzVar;
 | |
|         while (*pszVar) {
 | |
|             *pwzVar++ = *pszVar++;
 | |
|         }
 | |
|         *pwzVar = '\0';
 | |
| 
 | |
|         Used(wzVar);
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID EnvVars::Dump()
 | |
| {
 | |
|     if (s_nVars == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     LockAcquire();
 | |
| 
 | |
|     Tblog("<t:Vars>\n");
 | |
| 
 | |
|     // Remove any variables that match the original environment.
 | |
|     PCWSTR pwzz = s_Payload.wzzEnvironment;
 | |
|     while (*pwzz) {
 | |
|         WCHAR wzVar[MAX_PATH];
 | |
|         PWCHAR pwzVar = wzVar;
 | |
| 
 | |
|         while (*pwzz && *pwzz != '=') {
 | |
|             *pwzVar++ = *pwzz++;
 | |
|         }
 | |
|         *pwzVar = '\0';
 | |
|         if (*pwzz == '=') {
 | |
|             pwzz++;
 | |
|         }
 | |
| 
 | |
|         EnvInfo *pInfo = Find(wzVar);
 | |
|         if (pInfo) {
 | |
|             if (Compare(pwzz, pInfo->m_pwzVal) == 0) {
 | |
|                 pInfo->m_fUsed = FALSE;
 | |
|             }
 | |
|         }
 | |
|         pwzz += Size(pwzz) + 1;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     EnvInfo ** pSorted = (EnvInfo **)GlobalAlloc(GPTR, s_nVars * sizeof(EnvInfo *));
 | |
| 
 | |
|     for (DWORD n = 0; n < s_nCapacity; n++) {
 | |
|         if (s_pVars[n] != NULL) {
 | |
|             if (s_pVars[n]->m_nIndex > s_nVars) {
 | |
|                 DEBUG_BREAK();
 | |
|             }
 | |
|             pSorted[s_pVars[n]->m_nIndex] = s_pVars[n];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     for (DWORD n = 0; n < s_nVars; n++) {
 | |
|         EnvInfo *pInfo = pSorted[n];
 | |
| 
 | |
|         if (pInfo == NULL) {
 | |
|             Print("<!-- Warning: Missing %d of %d -->\n", n, s_nVars);
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         if (pInfo->m_fUsed && pInfo->m_pwzVal[0]) {
 | |
|             Print("<t:Var var=\"%le\">%le</t:Var>\n", pInfo->m_pwzVar, pInfo->m_pwzVal);
 | |
|         }
 | |
|     }
 | |
|     GlobalFree((HGLOBAL)pSorted);
 | |
| 
 | |
|     Tblog("</t:Vars>\n");
 | |
| 
 | |
|     LockRelease();
 | |
| }
 | |
| 
 | |
| void SaveEnvironment()
 | |
| {
 | |
|     LPWCH pwStrings = GetEnvironmentStringsW();
 | |
|     PCWSTR pwEnv = (PCWSTR)pwStrings;
 | |
| 
 | |
|     while (*pwEnv != '\0') {
 | |
|         WCHAR wzVar[MAX_PATH];
 | |
|         PWCHAR pwzDst = wzVar;
 | |
|         PCWSTR pwzVal = NULL;
 | |
| 
 | |
|         if (*pwEnv == '=') {
 | |
|             *pwzDst++ = *pwEnv++;
 | |
|         }
 | |
|         while (*pwEnv != '\0' && *pwEnv != '=') {
 | |
|             *pwzDst++ = *pwEnv++;
 | |
|         }
 | |
|         *pwzDst++ = '\0';
 | |
| 
 | |
|         if (*pwEnv == '=') {
 | |
|             pwEnv++;
 | |
|         }
 | |
| 
 | |
|         pwzVal = pwEnv;
 | |
|         while (*pwEnv != '\0') {
 | |
|             pwEnv++;
 | |
|         }
 | |
|         if (*pwEnv == '\0') {
 | |
|             pwEnv++;
 | |
|         }
 | |
|         if (wzVar[0] != '=') {
 | |
|             EnvVars::Add(wzVar, pwzVal);
 | |
|         }
 | |
|     }
 | |
|     FreeEnvironmentStringsW(pwStrings);
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| struct ProcInfo
 | |
| {
 | |
|     HANDLE  m_hProc;
 | |
|     DWORD   m_nProcId;
 | |
|     DWORD   m_nProc;
 | |
| };
 | |
| 
 | |
| class Procs
 | |
| {
 | |
|   private:
 | |
|     static CRITICAL_SECTION s_csLock;
 | |
|     static DWORD            s_nProcs;
 | |
|     static ProcInfo         s_rProcs[4049];
 | |
| 
 | |
|   private:
 | |
|     static ProcInfo& HashToSlot(HANDLE handle)
 | |
|     {
 | |
|         return s_rProcs[((DWORD_PTR)handle) % ARRAYSIZE(s_rProcs)];
 | |
|     }
 | |
| 
 | |
|     static VOID LockAcquire()
 | |
|     {
 | |
|         EnterCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|     static VOID LockRelease()
 | |
|     {
 | |
|         LeaveCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     static VOID Initialize();
 | |
|     static ProcInfo * Create(HANDLE hProc, DWORD nProcId);
 | |
|     static BOOL Close(HANDLE hProc);
 | |
| };
 | |
| 
 | |
| CRITICAL_SECTION    Procs::s_csLock;
 | |
| DWORD               Procs::s_nProcs = 0;
 | |
| ProcInfo            Procs::s_rProcs[4049];
 | |
| 
 | |
| VOID Procs::Initialize()
 | |
| {
 | |
|     InitializeCriticalSection(&s_csLock);
 | |
|     for (DWORD i = 0; i < ARRAYSIZE(s_rProcs); i++) {
 | |
|         s_rProcs[i].m_hProc = INVALID_HANDLE_VALUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| ProcInfo * Procs::Create(HANDLE hProc, DWORD nProcId)
 | |
| {
 | |
|     LockAcquire();
 | |
|     s_nProcs++;
 | |
|     ProcInfo& slot = HashToSlot(hProc);
 | |
|     slot.m_hProc = hProc;
 | |
|     slot.m_nProcId = nProcId;
 | |
|     slot.m_nProc = s_nProcs;
 | |
|     Print("<!-- CreateProcess (%d)-->\n", slot.m_nProc);
 | |
|     LockRelease();
 | |
| 
 | |
|     return &slot;
 | |
| }
 | |
| 
 | |
| BOOL Procs::Close(HANDLE hProc)
 | |
| {
 | |
|     BOOL first = false;
 | |
| 
 | |
|     LockAcquire();
 | |
|     ProcInfo& slot = HashToSlot(hProc);
 | |
|     if (slot.m_hProc == hProc) {
 | |
|         first = true;
 | |
|         Print("<!-- CloseProcess (%d)-->\n", slot.m_nProc);
 | |
|         slot.m_hProc = INVALID_HANDLE_VALUE;
 | |
|         slot.m_nProcId = 0;
 | |
|         slot.m_nProc = 0;
 | |
|         s_nProcs--;
 | |
|     }
 | |
|     LockRelease();
 | |
| 
 | |
|     return first;
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| struct FileInfo
 | |
| {
 | |
|     DWORD   m_nHash;
 | |
|     DWORD   m_nIndex;
 | |
| 
 | |
|     BOOL    m_fCantRead;        // Set for file that are opened Create
 | |
|     BOOL    m_fRead;
 | |
|     BOOL    m_fWrite;
 | |
| 
 | |
|     BOOL    m_fDelete;
 | |
|     BOOL    m_fCleanup;
 | |
|     BOOL    m_fSystemPath;
 | |
|     BOOL    m_fTemporaryPath;
 | |
|     BOOL    m_fTemporaryFile;
 | |
| 
 | |
|     DWORD   m_cbRead;
 | |
|     DWORD   m_cbWrite;
 | |
| 
 | |
|     BOOL    m_fAppend;
 | |
|     BOOL    m_fAbsorbed;        // Absorbed by TraceBld.
 | |
|     BOOL    m_fDirectory;
 | |
| 
 | |
|     PCWSTR  m_pwzPath;
 | |
|     PBYTE   m_pbContent;
 | |
|     DWORD   m_cbContent;
 | |
| 
 | |
| };
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| class FileNames
 | |
| {
 | |
|   private:
 | |
|     static CRITICAL_SECTION s_csLock;
 | |
|     static DWORD            s_nFiles;
 | |
|     static DWORD            s_nCapacity;
 | |
|     static FileInfo **      s_pFiles;
 | |
| 
 | |
|   public:
 | |
|     static WCHAR            s_wzSysPath[MAX_PATH];
 | |
|     static WCHAR            s_wzS64Path[MAX_PATH];
 | |
|     static WCHAR            s_wzTmpPath[MAX_PATH];
 | |
|     static WCHAR            s_wzExePath[MAX_PATH];
 | |
|     static DWORD            s_wcSysPath;
 | |
|     static DWORD            s_wcS64Path;
 | |
|     static DWORD            s_wcTmpPath;
 | |
|     static DWORD            s_wcExePath;
 | |
| 
 | |
|   private:
 | |
|     static DWORD Hash(PCWSTR pwzFile)
 | |
|     {
 | |
|         DWORD hash = 5381;
 | |
|         while (*pwzFile != 0) {
 | |
|             WCHAR c = *pwzFile++;
 | |
|             if (c >= 'A' && c <= 'Z') {
 | |
|                 c += ('a' - 'A');
 | |
|             }
 | |
|             hash = ((hash << 5) + hash) + c;
 | |
|         }
 | |
|         return hash;
 | |
|     }
 | |
| 
 | |
|     static VOID LockAcquire()
 | |
|     {
 | |
|         EnterCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|     static VOID LockRelease()
 | |
|     {
 | |
|         LeaveCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|     static VOID Resize(DWORD nCapacity);
 | |
|     static VOID Set(FileInfo *info);
 | |
|     static VOID Replace(PWCHAR pwzBuffer, PWCHAR pwzDstEnd, DWORD cwOld, PCWSTR pwzNew);
 | |
| 
 | |
|   public:
 | |
|     static BOOL Equal(PCWSTR pwzA, PCWSTR pwzB)
 | |
|     {
 | |
|         return (Compare(pwzA, pwzB) == 0);
 | |
|     }
 | |
| 
 | |
|     static BOOL PrefixMatch(PCWSTR pwzFile, PCWSTR pwzPrefix)
 | |
|     {
 | |
|         for (;;) {
 | |
|             WCHAR cFile = *pwzFile++;
 | |
|             WCHAR cPrefix = *pwzPrefix++;
 | |
| 
 | |
|             if (cFile >= 'A' && cFile <= 'Z') {
 | |
|                 cFile += ('a' - 'A');
 | |
|             }
 | |
|             if (cPrefix >= 'A' && cPrefix <= 'Z') {
 | |
|                 cPrefix += ('a' - 'A');
 | |
|             }
 | |
| 
 | |
|             if (cPrefix == 0) {
 | |
|                 return TRUE;
 | |
|             }
 | |
|             if (cFile != cPrefix) {
 | |
|                 return FALSE;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static BOOL SuffixMatch(PCWSTR pwzFile, PCWSTR pwzSuffix)
 | |
|     {
 | |
|         // Move both pointers to the end of the strings.
 | |
|         PCWSTR pwzFileBeg = pwzFile;
 | |
|         while (*pwzFile) {
 | |
|             pwzFile++;
 | |
|         }
 | |
| 
 | |
|         PCWSTR pwzSuffixBeg = pwzSuffix;
 | |
|         while (*pwzSuffix) {
 | |
|             pwzSuffix++;
 | |
|         }
 | |
| 
 | |
|         // Now walk backwards comparing strings.
 | |
|         for (;;) {
 | |
|             WCHAR cFile = (pwzFile > pwzFileBeg) ? *--pwzFile : 0;
 | |
|             WCHAR cSuffix = (pwzSuffix > pwzSuffixBeg) ? *--pwzSuffix : 0;
 | |
| 
 | |
|             if (cFile >= 'A' && cFile <= 'Z') {
 | |
|                 cFile += ('a' - 'A');
 | |
|             }
 | |
|             if (cSuffix >= 'A' && cSuffix <= 'Z') {
 | |
|                 cSuffix += ('a' - 'A');
 | |
|             }
 | |
| 
 | |
|             if (cSuffix == 0) {
 | |
|                 return TRUE;
 | |
|             }
 | |
|             if (cFile != cSuffix) {
 | |
|                 return FALSE;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static VOID EndInSlash(PWCHAR pwzPath)
 | |
|     {
 | |
|         if (*pwzPath) {
 | |
|             while (*pwzPath) {
 | |
|                 pwzPath++;
 | |
|             }
 | |
|             if (pwzPath[-1] != '\\') {
 | |
|                 *pwzPath++ = '\\';
 | |
|                 *pwzPath = '\0';
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     static VOID Initialize();
 | |
|     static VOID Dump();
 | |
|     static FileInfo * FindPartial(PCWSTR pwzPath);
 | |
|     static FileInfo * FindPartial(PCSTR pszPath);
 | |
|     static FileInfo * FindFull(PCWSTR pwzPath);
 | |
|     static PCWSTR ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, PCWSTR pwzPath);
 | |
|     static PCWSTR ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, FileInfo *pInfo);
 | |
|     static VOID ParameterizeLine(PWCHAR pwzDst, PWCHAR pwzDstEnd);
 | |
| };
 | |
| 
 | |
| CRITICAL_SECTION    FileNames::s_csLock;
 | |
| DWORD               FileNames::s_nFiles = 0;
 | |
| DWORD               FileNames::s_nCapacity = 0;
 | |
| FileInfo **         FileNames::s_pFiles;
 | |
| WCHAR               FileNames::s_wzSysPath[MAX_PATH];
 | |
| WCHAR               FileNames::s_wzS64Path[MAX_PATH];
 | |
| WCHAR               FileNames::s_wzTmpPath[MAX_PATH];
 | |
| WCHAR               FileNames::s_wzExePath[MAX_PATH];
 | |
| DWORD               FileNames::s_wcSysPath;
 | |
| DWORD               FileNames::s_wcS64Path;
 | |
| DWORD               FileNames::s_wcTmpPath;
 | |
| DWORD               FileNames::s_wcExePath;
 | |
| 
 | |
| VOID FileNames::Initialize()
 | |
| {
 | |
|     InitializeCriticalSection(&s_csLock);
 | |
| 
 | |
|     s_wzSysPath[0] = '\0';
 | |
|     GetSystemDirectoryW(s_wzSysPath, ARRAYSIZE(s_wzSysPath));
 | |
|     EndInSlash(s_wzSysPath);
 | |
| 
 | |
|     s_wzS64Path[0] = '\0';
 | |
|     GetWindowsDirectoryW(s_wzS64Path, ARRAYSIZE(s_wzS64Path));
 | |
|     EndInSlash(s_wzS64Path);
 | |
|     Copy(s_wzS64Path + Size(s_wzS64Path), L"SysWOW64\\");
 | |
| 
 | |
|     s_wzTmpPath[0] = '\0';
 | |
|     GetTempPathW(ARRAYSIZE(s_wzTmpPath), s_wzTmpPath);
 | |
|     EndInSlash(s_wzTmpPath);
 | |
| 
 | |
|     s_wzExePath[0] = '\0';
 | |
|     GetModuleFileNameW(NULL, s_wzExePath, ARRAYSIZE(s_wzExePath));
 | |
|     PWCHAR pwzLast = s_wzExePath;
 | |
|     for (PWCHAR pwz = s_wzExePath; *pwz; pwz++) {
 | |
|         if (*pwz == '\\') {
 | |
|             pwzLast = pwz;
 | |
|         }
 | |
|     }
 | |
|     if (*pwzLast == '\\') {
 | |
|         *++pwzLast = '\0';
 | |
|     }
 | |
| 
 | |
|     s_wcSysPath = Size(s_wzSysPath);
 | |
|     s_wcS64Path = Size(s_wzS64Path);
 | |
|     s_wcTmpPath = Size(s_wzTmpPath);
 | |
|     s_wcExePath = Size(s_wzExePath);
 | |
| 
 | |
|     Resize(4049);
 | |
| }
 | |
| 
 | |
| VOID FileNames::Resize(DWORD nCapacity)
 | |
| {
 | |
|     if (nCapacity > s_nCapacity) {
 | |
|         DWORD nOld = s_nCapacity;
 | |
|         FileInfo ** pOld = s_pFiles;
 | |
| 
 | |
|         s_pFiles = (FileInfo **)GlobalAlloc(GPTR, nCapacity * sizeof(FileInfo *));
 | |
|         s_nCapacity = nCapacity;
 | |
| 
 | |
|         if (pOld != NULL) {
 | |
|             for (DWORD n = 0; n < nOld; n++) {
 | |
|                 if (pOld[n] != NULL) {
 | |
|                     Set(pOld[n]);
 | |
|                 }
 | |
|             }
 | |
|             GlobalFree((HGLOBAL)pOld);
 | |
|             pOld = NULL;
 | |
|         }
 | |
|         s_nCapacity = nCapacity;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID FileNames::Set(FileInfo *info)
 | |
| {
 | |
|     DWORD hash = info->m_nHash;
 | |
|     DWORD slot = hash % s_nCapacity;
 | |
|     DWORD death = 0;
 | |
| 
 | |
|     // Find an empty slot.
 | |
|     for (; s_pFiles[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
 | |
|         if (++death > s_nCapacity) {
 | |
|             // We should have dropped out at some point...
 | |
|             DEBUG_BREAK();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     s_pFiles[slot] = info;
 | |
| }
 | |
| 
 | |
| FileInfo * FileNames::FindFull(PCWSTR pwzPath)
 | |
| {
 | |
|     if (pwzPath == NULL) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     LockAcquire();
 | |
| 
 | |
|     DWORD hash = Hash(pwzPath);
 | |
|     DWORD slot = hash % s_nCapacity;
 | |
|     FileInfo *info = NULL;
 | |
|     DWORD death = 0;
 | |
| 
 | |
|     // Find the the matching slot, or an empty one.
 | |
|     for (; s_pFiles[slot] != NULL; slot = (slot + 1) % s_nCapacity) {
 | |
|         if (Equal(s_pFiles[slot]->m_pwzPath, pwzPath)) {
 | |
|             info = s_pFiles[slot];
 | |
|             goto succeed;
 | |
|         }
 | |
|         if (++death > s_nCapacity) {
 | |
|             // We should have dropped out at some point...
 | |
|             DEBUG_BREAK();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Add the file to list of known files.
 | |
|     info = (FileInfo *)GlobalAlloc(GPTR, sizeof(FileInfo));
 | |
|     info->m_nHash = hash;
 | |
|     info->m_nIndex = s_nFiles++;
 | |
|     info->m_pwzPath = Save(pwzPath);
 | |
|     info->m_fSystemPath = (PrefixMatch(info->m_pwzPath, s_wzSysPath) ||
 | |
|                            PrefixMatch(info->m_pwzPath, s_wzS64Path));
 | |
|     info->m_fTemporaryPath = PrefixMatch(info->m_pwzPath, s_wzTmpPath);
 | |
|     info->m_fTemporaryFile = SuffixMatch(info->m_pwzPath, L".tmp");
 | |
| 
 | |
|     s_pFiles[slot] = info;
 | |
| 
 | |
|     // Check if we should grow the table.
 | |
|     if (s_nFiles > (s_nCapacity / 2)) {
 | |
|         Resize(s_nCapacity * 2 - 1);
 | |
|     }
 | |
| 
 | |
|   succeed:
 | |
|     LockRelease();
 | |
| 
 | |
|     return info;
 | |
| }
 | |
| 
 | |
| FileInfo * FileNames::FindPartial(PCWSTR pwzPath)
 | |
| {
 | |
|     WCHAR wzPath[MAX_PATH];
 | |
|     PWCHAR pwzFile = NULL;
 | |
| 
 | |
|     if (!GetFullPathNameW(pwzPath, ARRAYSIZE(wzPath), wzPath, &pwzFile)) {
 | |
|         return FindFull(pwzPath);
 | |
|     }
 | |
|     else {
 | |
|         return FindFull(wzPath);
 | |
|     }
 | |
| }
 | |
| 
 | |
| FileInfo * FileNames::FindPartial(PCSTR pwzPath)
 | |
| {
 | |
|     WCHAR wzPath[MAX_PATH];
 | |
|     PWCHAR pwzFile = wzPath;
 | |
| 
 | |
|     while (*pwzPath) {
 | |
|         *pwzFile++ = *pwzPath++;
 | |
|     }
 | |
|     *pwzFile = '\0';
 | |
| 
 | |
|     return FindPartial(wzPath);
 | |
| }
 | |
| 
 | |
| PCWSTR FileNames::ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, FileInfo *pInfo)
 | |
| {
 | |
|     return ParameterizeName(pwzDst, cMaxDst, pInfo->m_pwzPath);
 | |
| }
 | |
| 
 | |
| PCWSTR FileNames::ParameterizeName(PWCHAR pwzDst, DWORD cMaxDst, PCWSTR pwzPath)
 | |
| {
 | |
|     if (PrefixMatch(pwzPath, s_wzSysPath)) {
 | |
|         Copy(pwzDst, L"%SYSDIR%\\");
 | |
|         Copy(pwzDst + Size(pwzDst), pwzPath + s_wcSysPath);
 | |
|         goto finish;
 | |
|     }
 | |
|     else if (PrefixMatch(pwzPath, s_wzS64Path)) {
 | |
|         Copy(pwzDst, L"%SYSDIR%\\");
 | |
|         Copy(pwzDst + Size(pwzDst), pwzPath + s_wcS64Path);
 | |
|         goto finish;
 | |
|     }
 | |
|     else if (PrefixMatch(pwzPath, s_wzTmpPath)) {
 | |
|         Copy(pwzDst, L"%TMPDIR%\\");
 | |
|         Copy(pwzDst + Size(pwzDst), pwzPath + s_wcTmpPath);
 | |
|         goto finish;
 | |
|     }
 | |
|     else {
 | |
|         Copy(pwzDst, pwzPath);
 | |
| 
 | |
|       finish:
 | |
| #if 0 // to convert to all lower case.
 | |
|         for (PWCHAR pwz = pwzDst; *pwz && pwz < pwzDst + cMaxDst; pwz++) {
 | |
|             if (*pwz >= 'A' && *pwz <= 'Z') {
 | |
|                 *pwz = 'a' + (*pwz - 'A');
 | |
|             }
 | |
|         }
 | |
| #else
 | |
|         (void)cMaxDst;
 | |
| #endif
 | |
|         return pwzDst;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID FileNames::Replace(PWCHAR pwzDst, PWCHAR pwzDstEnd, DWORD cwOld, PCWSTR pwzNew)
 | |
| {
 | |
|     DWORD cwNew = Size(pwzNew);
 | |
|     DWORD cwDst = Size(pwzDst);
 | |
| 
 | |
|     if (cwOld < cwNew) {        // We have to insert.
 | |
|         if ((cwDst + cwNew - cwOld) >= (DWORD)(pwzDstEnd - pwzDst)) {
 | |
|             // Won't fit, so abort.
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         PWCHAR pwzTo = pwzDst + cwDst + (cwNew - cwOld);
 | |
|         PWCHAR pwzFm = pwzDst + cwDst;
 | |
| 
 | |
|         while (pwzTo >= pwzDst) {
 | |
|             *pwzTo-- = *pwzFm--;
 | |
|         }
 | |
|     }
 | |
|     else if (cwOld > cwNew) {  // We have to remove.
 | |
|         PWCHAR pwzTo = pwzDst + cwNew;
 | |
|         PWCHAR pwzFm = pwzDst + cwOld;
 | |
| 
 | |
|         while (*pwzFm) {
 | |
|             *pwzTo++ = *pwzFm++;
 | |
|         }
 | |
|         *pwzTo = '\0';
 | |
|     }
 | |
| 
 | |
|     // Now write the new string.
 | |
|     while (*pwzNew) {
 | |
|         *pwzDst++ = *pwzNew++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID FileNames::ParameterizeLine(PWCHAR pwzDst, PWCHAR pwzDstEnd)
 | |
| {
 | |
|     for (; *pwzDst != '\0'; pwzDst++) {
 | |
|         if (PrefixMatch(pwzDst, s_wzSysPath)) {
 | |
|             Replace(pwzDst, pwzDstEnd, s_wcSysPath, L"%SYSDIR%\\");
 | |
|         }
 | |
|         else if (PrefixMatch(pwzDst, s_wzS64Path)) {
 | |
|             Replace(pwzDst, pwzDstEnd, s_wcS64Path, L"%SYSDIR%\\");
 | |
|         }
 | |
|         else if (PrefixMatch(pwzDst, s_wzTmpPath)) {
 | |
|             Replace(pwzDst, pwzDstEnd, s_wcTmpPath, L"%TMPDIR%\\");
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID FileNames::Dump()
 | |
| {
 | |
|     WCHAR wzPath[MAX_PATH];
 | |
| 
 | |
|     if (s_nFiles == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     LockAcquire();
 | |
| 
 | |
|     Tblog("<t:Files>\n");
 | |
| 
 | |
|     FileInfo ** pSorted = (FileInfo **)GlobalAlloc(GPTR, s_nFiles * sizeof(FileInfo *));
 | |
| 
 | |
|     for (DWORD n = 0; n < s_nCapacity; n++) {
 | |
|         if (s_pFiles[n] != NULL) {
 | |
|             if (s_pFiles[n]->m_nIndex > s_nFiles) {
 | |
|                 DEBUG_BREAK();
 | |
|             }
 | |
|             pSorted[s_pFiles[n]->m_nIndex] = s_pFiles[n];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     for (DWORD n = 0; n < s_nFiles; n++) {
 | |
|         FileInfo *pInfo = pSorted[n];
 | |
| 
 | |
|         if (pInfo == NULL) {
 | |
|             Print("<!-- Warning: Missing %d of %d -->\n", n, s_nFiles);
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         BOOL fRead = pInfo->m_fRead;
 | |
|         BOOL fWrite = pInfo->m_fWrite;
 | |
|         BOOL fDelete = (pInfo->m_fDelete);
 | |
|         BOOL fCleanup = (pInfo->m_fCleanup);
 | |
|         BOOL fAppend = (pInfo->m_fAppend);
 | |
| 
 | |
| #if 0
 | |
|         if (fDelete && !fRead && !fWrite) {
 | |
|             Print("<!-- Discarding: %ls -->\n", pInfo->m_pwzPath);
 | |
|             // Discard pipe files only passed to children.
 | |
|             continue;
 | |
|         }
 | |
| #endif
 | |
|         if (pInfo->m_fAbsorbed) {
 | |
|             // Discard response fles
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         if (PrefixMatch(pInfo->m_pwzPath, s_wzExePath) ||
 | |
|             PrefixMatch(pInfo->m_pwzPath, s_wzSysPath) ||
 | |
|             PrefixMatch(pInfo->m_pwzPath, s_wzS64Path)) {
 | |
|             // Discard files from exec directory (because considered internal to code).
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
| #if 1 // Ignore PIPEs.
 | |
|         if (FileNames::PrefixMatch(pInfo->m_pwzPath, L"\\\\.\\PIPE\\")) {
 | |
|             continue;
 | |
|         }
 | |
| #endif
 | |
|         if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conout$")) {
 | |
|             continue;
 | |
|         }
 | |
|         if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conin$")) {
 | |
|             continue;
 | |
|         }
 | |
|         if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\nul")) {
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo);
 | |
| 
 | |
|         if (pInfo->m_fDirectory) {
 | |
|             Print("<t:File mkdir=\"true\">%ls</t:File>\n", wzPath);
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         if (!fRead && !fWrite && !fDelete && !fCleanup) {
 | |
|             // Discard do "none" files.
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         if (pInfo->m_pbContent == NULL ||
 | |
|             pInfo->m_fDelete ||
 | |
|             pInfo->m_fCleanup ||
 | |
|             pInfo->m_fWrite) {
 | |
| 
 | |
|             Print("<t:File%s%s%s%s%s>%ls</t:File>\n",
 | |
|                   fRead ? " read=\"true\"" : "",
 | |
|                   fWrite ? " write=\"true\"" : "",
 | |
|                   fDelete ? " delete=\"true\"" : "",
 | |
|                   fCleanup ? " cleanup=\"true\"" : "",
 | |
|                   fAppend ? " append=\"true\"" : "",
 | |
|                   // size=\"%d\" pInfo->m_cbContent,
 | |
|                   wzPath);
 | |
|         }
 | |
|         else if ((pInfo->m_pbContent)[0] == 0xff && (pInfo->m_pbContent)[1] == 0xfe) {
 | |
|             // Unicode
 | |
|             Print("<t:File%s%s%s%s%s>%ls<t:Data>%le</t:Data></t:File>\n",
 | |
|                   fRead ? " read=\"true\"" : "",
 | |
|                   fWrite ? " write=\"true\"" : "",
 | |
|                   fDelete ? " delete=\"true\"" : "",
 | |
|                   fCleanup ? " cleanup=\"true\"" : "",
 | |
|                   fAppend ? " append=\"true\"" : "",
 | |
|                   //  size=\"%d\" pInfo->m_cbContent,
 | |
|                   wzPath,
 | |
|                   RemoveReturns((PWCHAR)pInfo->m_pbContent));
 | |
|         }
 | |
|         else {
 | |
|             // Ascii
 | |
|             Print("<t:File%s%s%s%s%s>%ls<t:Data>%he</t:Data></t:File>\n",
 | |
|                   fRead ? " read=\"true\"" : "",
 | |
|                   fWrite ? " write=\"true\"" : "",
 | |
|                   fDelete ? " delete=\"true\"" : "",
 | |
|                   fCleanup ? " cleanup=\"true\"" : "",
 | |
|                   fAppend ? " append=\"true\"" : "",
 | |
|                   //  size=\"%d\" pInfo->m_cbContent,
 | |
|                   wzPath,
 | |
|                   RemoveReturns((PCHAR)pInfo->m_pbContent));
 | |
|         }
 | |
| 
 | |
|         if (pInfo->m_pbContent != NULL) {
 | |
|             GlobalFree((HGLOBAL)pInfo->m_pbContent);
 | |
|             pInfo->m_pbContent = NULL;
 | |
|         }
 | |
|     }
 | |
|     GlobalFree((HGLOBAL)pSorted);
 | |
| 
 | |
|     Tblog("</t:Files>\n");
 | |
| 
 | |
|     LockRelease();
 | |
| }
 | |
| 
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| class OpenFiles
 | |
| {
 | |
|   private:
 | |
|     struct SLOT
 | |
|     {
 | |
|         HANDLE      m_hHandle;
 | |
|         FileInfo *  m_pFile;
 | |
|         ProcInfo *  m_pProc;
 | |
|     };
 | |
| 
 | |
|   private:
 | |
|     static CRITICAL_SECTION s_csLock;
 | |
|     static DWORD            s_nHandles;
 | |
|     static SLOT             s_rHandles[4049];
 | |
| 
 | |
|   private:
 | |
|     static SLOT& HashToSlot(HANDLE handle)
 | |
|     {
 | |
|         return s_rHandles[((DWORD_PTR)handle) % ARRAYSIZE(s_rHandles)];
 | |
|     }
 | |
| 
 | |
|     static VOID LockAcquire()
 | |
|     {
 | |
|         EnterCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|     static VOID LockRelease()
 | |
|     {
 | |
|         LeaveCriticalSection(&s_csLock);
 | |
|     }
 | |
| 
 | |
|   public:
 | |
|     static VOID Initialize();
 | |
| 
 | |
|     static VOID SetWrite(HANDLE hFile, DWORD cbData)
 | |
|     {
 | |
|         SLOT& slot = HashToSlot(hFile);
 | |
|         if (slot.m_hHandle == hFile) {
 | |
|             slot.m_pFile->m_fWrite = TRUE;
 | |
|             slot.m_pFile->m_cbWrite += cbData;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static VOID SetRead(HANDLE hFile, DWORD cbData)
 | |
|     {
 | |
|         SLOT& slot = HashToSlot(hFile);
 | |
|         if (slot.m_hHandle == hFile) {
 | |
|             slot.m_pFile->m_fRead = TRUE;
 | |
|             slot.m_pFile->m_cbRead += cbData;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static BOOL Forget(HANDLE handle);
 | |
|     static BOOL Remember(HANDLE hFile, FileInfo *pInfo);
 | |
|     static BOOL Remember(HANDLE hProc, ProcInfo *pInfo);
 | |
|     static FileInfo * RecallFile(HANDLE hFile);
 | |
|     static ProcInfo * RecallProc(HANDLE hProc);
 | |
| };
 | |
| 
 | |
| CRITICAL_SECTION    OpenFiles::s_csLock;  // Guards access to OpenFile stuctures.
 | |
| DWORD               OpenFiles::s_nHandles = 0;
 | |
| OpenFiles::SLOT     OpenFiles::s_rHandles[4049];
 | |
| 
 | |
| VOID OpenFiles::Initialize()
 | |
| {
 | |
|     InitializeCriticalSection(&s_csLock);
 | |
|     for (DWORD n = 0; n < ARRAYSIZE(s_rHandles); n++) {
 | |
|         s_rHandles[n].m_hHandle = INVALID_HANDLE_VALUE;
 | |
|         s_rHandles[n].m_pFile = NULL;
 | |
|         s_rHandles[n].m_pProc = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| BOOL OpenFiles::Forget(HANDLE handle)
 | |
| {
 | |
|     LockAcquire();
 | |
|     OpenFiles::SLOT& slot = HashToSlot(handle);
 | |
| 
 | |
|     if (slot.m_hHandle == handle    ) {
 | |
|         slot.m_hHandle = INVALID_HANDLE_VALUE;
 | |
|         slot.m_pFile = NULL;
 | |
|         slot.m_pProc = NULL;
 | |
|         s_nHandles--;
 | |
|     }
 | |
|     LockRelease();
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| BOOL OpenFiles::Remember(HANDLE hFile, FileInfo *pFile)
 | |
| {
 | |
|     LockAcquire();
 | |
| 
 | |
|     OpenFiles::SLOT& slot = HashToSlot(hFile);
 | |
|     if (slot.m_hHandle != hFile && slot.m_hHandle != INVALID_HANDLE_VALUE) {
 | |
|         // hash collision
 | |
|         DEBUG_BREAK();
 | |
|     }
 | |
| 
 | |
|     slot.m_hHandle = hFile;
 | |
|     slot.m_pFile = pFile;
 | |
|     slot.m_pProc = NULL;
 | |
|     s_nHandles++;
 | |
| 
 | |
|     LockRelease();
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| BOOL OpenFiles::Remember(HANDLE hProc, ProcInfo *pProc)
 | |
| {
 | |
|     LockAcquire();
 | |
| 
 | |
|     OpenFiles::SLOT& slot = HashToSlot(hProc);
 | |
|     if (slot.m_hHandle != hProc && slot.m_hHandle != INVALID_HANDLE_VALUE) {
 | |
|         // hash collision
 | |
|         DEBUG_BREAK();
 | |
|     }
 | |
| 
 | |
|     slot.m_hHandle = hProc;
 | |
|     slot.m_pProc = pProc;
 | |
|     slot.m_pFile = NULL;
 | |
|     s_nHandles++;
 | |
| 
 | |
|     LockRelease();
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| FileInfo * OpenFiles::RecallFile(HANDLE hFile)
 | |
| {
 | |
|     LockAcquire();
 | |
| 
 | |
|     OpenFiles::SLOT& slot = HashToSlot(hFile);
 | |
| 
 | |
|     if (slot.m_hHandle == hFile) {
 | |
|         LockRelease();
 | |
|         return slot.m_pFile;
 | |
|     }
 | |
|     LockRelease();
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| ProcInfo * OpenFiles::RecallProc(HANDLE hProc)
 | |
| {
 | |
|     LockAcquire();
 | |
| 
 | |
|     OpenFiles::SLOT& slot = HashToSlot(hProc);
 | |
| 
 | |
|     if (slot.m_hHandle == hProc) {
 | |
|         LockRelease();
 | |
|         return slot.m_pProc;
 | |
|     }
 | |
|     LockRelease();
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////// VPrintf.
 | |
| //
 | |
| // Completely side-effect free printf replacement (but no FP numbers).
 | |
| //
 | |
| static PCHAR do_base(PCHAR pszOut, UINT64 nValue, UINT nBase, PCSTR pszDigits)
 | |
| {
 | |
|     CHAR szTmp[96];
 | |
|     int nDigit = sizeof(szTmp)-2;
 | |
|     for (; nDigit >= 0; nDigit--) {
 | |
|         szTmp[nDigit] = pszDigits[nValue % nBase];
 | |
|         nValue /= nBase;
 | |
|     }
 | |
|     for (nDigit = 0; nDigit < sizeof(szTmp) - 2 && szTmp[nDigit] == '0'; nDigit++) {
 | |
|         // skip leading zeros.
 | |
|     }
 | |
|     for (; nDigit < sizeof(szTmp) - 1; nDigit++) {
 | |
|         *pszOut++ = szTmp[nDigit];
 | |
|     }
 | |
|     *pszOut = '\0';
 | |
|     return pszOut;
 | |
| }
 | |
| 
 | |
| static PCHAR do_str(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn)
 | |
| {
 | |
|     while (*pszIn && pszOut < pszEnd) {
 | |
|         *pszOut++ = *pszIn++;
 | |
|     }
 | |
|     *pszOut = '\0';
 | |
|     return pszOut;
 | |
| }
 | |
| 
 | |
| static PCHAR do_wstr(PCHAR pszOut, PCHAR pszEnd, PCWSTR pszIn)
 | |
| {
 | |
|     while (*pszIn && pszOut < pszEnd) {
 | |
|         *pszOut++ = (CHAR)*pszIn++;
 | |
|     }
 | |
|     *pszOut = '\0';
 | |
|     return pszOut;
 | |
| }
 | |
| 
 | |
| static PCHAR do_estr(PCHAR pszOut, PCHAR pszEnd, PCSTR pszIn)
 | |
| {
 | |
|     while (*pszIn && pszOut < pszEnd) {
 | |
|         if (*pszIn == '<') {
 | |
|             if (pszOut + 4 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'l';
 | |
|             *pszOut++ = 't';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '>') {
 | |
|             if (pszOut + 4 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'g';
 | |
|             *pszOut++ = 't';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '&') {
 | |
|             if (pszOut + 5 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'a';
 | |
|             *pszOut++ = 'm';
 | |
|             *pszOut++ = 'p';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '\"') {
 | |
|             if (pszOut + 6 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'q';
 | |
|             *pszOut++ = 'u';
 | |
|             *pszOut++ = 'o';
 | |
|             *pszOut++ = 't';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '\'') {
 | |
|             if (pszOut + 6 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'a';
 | |
|             *pszOut++ = 'p';
 | |
|             *pszOut++ = 'o';
 | |
|             *pszOut++ = 's';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn  < ' ') {
 | |
|             BYTE c = (BYTE)(*pszIn++);
 | |
|             if (c < 10 && pszOut + 4 <= pszEnd) {
 | |
|                 *pszOut++ = '&';
 | |
|                 *pszOut++ = '#';
 | |
|                 *pszOut++ = '0' + (c % 10);
 | |
|                 *pszOut++ = ';';
 | |
|             }
 | |
|             else if (c < 100 && pszOut + 5 <= pszEnd) {
 | |
|                 *pszOut++ = '&';
 | |
|                 *pszOut++ = '#';
 | |
|                 *pszOut++ = '0' + ((c / 10) % 10);
 | |
|                 *pszOut++ = '0' + (c % 10);
 | |
|                 *pszOut++ = ';';
 | |
|             }
 | |
|             else if (c < 1000 && pszOut + 6 <= pszEnd) {
 | |
|                 *pszOut++ = '&';
 | |
|                 *pszOut++ = '#';
 | |
|                 *pszOut++ = '0' + ((c / 100) % 10);
 | |
|                 *pszOut++ = '0' + ((c / 10) % 10);
 | |
|                 *pszOut++ = '0' + (c % 10);
 | |
|                 *pszOut++ = ';';
 | |
|             }
 | |
|             else {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             *pszOut++ = *pszIn++;
 | |
|         }
 | |
|     }
 | |
|     *pszOut = '\0';
 | |
|     return pszOut;
 | |
| }
 | |
| 
 | |
| static PCHAR do_ewstr(PCHAR pszOut, PCHAR pszEnd, PCWSTR pszIn)
 | |
| {
 | |
|     while (*pszIn && pszOut < pszEnd) {
 | |
|         if (*pszIn == '<') {
 | |
|             if (pszOut + 4 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'l';
 | |
|             *pszOut++ = 't';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '>') {
 | |
|             if (pszOut + 4 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'g';
 | |
|             *pszOut++ = 't';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '&') {
 | |
|             if (pszOut + 5 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'a';
 | |
|             *pszOut++ = 'm';
 | |
|             *pszOut++ = 'p';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '\"') {
 | |
|             if (pszOut + 6 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'q';
 | |
|             *pszOut++ = 'u';
 | |
|             *pszOut++ = 'o';
 | |
|             *pszOut++ = 't';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn == '\'') {
 | |
|             if (pszOut + 6 > pszEnd) {
 | |
|                 break;
 | |
|             }
 | |
|             pszIn++;
 | |
|             *pszOut++ = '&';
 | |
|             *pszOut++ = 'a';
 | |
|             *pszOut++ = 'p';
 | |
|             *pszOut++ = 'o';
 | |
|             *pszOut++ = 's';
 | |
|             *pszOut++ = ';';
 | |
|         }
 | |
|         else if (*pszIn  < ' ' || *pszIn > 127) {
 | |
|             WCHAR c = *pszIn++;
 | |
|             if (c < 10 && pszOut + 4 <= pszEnd) {
 | |
|                 *pszOut++ = '&';
 | |
|                 *pszOut++ = '#';
 | |
|                 *pszOut++ = '0' + (CHAR)(c % 10);
 | |
|                 *pszOut++ = ';';
 | |
|             }
 | |
|             else if (c < 100 && pszOut + 5 <= pszEnd) {
 | |
|                 *pszOut++ = '&';
 | |
|                 *pszOut++ = '#';
 | |
|                 *pszOut++ = '0' + (CHAR)((c / 10) % 10);
 | |
|                 *pszOut++ = '0' + (CHAR)(c % 10);
 | |
|                 *pszOut++ = ';';
 | |
|             }
 | |
|             else if (c < 1000 && pszOut + 6 <= pszEnd) {
 | |
|                 *pszOut++ = '&';
 | |
|                 *pszOut++ = '#';
 | |
|                 *pszOut++ = '0' + (CHAR)((c / 100) % 10);
 | |
|                 *pszOut++ = '0' + (CHAR)((c / 10) % 10);
 | |
|                 *pszOut++ = '0' + (CHAR)(c % 10);
 | |
|                 *pszOut++ = ';';
 | |
|             }
 | |
|             else {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             *pszOut++ = (CHAR)*pszIn++;
 | |
|         }
 | |
|     }
 | |
|     *pszOut = '\0';
 | |
|     return pszOut;
 | |
| }
 | |
| 
 | |
| #if _MSC_VER >= 1900
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable:4456) // declaration hides previous local declaration
 | |
| #endif
 | |
| 
 | |
| VOID VSafePrintf(PCSTR pszMsg, va_list args, PCHAR pszBuffer, LONG cbBuffer)
 | |
| {
 | |
|     PCHAR pszOut = pszBuffer;
 | |
|     PCHAR pszEnd = pszBuffer + cbBuffer - 1;
 | |
|     pszBuffer[0] = '\0';
 | |
| 
 | |
|     __try {
 | |
|         while (*pszMsg && pszOut < pszEnd) {
 | |
|             if (*pszMsg == '%') {
 | |
|                 CHAR szHead[4] = "";
 | |
|                 INT nLen;
 | |
|                 INT nWidth = 0;
 | |
|                 INT nPrecision = 0;
 | |
|                 BOOL fLeft = FALSE;
 | |
|                 BOOL fPositive = FALSE;
 | |
|                 BOOL fPound = FALSE;
 | |
|                 BOOL fBlank = FALSE;
 | |
|                 BOOL fZero = FALSE;
 | |
|                 BOOL fDigit = FALSE;
 | |
|                 BOOL fSmall = FALSE;
 | |
|                 BOOL fLarge = FALSE;
 | |
|                 BOOL f64Bit = FALSE;
 | |
|                 PCSTR pszArg = pszMsg;
 | |
| 
 | |
|                 pszMsg++;
 | |
| 
 | |
|                 for (; (*pszMsg == '-' ||
 | |
|                         *pszMsg == '+' ||
 | |
|                         *pszMsg == '#' ||
 | |
|                         *pszMsg == ' ' ||
 | |
|                         *pszMsg == '0'); pszMsg++) {
 | |
|                     switch (*pszMsg) {
 | |
|                       case '-': fLeft = TRUE; break;
 | |
|                       case '+': fPositive = TRUE; break;
 | |
|                       case '#': fPound = TRUE; break;
 | |
|                       case ' ': fBlank = TRUE; break;
 | |
|                       case '0': fZero = TRUE; break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (*pszMsg == '*') {
 | |
|                     nWidth = va_arg(args, INT);
 | |
|                     pszMsg++;
 | |
|                 }
 | |
|                 else {
 | |
|                     while (*pszMsg >= '0' && *pszMsg <= '9') {
 | |
|                         nWidth = nWidth * 10 + (*pszMsg++ - '0');
 | |
|                     }
 | |
|                 }
 | |
|                 if (*pszMsg == '.') {
 | |
|                     pszMsg++;
 | |
|                     fDigit = TRUE;
 | |
|                     if (*pszMsg == '*') {
 | |
|                         nPrecision = va_arg(args, INT);
 | |
|                         pszMsg++;
 | |
|                     }
 | |
|                     else {
 | |
|                         while (*pszMsg >= '0' && *pszMsg <= '9') {
 | |
|                             nPrecision = nPrecision * 10 + (*pszMsg++ - '0');
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (*pszMsg == 'h') {
 | |
|                     fSmall = TRUE;
 | |
|                     pszMsg++;
 | |
|                 }
 | |
|                 else if (*pszMsg == 'l') {
 | |
|                     fLarge = TRUE;
 | |
|                     pszMsg++;
 | |
|                 }
 | |
|                 else if (*pszMsg == 'I' && pszMsg[1] == '6' && pszMsg[2] == '4') {
 | |
|                     f64Bit = TRUE;
 | |
|                     pszMsg += 3;
 | |
|                 }
 | |
| 
 | |
|                 if (*pszMsg == 's' || *pszMsg == 'e' || *pszMsg == 'c') {
 | |
|                     // We ignore the length, precision, and alignment
 | |
|                     // to avoid using a temporary buffer.
 | |
| 
 | |
|                     if (*pszMsg == 's') { // [GalenH] need to not use temp.
 | |
|                         PVOID pvData = va_arg(args, PVOID);
 | |
| 
 | |
|                         pszMsg++;
 | |
| 
 | |
|                         if (fSmall) {
 | |
|                             fLarge = FALSE;
 | |
|                         }
 | |
| 
 | |
|                         __try {
 | |
|                             if (pvData == NULL) {
 | |
|                                 pszOut = do_str(pszOut, pszEnd, "-NULL-");
 | |
|                             }
 | |
|                             else if (fLarge) {
 | |
|                                 pszOut = do_wstr(pszOut, pszEnd, (PWCHAR)pvData);
 | |
|                             }
 | |
|                             else {
 | |
|                                 pszOut = do_str(pszOut, pszEnd, (PCHAR)pvData);
 | |
|                             }
 | |
|                         } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
|                             pszOut = do_str(pszOut, pszEnd, "-");
 | |
|                             pszOut = do_base(pszOut, (UINT64)pvData, 16,
 | |
|                                              "0123456789ABCDEF");
 | |
|                             pszOut = do_str(pszOut, pszEnd, "-");
 | |
|                         }
 | |
|                     }
 | |
|                     else if (*pszMsg == 'e')    {   // Escape the string.
 | |
|                         PVOID pvData = va_arg(args, PVOID);
 | |
| 
 | |
|                         pszMsg++;
 | |
| 
 | |
|                         if (fSmall) {
 | |
|                             fLarge = FALSE;
 | |
|                         }
 | |
| 
 | |
|                         __try {
 | |
|                             if (pvData == NULL) {
 | |
|                                 pszOut = do_str(pszOut, pszEnd, "-NULL-");
 | |
|                             }
 | |
|                             else if (fLarge) {
 | |
|                                 pszOut = do_ewstr(pszOut, pszEnd, (PWCHAR)pvData);
 | |
|                             }
 | |
|                             else {
 | |
|                                 pszOut = do_estr(pszOut, pszEnd, (PCHAR)pvData);
 | |
|                             }
 | |
|                         } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
|                             pszOut = do_str(pszOut, pszEnd, "-");
 | |
|                             pszOut = do_base(pszOut, (UINT64)pvData, 16,
 | |
|                                              "0123456789ABCDEF");
 | |
|                             pszOut = do_str(pszOut, pszEnd, "-");
 | |
|                         }
 | |
|                     }
 | |
|                     else {
 | |
|                         CHAR szTemp[2];
 | |
|                         pszMsg++;
 | |
| 
 | |
|                         szTemp[0] = (CHAR)va_arg(args, INT);
 | |
|                         szTemp[1] = '\0';
 | |
|                         pszOut = do_str(pszOut, pszEnd, szTemp);
 | |
|                     }
 | |
|                 }
 | |
|                 else if (*pszMsg == 'd' || *pszMsg == 'i' || *pszMsg == 'o' ||
 | |
|                          *pszMsg == 'x' || *pszMsg == 'X' || *pszMsg == 'b' ||
 | |
|                          *pszMsg == 'u') {
 | |
|                     CHAR szTemp[128];
 | |
|                     UINT64 value;
 | |
|                     if (f64Bit) {
 | |
|                         value = va_arg(args, UINT64);
 | |
|                     }
 | |
|                     else {
 | |
|                         value = va_arg(args, UINT);
 | |
|                     }
 | |
| 
 | |
|                     if (*pszMsg == 'x') {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, value, 16, "0123456789abcdef") - szTemp);
 | |
|                         if (fPound && value) {
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "0x");
 | |
|                         }
 | |
|                     }
 | |
|                     else if (*pszMsg == 'X') {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, value, 16, "0123456789ABCDEF") - szTemp);
 | |
|                         if (fPound && value) {
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "0X");
 | |
|                         }
 | |
|                     }
 | |
|                     else if (*pszMsg == 'd') {
 | |
|                         pszMsg++;
 | |
|                         if ((INT64)value < 0) {
 | |
|                             value = -(INT64)value;
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "-");
 | |
|                         }
 | |
|                         else if (fPositive) {
 | |
|                             if (value > 0) {
 | |
|                                 do_str(szHead, szHead + sizeof(szHead) - 1, "+");
 | |
|                             }
 | |
|                         }
 | |
|                         else if (fBlank) {
 | |
|                             if (value > 0) {
 | |
|                                 do_str(szHead, szHead + sizeof(szHead) - 1, " ");
 | |
|                             }
 | |
|                         }
 | |
|                         nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp);
 | |
|                         nPrecision = 0;
 | |
|                     }
 | |
|                     else if (*pszMsg == 'u') {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp);
 | |
|                         nPrecision = 0;
 | |
|                     }
 | |
|                     else if (*pszMsg == 'o') {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, value, 8, "01234567") - szTemp);
 | |
|                         nPrecision = 0;
 | |
| 
 | |
|                         if (fPound && value) {
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "0");
 | |
|                         }
 | |
|                     }
 | |
|                     else if (*pszMsg == 'b') {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, value, 2, "01") - szTemp);
 | |
|                         nPrecision = 0;
 | |
| 
 | |
|                         if (fPound && value) {
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "0b");
 | |
|                         }
 | |
|                     }
 | |
|                     else {
 | |
|                         pszMsg++;
 | |
|                         if ((INT64)value < 0) {
 | |
|                             value = -(INT64)value;
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "-");
 | |
|                         }
 | |
|                         else if (fPositive) {
 | |
|                             if (value > 0) {
 | |
|                                 do_str(szHead, szHead + sizeof(szHead) - 1, "+");
 | |
|                             }
 | |
|                         }
 | |
|                         else if (fBlank) {
 | |
|                             if (value > 0) {
 | |
|                                 do_str(szHead, szHead + sizeof(szHead) - 1, " ");
 | |
|                             }
 | |
|                         }
 | |
|                         nLen = (int)(do_base(szTemp, value, 10, "0123456789") - szTemp);
 | |
|                         nPrecision = 0;
 | |
|                     }
 | |
| 
 | |
|                     INT nHead = 0;
 | |
|                     for (; szHead[nHead]; nHead++) {
 | |
|                         // Count characters in head string.
 | |
|                     }
 | |
| 
 | |
|                     if (fLeft) {
 | |
|                         if (nHead) {
 | |
|                             pszOut = do_str(pszOut, pszEnd, szHead);
 | |
|                             nLen += nHead;
 | |
|                         }
 | |
|                         pszOut = do_str(pszOut, pszEnd, szTemp);
 | |
|                         for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
 | |
|                             *pszOut++ = ' ';
 | |
|                         }
 | |
|                     }
 | |
|                     else if (fZero) {
 | |
|                         if (nHead) {
 | |
|                             pszOut = do_str(pszOut, pszEnd, szHead);
 | |
|                             nLen += nHead;
 | |
|                         }
 | |
|                         for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
 | |
|                             *pszOut++ = '0';
 | |
|                         }
 | |
|                         pszOut = do_str(pszOut, pszEnd, szTemp);
 | |
|                     }
 | |
|                     else {
 | |
|                         if (nHead) {
 | |
|                             nLen += nHead;
 | |
|                         }
 | |
|                         for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
 | |
|                             *pszOut++ = ' ';
 | |
|                         }
 | |
|                         if (nHead) {
 | |
|                             pszOut = do_str(pszOut, pszEnd, szHead);
 | |
|                         }
 | |
|                         pszOut = do_str(pszOut, pszEnd, szTemp);
 | |
|                     }
 | |
|                 }
 | |
|                 else if (*pszMsg == 'p') {
 | |
|                     CHAR szTemp[64];
 | |
|                     ULONG_PTR value;
 | |
|                     value = va_arg(args, ULONG_PTR);
 | |
| 
 | |
|                     if (*pszMsg == 'p') {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, (UINT64)value, 16, "0123456789abcdef") - szTemp);
 | |
|                         if (fPound && value) {
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "0x");
 | |
|                         }
 | |
|                     }
 | |
|                     else {
 | |
|                         pszMsg++;
 | |
|                         nLen = (int)(do_base(szTemp, (UINT64)value, 16, "0123456789ABCDEF") - szTemp);
 | |
|                         if (fPound && value) {
 | |
|                             do_str(szHead, szHead + sizeof(szHead) - 1, "0x");
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     INT nHead = 0;
 | |
|                     for (; szHead[nHead]; nHead++) {
 | |
|                         // Count characters in head string.
 | |
|                     }
 | |
| 
 | |
|                     if (nHead) {
 | |
|                         pszOut = do_str(pszOut, pszEnd, szHead);
 | |
|                         nLen += nHead;
 | |
|                     }
 | |
|                     for (; nLen < nWidth && pszOut < pszEnd; nLen++) {
 | |
|                         *pszOut++ = '0';
 | |
|                     }
 | |
|                     pszOut = do_str(pszOut, pszEnd, szTemp);
 | |
|                 }
 | |
|                 else {
 | |
|                     pszMsg++;
 | |
|                     while (pszArg < pszMsg && pszOut < pszEnd) {
 | |
|                         *pszOut++ = *pszArg++;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 if (pszOut < pszEnd) {
 | |
|                     *pszOut++ = *pszMsg++;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         *pszOut = '\0';
 | |
|         pszBuffer[cbBuffer - 1] = '\0';
 | |
|     } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
|         PCHAR pszOut = pszBuffer;
 | |
|         *pszOut = '\0';
 | |
|         pszOut = do_str(pszOut, pszEnd, "-exception:");
 | |
|         pszOut = do_base(pszOut, (UINT64)GetExceptionCode(), 10, "0123456789");
 | |
|         pszOut = do_str(pszOut, pszEnd, "-");
 | |
|     }
 | |
| }
 | |
| 
 | |
| #if _MSC_VER >= 1900
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| PCHAR SafePrintf(PCHAR pszBuffer, LONG cbBuffer, PCSTR pszMsg, ...)
 | |
| {
 | |
|     va_list args;
 | |
|     va_start(args, pszMsg);
 | |
|     VSafePrintf(pszMsg, args, pszBuffer, cbBuffer);
 | |
|     va_end(args);
 | |
| 
 | |
|     while (*pszBuffer) {
 | |
|         pszBuffer++;
 | |
|     }
 | |
|     return pszBuffer;
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| BOOL TblogOpen()
 | |
| {
 | |
|     EnterCriticalSection(&s_csPipe);
 | |
| 
 | |
|     WCHAR wzPipe[256];
 | |
|     StringCchPrintfW(wzPipe, ARRAYSIZE(wzPipe), L"%ls.%d", TBLOG_PIPE_NAMEW, s_nTraceProcessId);
 | |
| 
 | |
|     for (int retries = 0; retries < 10; retries++) {
 | |
|         WaitNamedPipeW(wzPipe, 10000); // Wait up to 10 seconds for a pipe to appear.
 | |
| 
 | |
|         s_hPipe = Real_CreateFileW(wzPipe, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
 | |
|         if (s_hPipe != INVALID_HANDLE_VALUE) {
 | |
|             DWORD dwMode = PIPE_READMODE_MESSAGE;
 | |
|             if (SetNamedPipeHandleState(s_hPipe, &dwMode, NULL, NULL)) {
 | |
|                 LeaveCriticalSection(&s_csPipe);
 | |
|                 return TRUE;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     LeaveCriticalSection(&s_csPipe);
 | |
| 
 | |
|     // Couldn't open pipe.
 | |
|     DEBUG_BREAK();
 | |
|     Real_ExitProcess(9990);
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| VOID TblogV(PCSTR pszMsgf, va_list args)
 | |
| {
 | |
|     if (s_hPipe == INVALID_HANDLE_VALUE) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     EnterCriticalSection(&s_csPipe);
 | |
| 
 | |
|     DWORD cbWritten = 0;
 | |
| 
 | |
|     PCHAR pszBuf = s_rMessage.szMessage;
 | |
|     VSafePrintf(pszMsgf, args,
 | |
|                 pszBuf, (int)(s_rMessage.szMessage + sizeof(s_rMessage.szMessage) - pszBuf));
 | |
| 
 | |
|     PCHAR pszEnd = s_rMessage.szMessage;
 | |
|     for (; *pszEnd; pszEnd++) {
 | |
|         // no internal contents.
 | |
|     }
 | |
|     s_rMessage.nBytes = (DWORD)(pszEnd - ((PCSTR)&s_rMessage));
 | |
| 
 | |
|     // If the write fails, then we abort
 | |
|     if (s_hPipe != INVALID_HANDLE_VALUE) {
 | |
|         if (!Real_WriteFile(s_hPipe, &s_rMessage, s_rMessage.nBytes, &cbWritten, NULL)) {
 | |
|             Real_ExitProcess(9991);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     LeaveCriticalSection(&s_csPipe);
 | |
| }
 | |
| 
 | |
| VOID Tblog(PCSTR pszMsgf, ...)
 | |
| {
 | |
|     if (s_hPipe == INVALID_HANDLE_VALUE) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     va_list args;
 | |
|     va_start(args, pszMsgf);
 | |
|     TblogV(pszMsgf, args);
 | |
|     va_end(args);
 | |
| }
 | |
| 
 | |
| VOID TblogClose()
 | |
| {
 | |
|     EnterCriticalSection(&s_csPipe);
 | |
| 
 | |
|     if (s_hPipe != INVALID_HANDLE_VALUE) {
 | |
|         DWORD cbWritten = 0;
 | |
| 
 | |
|         s_rMessage.nBytes = 0;
 | |
| 
 | |
|         Real_WriteFile(s_hPipe, &s_rMessage, 4, &cbWritten, NULL);
 | |
|         FlushFileBuffers(s_hPipe);
 | |
|         Real_CloseHandle(s_hPipe);
 | |
|         s_hPipe = INVALID_HANDLE_VALUE;
 | |
|     }
 | |
| 
 | |
|     LeaveCriticalSection(&s_csPipe);
 | |
| }
 | |
| 
 | |
| /////////////////////////////////////////////////////////////
 | |
| // Detours
 | |
| //
 | |
| static BOOL IsInherited(HANDLE hHandle)
 | |
| {
 | |
|     DWORD dwFlags;
 | |
| 
 | |
|     if (GetHandleInformation(hHandle, &dwFlags)) {
 | |
|         return (dwFlags & HANDLE_FLAG_INHERIT) ? TRUE : FALSE;
 | |
|     }
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static void SaveStdHandleName(HANDLE hFile, PWCHAR pwzBuffer, BOOL *fAppend)
 | |
| {
 | |
|     pwzBuffer[0] = '\0';
 | |
| 
 | |
|     if ((hFile != INVALID_HANDLE_VALUE) && IsInherited(hFile)) {
 | |
|         FileInfo * pInfo = OpenFiles::RecallFile(hFile);
 | |
|         if (pInfo) {
 | |
|             Copy(pwzBuffer, pInfo->m_pwzPath);
 | |
|             if (pInfo->m_fAppend && fAppend != NULL) {
 | |
|                 *fAppend = TRUE;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void LoadStdHandleName(DWORD id, PCWSTR pwzBuffer, BOOL fAppend)
 | |
| {
 | |
|     HANDLE hFile = GetStdHandle(id);
 | |
| 
 | |
|     if ((hFile != INVALID_HANDLE_VALUE) && pwzBuffer[0] != '\0') {
 | |
|         FileInfo *pInfo = FileNames::FindPartial(pwzBuffer);
 | |
|         if (fAppend) {
 | |
|             pInfo->m_fAppend = TRUE;
 | |
|         }
 | |
|         OpenFiles::Remember(hFile, pInfo);
 | |
|     }
 | |
| }
 | |
| 
 | |
| BOOL CreateProcessInternals(HANDLE hProcess, DWORD nProcessId, PCHAR pszId,
 | |
|                             HANDLE hStdin, HANDLE hStdout, HANDLE hStderr)
 | |
| {
 | |
|     EnterCriticalSection(&s_csChildPayload);
 | |
| 
 | |
|     ProcInfo *proc = Procs::Create(hProcess, nProcessId);
 | |
|     OpenFiles::Remember(hProcess, proc);
 | |
| 
 | |
|     ZeroMemory(&s_ChildPayload, sizeof(s_ChildPayload));
 | |
|     CopyMemory(&s_ChildPayload, &s_Payload, sizeof(s_ChildPayload));
 | |
| 
 | |
|     s_ChildPayload.nParentProcessId = GetCurrentProcessId();
 | |
|     s_ChildPayload.rGeneology[s_ChildPayload.nGeneology]
 | |
|         = (DWORD)InterlockedIncrement(&s_nChildCnt);
 | |
|     s_ChildPayload.nGeneology++;
 | |
| 
 | |
|     SaveStdHandleName(hStdin, s_ChildPayload.wzStdin, NULL);
 | |
|     SaveStdHandleName(hStdout, s_ChildPayload.wzStdout, &s_ChildPayload.fStdoutAppend);
 | |
|     SaveStdHandleName(hStderr, s_ChildPayload.wzStderr, &s_ChildPayload.fStderrAppend);
 | |
| 
 | |
|     DetourCopyPayloadToProcess(hProcess, s_guidTrace, &s_ChildPayload, sizeof(s_ChildPayload));
 | |
| 
 | |
|     for (DWORD i = 0; i < s_ChildPayload.nGeneology; i++) {
 | |
|         pszId = SafePrintf(pszId, 16, "%d.", s_ChildPayload.rGeneology[i]);
 | |
|     }
 | |
|     *pszId = '\0';
 | |
| 
 | |
|     LeaveCriticalSection(&s_csChildPayload);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CreateProcessW(LPCWSTR lpApplicationName,
 | |
|                                 LPWSTR lpCommandLine,
 | |
|                                 LPSECURITY_ATTRIBUTES lpProcessAttributes,
 | |
|                                 LPSECURITY_ATTRIBUTES lpThreadAttributes,
 | |
|                                 BOOL bInheritHandles,
 | |
|                                 DWORD dwCreationFlags,
 | |
|                                 LPVOID lpEnvironment,
 | |
|                                 LPCWSTR lpCurrentDirectory,
 | |
|                                 LPSTARTUPINFOW lpStartupInfo,
 | |
|                                 LPPROCESS_INFORMATION lpProcessInformation)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     if (lpCommandLine == NULL) {
 | |
|         lpCommandLine = (LPWSTR)lpApplicationName;
 | |
|     }
 | |
| 
 | |
|     CHAR szProc[MAX_PATH];
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         LPPROCESS_INFORMATION ppi = lpProcessInformation;
 | |
|         PROCESS_INFORMATION pi;
 | |
|         if (ppi == NULL) {
 | |
|             ppi = π
 | |
|         }
 | |
| 
 | |
|         rv = DetourCreateProcessWithDllExW(lpApplicationName,
 | |
|                                            lpCommandLine,
 | |
|                                            lpProcessAttributes,
 | |
|                                            lpThreadAttributes,
 | |
|                                            bInheritHandles,
 | |
|                                            dwCreationFlags | CREATE_SUSPENDED,
 | |
|                                            lpEnvironment,
 | |
|                                            lpCurrentDirectory,
 | |
|                                            lpStartupInfo,
 | |
|                                            ppi,
 | |
|                                            s_szDllPath,
 | |
|                                            Real_CreateProcessW);
 | |
| 
 | |
|         if (rv) {
 | |
|             HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
 | |
|             HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 | |
|             HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
 | |
| 
 | |
|             if (lpStartupInfo != NULL && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) != 0) {
 | |
|                 hStdin = lpStartupInfo->hStdInput;
 | |
|                 hStdout = lpStartupInfo->hStdOutput;
 | |
|                 hStderr = lpStartupInfo->hStdError;
 | |
|             }
 | |
|             CreateProcessInternals(ppi->hProcess, ppi->dwProcessId,
 | |
|                                    szProc, hStdin, hStdout, hStderr);
 | |
| 
 | |
|             Print("<t:Child id=\"::%hs::\">\n", szProc);
 | |
| 
 | |
|             WCHAR wzPath[MAX_PATH];
 | |
|             FileInfo *pInfo = NULL;
 | |
|             if (lpApplicationName == NULL) {
 | |
|                 PWCHAR pwzDst = wzPath;
 | |
|                 PWCHAR pwzSrc = lpCommandLine;
 | |
| 
 | |
|                 if (*pwzSrc == '\"') {
 | |
|                     WCHAR cQuote = *pwzSrc++;
 | |
| 
 | |
|                     while (*pwzSrc && *pwzSrc != cQuote) {
 | |
|                         *pwzDst++ = *pwzSrc++;
 | |
|                     }
 | |
|                     *pwzDst++ = '\0';
 | |
|                 }
 | |
|                 else {
 | |
|                     while (*pwzSrc && *pwzSrc != ' ' && *pwzSrc != '\t') {
 | |
|                         if (*pwzSrc == '\t') {
 | |
|                             *pwzSrc = ' ';
 | |
|                         }
 | |
|                         *pwzDst++ = *pwzSrc++;
 | |
|                     }
 | |
|                     *pwzDst++ = '\0';
 | |
|                 }
 | |
|                 pInfo = FileNames::FindPartial(wzPath);
 | |
|             }
 | |
|             else {
 | |
|                 pInfo = FileNames::FindPartial(lpApplicationName);
 | |
|             }
 | |
| 
 | |
|             Print("<t:Executable>%ls</t:Executable>\n",
 | |
|                   FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo));
 | |
|             Print("<t:Line>%le</t:Line>\n", lpCommandLine);
 | |
|             Print("</t:Child>\n");
 | |
| 
 | |
|             if (pInfo) {
 | |
|                 pInfo->m_fAbsorbed = true;
 | |
|             }
 | |
| 
 | |
|             if (!(dwCreationFlags & CREATE_SUSPENDED)) {
 | |
|                 ResumeThread(ppi->hThread);
 | |
|             }
 | |
| 
 | |
|             if (ppi == &pi) {
 | |
|                 Real_CloseHandle(ppi->hThread);
 | |
|                 Real_CloseHandle(ppi->hProcess);
 | |
|             }
 | |
|         }
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (!rv) {
 | |
|             Print("<!-- Warning: CreateProcessW failed %d: %ls; %ls -->\n",
 | |
|                   GetLastError(), lpApplicationName, lpCommandLine);
 | |
|         }
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CreateProcessA(LPCSTR lpApplicationName,
 | |
|                                 LPSTR lpCommandLine,
 | |
|                                 LPSECURITY_ATTRIBUTES lpProcessAttributes,
 | |
|                                 LPSECURITY_ATTRIBUTES lpThreadAttributes,
 | |
|                                 BOOL bInheritHandles,
 | |
|                                 DWORD dwCreationFlags,
 | |
|                                 LPVOID lpEnvironment,
 | |
|                                 LPCSTR lpCurrentDirectory,
 | |
|                                 LPSTARTUPINFOA lpStartupInfo,
 | |
|                                 LPPROCESS_INFORMATION lpProcessInformation)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     if (lpCommandLine == NULL) {
 | |
|         lpCommandLine = (LPSTR)lpApplicationName;
 | |
|     }
 | |
| 
 | |
|     CHAR szProc[MAX_PATH];
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         LPPROCESS_INFORMATION ppi = lpProcessInformation;
 | |
|         PROCESS_INFORMATION pi;
 | |
|         if (ppi == NULL) {
 | |
|             ppi = π
 | |
|         }
 | |
| 
 | |
|         rv = DetourCreateProcessWithDllExA(lpApplicationName,
 | |
|                                            lpCommandLine,
 | |
|                                            lpProcessAttributes,
 | |
|                                            lpThreadAttributes,
 | |
|                                            bInheritHandles,
 | |
|                                            dwCreationFlags | CREATE_SUSPENDED,
 | |
|                                            lpEnvironment,
 | |
|                                            lpCurrentDirectory,
 | |
|                                            lpStartupInfo,
 | |
|                                            ppi,
 | |
|                                            s_szDllPath,
 | |
|                                            Real_CreateProcessA);
 | |
| 
 | |
|         if (rv) {
 | |
|             HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
 | |
|             HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 | |
|             HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
 | |
| 
 | |
|             if (lpStartupInfo != NULL && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) != 0) {
 | |
|                 hStdin = lpStartupInfo->hStdInput;
 | |
|                 hStdout = lpStartupInfo->hStdOutput;
 | |
|                 hStderr = lpStartupInfo->hStdError;
 | |
|             }
 | |
|             CreateProcessInternals(ppi->hProcess, ppi->dwProcessId,
 | |
|                                    szProc, hStdin, hStdout, hStderr);
 | |
| 
 | |
|             Print("<t:Child id=\"::%hs::\">\n", szProc);
 | |
| 
 | |
|             WCHAR wzPath[MAX_PATH];
 | |
|             FileInfo *pInfo = NULL;
 | |
|             if (lpApplicationName == NULL) {
 | |
|                 PCHAR pszDst = szProc;
 | |
|                 PCHAR pszSrc = lpCommandLine;
 | |
| 
 | |
|                 if (*pszSrc == '\"') {
 | |
|                     CHAR cQuote = *pszSrc++;
 | |
| 
 | |
|                     while (*pszSrc && *pszSrc != cQuote) {
 | |
|                         *pszDst++ = *pszSrc++;
 | |
|                     }
 | |
|                     *pszDst++ = '\0';
 | |
|                 }
 | |
|                 else {
 | |
|                     while (*pszSrc && *pszSrc != ' ' && *pszSrc != '\t') {
 | |
|                         if (*pszSrc == '\t') {
 | |
|                             *pszSrc = ' ';
 | |
|                         }
 | |
|                         *pszDst++ = *pszSrc++;
 | |
|                     }
 | |
|                     *pszDst++ = '\0';
 | |
|                 }
 | |
|                 pInfo = FileNames::FindPartial(szProc);
 | |
|             }
 | |
|             else {
 | |
|                 pInfo = FileNames::FindPartial(lpApplicationName);
 | |
|             }
 | |
| 
 | |
|             Print("<t:Executable>%ls</t:Executable>\n",
 | |
|                   FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo));
 | |
|             Print("<t:Line>%he</t:Line>\n", lpCommandLine);
 | |
|             Print("</t:Child>\n");
 | |
| 
 | |
|             if (pInfo) {
 | |
|                 pInfo->m_fAbsorbed = true;
 | |
|             }
 | |
| 
 | |
|             if (!(dwCreationFlags & CREATE_SUSPENDED)) {
 | |
|                 ResumeThread(ppi->hThread);
 | |
|             }
 | |
|             if (ppi == &pi) {
 | |
|                 Real_CloseHandle(ppi->hThread);
 | |
|                 Real_CloseHandle(ppi->hProcess);
 | |
|             }
 | |
|         }
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (!rv) {
 | |
|             Print("<!-- Warning: CreateProcessA failed %d: %hs; %hs -->\n",
 | |
|                   GetLastError(), lpApplicationName, lpCommandLine);
 | |
|         }
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| //
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| BOOL WINAPI Mine_CopyFileExA(LPCSTR a0,
 | |
|                              LPCSTR a1,
 | |
|                              LPPROGRESS_ROUTINE a2,
 | |
|                              LPVOID a3,
 | |
|                              LPBOOL a4,
 | |
|                              DWORD a5)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CopyFileExA(a0, a1, a2, a3, a4, a5);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
| #if 0
 | |
|             Print("<!-- CopyFileExA %he to %he -->\n", a0, a1);
 | |
| #endif
 | |
|             NoteRead(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CopyFileExW(LPCWSTR a0,
 | |
|                              LPCWSTR a1,
 | |
|                              LPPROGRESS_ROUTINE a2,
 | |
|                              LPVOID a3,
 | |
|                              LPBOOL a4,
 | |
|                              DWORD a5)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
| #if 0
 | |
|         Print("\n");
 | |
|         Print("<!-- CopyFileExW %le to %le before -->\n", a0, a1);
 | |
| #endif
 | |
|         rv = Real_CopyFileExW(a0, a1, a2, a3, a4, a5);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
| #if 0
 | |
|             Print("<!-- CopyFileExW %le to %le -->\n", a0, a1);
 | |
| #endif
 | |
|             NoteRead(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_PrivCopyFileExW(LPCWSTR a0,
 | |
|                                  LPCWSTR a1,
 | |
|                                  LPPROGRESS_ROUTINE a2,
 | |
|                                  LPVOID a3,
 | |
|                                  LPBOOL a4,
 | |
|                                  DWORD a5)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_PrivCopyFileExW(a0, a1, a2, a3, a4, a5);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
| #if 0
 | |
|             Print("<!-- PrivCopyFileExW %le to %le -->\n", a0, a1);
 | |
| #endif
 | |
|             NoteRead(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CreateHardLinkA(LPCSTR a0,
 | |
|                                  LPCSTR a1,
 | |
|                                  LPSECURITY_ATTRIBUTES a2)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreateHardLinkA(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
| #if 0
 | |
|             Print("<!-- CreateHardLinkA %he to %he -->\n", a0, a1);
 | |
| #endif
 | |
|             NoteRead(a1);
 | |
|             NoteWrite(a0);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CreateHardLinkW(LPCWSTR a0,
 | |
|                                  LPCWSTR a1,
 | |
|                                  LPSECURITY_ATTRIBUTES a2)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreateHardLinkW(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
| #if 0
 | |
|             Print("<!-- CreateHardLinkW %le to %le -->\n", a0, a1);
 | |
| #endif
 | |
|             NoteRead(a1);
 | |
|             NoteWrite(a0);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CloseHandle(HANDLE a0)
 | |
| {
 | |
|     /*int nIndent =*/ EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         ProcInfo * pProc = OpenFiles::RecallProc(a0);
 | |
|         if (pProc != NULL) {
 | |
|             Procs::Close(pProc->m_hProc);
 | |
|         }
 | |
| 
 | |
|         FileInfo * pFile = OpenFiles::RecallFile(a0);
 | |
|         if (pFile != NULL) {
 | |
|             DWORD dwErr = GetLastError();
 | |
|             pFile->m_cbContent = GetFileSize(a0, NULL);
 | |
|             if (pFile->m_cbContent == INVALID_FILE_SIZE) {
 | |
|                 pFile->m_cbContent = 0;
 | |
|             }
 | |
| 
 | |
|             if (pFile->m_fCantRead) {
 | |
|                 if (pFile->m_fRead) {
 | |
| #if 0
 | |
|                     Print("<!-- Warning: Removing read from %le -->\n", pFile->m_pwzPath);
 | |
| #endif
 | |
|                     pFile->m_fRead = FALSE;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Here we should think about reading the file contents as appropriate.
 | |
|             if (pFile->m_fTemporaryPath && pFile->m_fRead && !pFile->m_fAbsorbed &&
 | |
|                 !pFile->m_fDelete && !pFile->m_fCleanup && !pFile->m_fWrite &&
 | |
|                 pFile->m_pbContent == NULL &&
 | |
|                 pFile->m_cbContent < 16384) {
 | |
| 
 | |
|                 pFile->m_pbContent = LoadFile(a0, pFile->m_cbContent);
 | |
|             }
 | |
| 
 | |
|             SetLastError(dwErr);
 | |
|         }
 | |
|         rv = Real_CloseHandle(a0);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv /* && nIndent == 0*/) {
 | |
|             OpenFiles::Forget(a0);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_DuplicateHandle(HANDLE hSourceProcessHandle,
 | |
|                                  HANDLE hSourceHandle,
 | |
|                                  HANDLE hTargetProcessHandle,
 | |
|                                  LPHANDLE lpTargetHandle,
 | |
|                                  DWORD dwDesiredAccess,
 | |
|                                  BOOL bInheritHandle,
 | |
|                                  DWORD dwOptions)
 | |
| {
 | |
|     HANDLE hTemp = INVALID_HANDLE_VALUE;
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         if (lpTargetHandle == NULL) {
 | |
|             lpTargetHandle = &hTemp;
 | |
|         }
 | |
|         *lpTargetHandle = INVALID_HANDLE_VALUE;
 | |
| 
 | |
|         rv = Real_DuplicateHandle(hSourceProcessHandle,
 | |
|                                   hSourceHandle,
 | |
|                                   hTargetProcessHandle,
 | |
|                                   lpTargetHandle,
 | |
|                                   dwDesiredAccess,
 | |
|                                   bInheritHandle,
 | |
|                                   dwOptions);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (*lpTargetHandle != INVALID_HANDLE_VALUE) {
 | |
|             FileInfo *pInfo = OpenFiles::RecallFile(hSourceHandle);
 | |
|             if (pInfo) {
 | |
|                 OpenFiles::Remember(*lpTargetHandle, pInfo);
 | |
|             }
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| static LONG s_nPipeCnt = 0;
 | |
| 
 | |
| BOOL WINAPI Mine_CreatePipe(PHANDLE hReadPipe,
 | |
|                             PHANDLE hWritePipe,
 | |
|                             LPSECURITY_ATTRIBUTES lpPipeAttributes,
 | |
|                             DWORD nSize)
 | |
| {
 | |
|     HANDLE hRead = INVALID_HANDLE_VALUE;
 | |
|     HANDLE hWrite = INVALID_HANDLE_VALUE;
 | |
| 
 | |
|     if (hReadPipe == NULL) {
 | |
|         hReadPipe = &hRead;
 | |
|     }
 | |
|     if (hWritePipe == NULL) {
 | |
|         hWritePipe = &hWrite;
 | |
|     }
 | |
| 
 | |
|     /*int nIndent = */ EnterFunc();
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreatePipe(hReadPipe, hWritePipe, lpPipeAttributes, nSize);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             CHAR szPipe[128];
 | |
| 
 | |
|             SafePrintf(szPipe, ARRAYSIZE(szPipe), "\\\\.\\PIPE\\Temp.%d.%d",
 | |
|                        GetCurrentProcessId(),
 | |
|                        InterlockedIncrement(&s_nPipeCnt));
 | |
| 
 | |
|             FileInfo *pInfo = FileNames::FindPartial(szPipe);
 | |
| 
 | |
|             pInfo->m_fCleanup = TRUE;
 | |
|             OpenFiles::Remember(*hReadPipe, pInfo);
 | |
|             OpenFiles::Remember(*hWritePipe, pInfo);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CreateDirectoryW(LPCWSTR a0,
 | |
|                                   LPSECURITY_ATTRIBUTES a1)
 | |
| {
 | |
|     /* int nIndent = */ EnterFunc();
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreateDirectoryW(a0, a1);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             FileInfo *pInfo = FileNames::FindPartial(a0);
 | |
|             pInfo->m_fDirectory = TRUE;
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_CreateDirectoryExW(LPCWSTR a0,
 | |
|                                     LPCWSTR a1,
 | |
|                                     LPSECURITY_ATTRIBUTES a2)
 | |
| {
 | |
|     /* int nIndent = */ EnterFunc();
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreateDirectoryExW(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             FileInfo *pInfo = FileNames::FindPartial(a1);
 | |
|             pInfo->m_fDirectory = TRUE;
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| HANDLE WINAPI Mine_CreateFileW(LPCWSTR a0,
 | |
|                                DWORD access,
 | |
|                                DWORD share,
 | |
|                                LPSECURITY_ATTRIBUTES a3,
 | |
|                                DWORD create,
 | |
|                                DWORD flags,
 | |
|                                HANDLE a6)
 | |
| {
 | |
|     /* int nIndent = */ EnterFunc();
 | |
|     HANDLE rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreateFileW(a0, access, share, a3, create, flags, a6);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
| #if 0
 | |
|             Print("<!-- CreateFileW(%le, ac=%08x, cr=%08x, fl=%08x -->\n",
 | |
|                   a0,
 | |
|                   access,
 | |
|                   create,
 | |
|                   flags);
 | |
| #endif
 | |
| 
 | |
|         if (access != 0 && /* nIndent == 0 && */ rv != INVALID_HANDLE_VALUE) {
 | |
| 
 | |
|             FileInfo *pInfo = FileNames::FindPartial(a0);
 | |
| 
 | |
|             // FILE_FLAG_WRITE_THROUGH              0x80000000
 | |
|             // FILE_FLAG_OVERLAPPED                 0x40000000
 | |
|             // FILE_FLAG_NO_BUFFERING               0x20000000
 | |
|             // FILE_FLAG_RANDOM_ACCESS              0x10000000
 | |
|             // FILE_FLAG_SEQUENTIAL_SCAN            0x08000000
 | |
|             // FILE_FLAG_DELETE_ON_CLOSE            0x04000000
 | |
|             // FILE_FLAG_BACKUP_SEMANTICS           0x02000000
 | |
|             // FILE_FLAG_POSIX_SEMANTICS            0x01000000
 | |
|             // FILE_FLAG_OPEN_REPARSE_POINT         0x00200000
 | |
|             // FILE_FLAG_OPEN_NO_RECALL             0x00100000
 | |
|             // FILE_FLAG_FIRST_PIPE_INSTANCE        0x00080000
 | |
|             // FILE_ATTRIBUTE_ENCRYPTED             0x00004000
 | |
|             // FILE_ATTRIBUTE_NOT_CONTENT_INDEXED   0x00002000
 | |
|             // FILE_ATTRIBUTE_OFFLINE               0x00001000
 | |
|             // FILE_ATTRIBUTE_COMPRESSED            0x00000800
 | |
|             // FILE_ATTRIBUTE_REPARSE_POINT         0x00000400
 | |
|             // FILE_ATTRIBUTE_SPARSE_FILE           0x00000200
 | |
|             // FILE_ATTRIBUTE_TEMPORARY             0x00000100
 | |
|             // FILE_ATTRIBUTE_NORMAL                0x00000080
 | |
|             // FILE_ATTRIBUTE_DEVICE                0x00000040
 | |
|             // FILE_ATTRIBUTE_ARCHIVE               0x00000020
 | |
|             // FILE_ATTRIBUTE_DIRECTORY             0x00000010
 | |
|             // FILE_ATTRIBUTE_SYSTEM                0x00000004
 | |
|             // FILE_ATTRIBUTE_HIDDEN                0x00000002
 | |
|             // FILE_ATTRIBUTE_READONLY              0x00000001
 | |
| 
 | |
|             // CREATE_NEW          1
 | |
|             // CREATE_ALWAYS       2
 | |
|             // OPEN_EXISTING       3
 | |
|             // OPEN_ALWAYS         4
 | |
|             // TRUNCATE_EXISTING   5
 | |
| 
 | |
|             if (create == CREATE_NEW ||
 | |
|                 create == CREATE_ALWAYS ||
 | |
|                 create == TRUNCATE_EXISTING) {
 | |
| 
 | |
|                 if (!pInfo->m_fRead) {
 | |
|                     pInfo->m_fCantRead = TRUE;
 | |
|                 }
 | |
|             }
 | |
|             else if (create == OPEN_EXISTING) {
 | |
|             }
 | |
|             else if (create == OPEN_ALWAYS) {
 | |
|                 // pInfo->m_fAppend = TRUE;    // !!!
 | |
|             }
 | |
| 
 | |
|             if ((flags & FILE_FLAG_DELETE_ON_CLOSE)) {
 | |
|                 pInfo->m_fCleanup = TRUE;
 | |
|             }
 | |
| 
 | |
|             OpenFiles::Remember(rv, pInfo);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| HANDLE WINAPI Mine_CreateFileMappingW(HANDLE hFile,
 | |
|                                       LPSECURITY_ATTRIBUTES a1,
 | |
|                                       DWORD flProtect,
 | |
|                                       DWORD a3,
 | |
|                                       DWORD a4,
 | |
|                                       LPCWSTR a5)
 | |
| {
 | |
|     /* int nIndent = */ EnterFunc();
 | |
|     HANDLE rv = 0;
 | |
|     __try {
 | |
|         rv = Real_CreateFileMappingW(hFile, a1, flProtect, a3, a4, a5);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv != INVALID_HANDLE_VALUE) {
 | |
| 
 | |
|             FileInfo *pInfo = OpenFiles::RecallFile(hFile);
 | |
| 
 | |
|             if (pInfo != NULL) {
 | |
|                 switch (flProtect) {
 | |
|                   case PAGE_READONLY:
 | |
|                     pInfo->m_fRead = TRUE;
 | |
|                     break;
 | |
|                   case PAGE_READWRITE:
 | |
|                     pInfo->m_fRead = TRUE;
 | |
|                     pInfo->m_fWrite = TRUE;
 | |
|                     break;
 | |
|                   case PAGE_WRITECOPY:
 | |
|                     pInfo->m_fRead = TRUE;
 | |
|                     break;
 | |
|                   case PAGE_EXECUTE_READ:
 | |
|                     pInfo->m_fRead = TRUE;
 | |
|                     break;
 | |
|                   case PAGE_EXECUTE_READWRITE:
 | |
|                     pInfo->m_fRead = TRUE;
 | |
|                     pInfo->m_fWrite = TRUE;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_DeleteFileW(LPCWSTR a0)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_DeleteFileW(a0);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
| #if 0
 | |
|         Print("<!-- DeleteFileW(%le -->\n", a0);
 | |
| #endif
 | |
|         NoteDelete(a0);
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| static VOID Dump(LPVOID pvData, DWORD cbData)
 | |
| {
 | |
|     CHAR szBuffer[128];
 | |
|     PBYTE pbData = (PBYTE)pvData;
 | |
| 
 | |
|     for (DWORD i = 0; i < cbData; i += 16) {
 | |
|         PCHAR psz = szBuffer;
 | |
|         psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), "%4d: ", i);
 | |
| 
 | |
|         for (DWORD j = i; j < i + 16; j++) {
 | |
|             if (j < cbData) {
 | |
|                 psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz),
 | |
|                                  "%02x", pbData[j]);
 | |
|             }
 | |
|             else {
 | |
|                 psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), "  ");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         for (DWORD j = i; j < i + 16; j++) {
 | |
|             if (j < cbData) {
 | |
|                 if (pbData[j] >= ' ' && pbData[j] <= 127) {
 | |
|                     psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz),
 | |
|                                      "%c", pbData[j]);
 | |
|                 }
 | |
|                 else {
 | |
|                     psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), ".");
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 psz = SafePrintf(psz, (LONG)(szBuffer + ARRAYSIZE(szBuffer) - psz), " ");
 | |
|             }
 | |
|         }
 | |
|         Print("%s\n", szBuffer);
 | |
|     }
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_DeviceIoControl(HANDLE a0,
 | |
|                                  DWORD a1,
 | |
|                                  LPVOID a2,
 | |
|                                  DWORD a3,
 | |
|                                  LPVOID a4,
 | |
|                                  DWORD a5,
 | |
|                                  LPDWORD a6,
 | |
|                                  LPOVERLAPPED a7)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD d6 = 0;
 | |
|     if (a6 == NULL) {
 | |
|         a6 = &d6;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_DeviceIoControl(a0, a1, a2, a3, a4, a5, a6, a7);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         OpenFiles::SetRead(a0, 0);
 | |
|         OpenFiles::SetWrite(a0, 0);
 | |
|         if (rv && a1 != 0x390008 && a1 != 0x4d0008 && a1 != 0x6d0008) {
 | |
|             FileInfo *pInfo = OpenFiles::RecallFile(a0);
 | |
| 
 | |
|             DWORD DeviceType    = (a1 & 0xffff0000) >> 16;
 | |
|             DWORD Access        = (a1 & 0x0000c000) >> 14;
 | |
|             DWORD Function      = (a1 & 0x00003ffc) >> 2;
 | |
|             DWORD Method        = (a1 & 0x00000003) >> 0;
 | |
| 
 | |
|             if (pInfo) {
 | |
|                 Print("<!-- DeviceIoControl %x [dev=%x,acc=%x,fun=%x,mth=%x] on %ls! -->\n",
 | |
|                       a1, DeviceType, Access, Function, Method, pInfo->m_pwzPath);
 | |
|             }
 | |
|             else {
 | |
|                 Print("<!-- DeviceIoControl %x [dev=%x,acc=%x,fun=%x,mth=%x,in=%d,out=%d/%d] on (%x)! -->\n",
 | |
|                       a1, DeviceType, Access, Function, Method, a3, *a6, a5, a0);
 | |
| 
 | |
|                 if (a3 > 0) {
 | |
|                     Dump(a2, a3);
 | |
|                 }
 | |
|                 if (a5 > 0) {
 | |
|                     Dump(a4, (*a6 < a5) ? *a6 : a5);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD WINAPI Mine_GetFileAttributesW(LPCWSTR a0)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         rv = Real_GetFileAttributesW(a0);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_MoveFileWithProgressW(LPCWSTR a0,
 | |
|                                        LPCWSTR a1,
 | |
|                                        LPPROGRESS_ROUTINE a2,
 | |
|                                        LPVOID a3,
 | |
|                                        DWORD a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_MoveFileWithProgressW(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             NoteRead(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_MoveFileA(LPCSTR a0,
 | |
|                            LPCSTR a1)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_MoveFileA(a0, a1);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             NoteRead(a0);
 | |
|             NoteCleanup(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_MoveFileW(LPCWSTR a0,
 | |
|                            LPCWSTR a1)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_MoveFileW(a0, a1);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             NoteRead(a0);
 | |
|             NoteCleanup(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_MoveFileExA(LPCSTR a0,
 | |
|                              LPCSTR a1,
 | |
|                              DWORD a2)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_MoveFileExA(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             NoteRead(a0);
 | |
|             NoteCleanup(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_MoveFileExW(LPCWSTR a0,
 | |
|                              LPCWSTR a1,
 | |
|                              DWORD a2)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_MoveFileExW(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|         if (rv) {
 | |
|             NoteRead(a0);
 | |
|             NoteCleanup(a0);
 | |
|             NoteWrite(a1);
 | |
|         }
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| void SetHandle(PCSTR pszName, HANDLE h)
 | |
| {
 | |
| #if 0
 | |
|     FileInfo *pInfo = OpenFiles::RecallFile(h);
 | |
| 
 | |
|     if (pInfo != NULL) {
 | |
|         Tblog("<!-- hset: %hs (%x) %ls -->\n", pszName, h, pInfo->m_pwzPath);
 | |
|     }
 | |
|     else {
 | |
|         Tblog("<!-- hset: %hs (%x) ***Unknown*** -->\n", pszName, h);
 | |
|     }
 | |
| #else
 | |
|     (void)pszName;
 | |
|     (void)h;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| BOOL WINAPI Mine_SetStdHandle(DWORD a0,
 | |
|                               HANDLE a1)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_SetStdHandle(a0, a1);
 | |
|         if (rv && a1 != 0) {
 | |
|             switch (a0) {
 | |
|               case STD_INPUT_HANDLE:
 | |
|                 SetHandle("stdin", a1);
 | |
|                 break;
 | |
|               case STD_OUTPUT_HANDLE:
 | |
|                 SetHandle("stdout", a1);
 | |
|                 break;
 | |
|               case STD_ERROR_HANDLE:
 | |
|                 SetHandle("stderr", a1);
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| HMODULE WINAPI Mine_LoadLibraryA(LPCSTR a0)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     HMODULE rv = 0;
 | |
|     __try {
 | |
|         rv = Real_LoadLibraryA(a0);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| HMODULE WINAPI Mine_LoadLibraryW(LPCWSTR a0)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     HMODULE rv = 0;
 | |
|     __try {
 | |
|         rv = Real_LoadLibraryW(a0);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| HMODULE WINAPI Mine_LoadLibraryExA(LPCSTR a0,
 | |
|                                    HANDLE a1,
 | |
|                                    DWORD a2)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     HMODULE rv = 0;
 | |
|     __try {
 | |
|         rv = Real_LoadLibraryExA(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| HMODULE WINAPI Mine_LoadLibraryExW(LPCWSTR a0,
 | |
|                                    HANDLE a1,
 | |
|                                    DWORD a2)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     HMODULE rv = 0;
 | |
|     __try {
 | |
|         rv = Real_LoadLibraryExW(a0, a1, a2);
 | |
|     } __finally {
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD WINAPI Mine_SetFilePointer(HANDLE hFile,
 | |
|                                  LONG lDistanceToMove,
 | |
|                                  PLONG lpDistanceToMoveHigh,
 | |
|                                  DWORD dwMoveMethod)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         rv = Real_SetFilePointer(hFile,
 | |
|                                  lDistanceToMove,
 | |
|                                  lpDistanceToMoveHigh,
 | |
|                                  dwMoveMethod);
 | |
|     } __finally {
 | |
|         LONG high = 0;
 | |
|         if (lpDistanceToMoveHigh == NULL) {
 | |
|             lpDistanceToMoveHigh = &high;
 | |
|         }
 | |
| 
 | |
|         FileInfo * pInfo = OpenFiles::RecallFile(hFile);
 | |
|         if (pInfo != NULL) {
 | |
|             if (dwMoveMethod == FILE_END && lDistanceToMove == 0xffffffff) {
 | |
| #if 0
 | |
|                 Print("<!-- SetFilePointer(APPEND, %le) -->\n",
 | |
|                       pInfo->m_pwzPath);
 | |
| #endif
 | |
|                 pInfo->m_fAppend = TRUE;
 | |
|             }
 | |
| #if 0
 | |
|             else if (dwMoveMethod == FILE_END) {
 | |
|                 Print("<!-- SetFilePointer(END:%08x:%08x, %le) -->\n",
 | |
|                       (int)lDistanceToMove,
 | |
|                       *lpDistanceToMoveHigh,
 | |
|                       pInfo->m_pwzPath);
 | |
|             }
 | |
|             else if (dwMoveMethod == FILE_BEGIN) {
 | |
|                 Print("<!-- SetFilePointer(BEG:%08x:%08x, %le) -->\n",
 | |
|                       (int)lDistanceToMove,
 | |
|                       *lpDistanceToMoveHigh,
 | |
|                       pInfo->m_pwzPath);
 | |
|             }
 | |
|             else if (dwMoveMethod == FILE_CURRENT) {
 | |
|                 Print("<!-- SetFilePointer(CUR:%08x:%08x, %le) -->\n",
 | |
|                       (int)lDistanceToMove,
 | |
|                       *lpDistanceToMoveHigh,
 | |
|                       pInfo->m_pwzPath);
 | |
|             }
 | |
| #endif
 | |
|         }
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_SetFilePointerEx(HANDLE hFile,
 | |
|                                   LARGE_INTEGER liDistanceToMove,
 | |
|                                   PLARGE_INTEGER lpNewFilePointer,
 | |
|                                   DWORD dwMoveMethod)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_SetFilePointerEx(hFile,
 | |
|                                    liDistanceToMove,
 | |
|                                    lpNewFilePointer,
 | |
|                                    dwMoveMethod);
 | |
|     } __finally {
 | |
| #if 0
 | |
|         FileInfo * pInfo = OpenFiles::RecallFile(hFile);
 | |
|         if (pInfo != NULL) {
 | |
|             if (dwMoveMethod == FILE_END) {
 | |
|                 Print("<!-- SetFilePointerEx(END:%I64d, %le) -->\n",
 | |
|                       liDistanceToMove.QuadPart,
 | |
|                       pInfo->m_pwzPath);
 | |
|             }
 | |
|             else if (dwMoveMethod == FILE_BEGIN) {
 | |
|                 Print("<!-- SetFilePointerEx(BEG:%I64d, %le) -->\n",
 | |
|                       liDistanceToMove.QuadPart,
 | |
|                       pInfo->m_pwzPath);
 | |
|             }
 | |
|             else if (dwMoveMethod == FILE_CURRENT) {
 | |
|                 Print("<!-- SetFilePointerEx(CUR:%I64d, %le) -->\n",
 | |
|                       liDistanceToMove.QuadPart,
 | |
|                       pInfo->m_pwzPath);
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_ReadFile(HANDLE a0,
 | |
|                           LPVOID a1,
 | |
|                           DWORD a2,
 | |
|                           LPDWORD a3,
 | |
|                           LPOVERLAPPED a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_ReadFile(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         if (rv) {
 | |
|             OpenFiles::SetRead(a0, a2);
 | |
|         }
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_ReadFileEx(HANDLE a0,
 | |
|                             LPVOID a1,
 | |
|                             DWORD a2,
 | |
|                             LPOVERLAPPED a3,
 | |
|                             LPOVERLAPPED_COMPLETION_ROUTINE a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_ReadFileEx(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         if (rv) {
 | |
|             OpenFiles::SetRead(a0, a2);
 | |
|         }
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_WriteFile(HANDLE a0,
 | |
|                            LPCVOID a1,
 | |
|                            DWORD a2,
 | |
|                            LPDWORD a3,
 | |
|                            LPOVERLAPPED a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_WriteFile(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         OpenFiles::SetWrite(a0, a2);
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_WriteFileEx(HANDLE a0,
 | |
|                              LPCVOID a1,
 | |
|                              DWORD a2,
 | |
|                              LPOVERLAPPED a3,
 | |
|                              LPOVERLAPPED_COMPLETION_ROUTINE a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_WriteFileEx(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         OpenFiles::SetWrite(a0, a2);
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_WriteConsoleA(HANDLE a0,
 | |
|                                   const VOID* a1,
 | |
|                                   DWORD a2,
 | |
|                                   LPDWORD a3,
 | |
|                                   LPVOID a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_WriteConsoleA(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         OpenFiles::SetWrite(a0, a2);
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| BOOL WINAPI Mine_WriteConsoleW(HANDLE a0,
 | |
|                                   const VOID* a1,
 | |
|                                   DWORD a2,
 | |
|                                   LPDWORD a3,
 | |
|                                   LPVOID a4)
 | |
| {
 | |
|     EnterFunc();
 | |
| 
 | |
|     BOOL rv = 0;
 | |
|     __try {
 | |
|         rv = Real_WriteConsoleW(a0, a1, a2, a3, a4);
 | |
|     } __finally {
 | |
|         OpenFiles::SetWrite(a0, a2);
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| DWORD WINAPI Mine_ExpandEnvironmentStringsA(PCSTR lpSrc, PCHAR lpDst, DWORD nSize)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         rv = Real_ExpandEnvironmentStringsA(lpSrc, lpDst, nSize);
 | |
|     }
 | |
|     __finally {
 | |
|         if (rv > 0) {
 | |
| #if 0
 | |
|             Print("<!-- ExpandEnvironmentStringsA(%he) -->\n", lpSrc);
 | |
| #endif
 | |
|         }
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD WINAPI Mine_ExpandEnvironmentStringsW(PCWSTR lpSrc, PWCHAR lpDst, DWORD nSize)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         rv = Real_ExpandEnvironmentStringsW(lpSrc, lpDst, nSize);
 | |
|     }
 | |
|     __finally {
 | |
|         if (rv > 0) {
 | |
| #if 0
 | |
|             Print("<!-- ExpandEnvironmentStringsW(%le) -->\n", lpSrc);
 | |
| #endif
 | |
|         }
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD WINAPI Mine_GetEnvironmentVariableA(PCSTR lpName, PCHAR lpBuffer, DWORD nSize)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         rv = Real_GetEnvironmentVariableA(lpName, lpBuffer, nSize);
 | |
|         //        if (rv > 0 && rv < nSize && lpBuffer != NULL) {
 | |
|         //            EnvVars::Used(lpName);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(lpName);
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD WINAPI Mine_GetEnvironmentVariableW(PCWSTR lpName, PWCHAR lpBuffer, DWORD nSize)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         rv = Real_GetEnvironmentVariableW(lpName, lpBuffer, nSize);
 | |
|         //        if (rv > 0 && rv < nSize && lpBuffer != NULL) {
 | |
|         //            EnvVars::Used(lpName);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(lpName);
 | |
|         ExitFunc();
 | |
|     };
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| PCWSTR CDECL Mine_wgetenv(PCWSTR var)
 | |
| {
 | |
|     EnterFunc();
 | |
|     PCWSTR rv = 0;
 | |
|     __try {
 | |
|         rv = Real_wgetenv(var);
 | |
|         //        if (rv != NULL) {
 | |
|         //            EnvVars::Used(var);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(var);
 | |
|         ExitFunc();
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| PCSTR CDECL Mine_getenv(PCSTR var)
 | |
| {
 | |
|     EnterFunc();
 | |
|     PCSTR rv = 0;
 | |
|     __try {
 | |
|         rv = Real_getenv(var);
 | |
|         //        if (rv) {
 | |
|         //            EnvVars::Used(var);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(var);
 | |
|         ExitFunc();
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD CDECL Mine_getenv_s(DWORD *pValue, PCHAR pBuffer, DWORD cBuffer, PCSTR varname)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         DWORD value;
 | |
|         if (pValue == NULL) {
 | |
|             pValue = &value;
 | |
|         }
 | |
|         rv = Real_getenv_s(pValue, pBuffer, cBuffer, varname);
 | |
|         //        if (rv == 0 && *pValue > 0) {
 | |
|         //            EnvVars::Used(varname);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(varname);
 | |
|         ExitFunc();
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD CDECL Mine_wgetenv_s(DWORD *pValue, PWCHAR pBuffer, DWORD cBuffer, PCWSTR varname)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         DWORD value;
 | |
|         if (pValue == NULL) {
 | |
|             pValue = &value;
 | |
|         }
 | |
|         rv = Real_wgetenv_s(pValue, pBuffer, cBuffer, varname);
 | |
|         //        if (rv == 0 && *pValue > 0) {
 | |
|         //            EnvVars::Used(varname);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(varname);
 | |
|         ExitFunc();
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD CDECL Mine_dupenv_s(PCHAR *ppBuffer, DWORD *pcBuffer, PCSTR varname)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         PCHAR pb;
 | |
|         DWORD cb;
 | |
|         if (ppBuffer == NULL) {
 | |
|             ppBuffer = &pb;
 | |
|         }
 | |
|         if (pcBuffer == NULL) {
 | |
|             pcBuffer = &cb;
 | |
|         }
 | |
|         rv = Real_dupenv_s(ppBuffer, pcBuffer, varname);
 | |
|         //        if (rv == 0 && *pcBuffer > 0 && *ppBuffer != NULL) {
 | |
|         //            EnvVars::Used(varname);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(varname);
 | |
|         ExitFunc();
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| DWORD CDECL Mine_wdupenv_s(PWCHAR *ppBuffer, DWORD *pcBuffer, PCWSTR varname)
 | |
| {
 | |
|     EnterFunc();
 | |
|     DWORD rv = 0;
 | |
|     __try {
 | |
|         PWCHAR pb;
 | |
|         DWORD cb;
 | |
|         if (ppBuffer == NULL) {
 | |
|             ppBuffer = &pb;
 | |
|         }
 | |
|         if (pcBuffer == NULL) {
 | |
|             pcBuffer = &cb;
 | |
|         }
 | |
|         rv = Real_wdupenv_s(ppBuffer, pcBuffer, varname);
 | |
|         //        if (rv == 0 && *pcBuffer > 0 && *ppBuffer != NULL) {
 | |
|         //            EnvVars::Used(varname);
 | |
|         //        }
 | |
|     }
 | |
|     __finally {
 | |
|         EnvVars::Used(varname);
 | |
|         ExitFunc();
 | |
|     }
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| 
 | |
| /////////////////////////////////////////////////////////////
 | |
| // AttachDetours
 | |
| //
 | |
| LONG AttachDetours(VOID)
 | |
| {
 | |
|     DetourTransactionBegin();
 | |
|     DetourUpdateThread(GetCurrentThread());
 | |
| 
 | |
|     DetourAttach(&(PVOID&)Real_EntryPoint, Mine_EntryPoint);
 | |
|     DetourAttach(&(PVOID&)Real_ExitProcess, Mine_ExitProcess);
 | |
|     DetourAttach(&(PVOID&)Real_CopyFileExA, Mine_CopyFileExA);
 | |
|     DetourAttach(&(PVOID&)Real_CopyFileExW, Mine_CopyFileExW);
 | |
|     DetourAttach(&(PVOID&)Real_PrivCopyFileExW, Mine_PrivCopyFileExW);
 | |
|     DetourAttach(&(PVOID&)Real_CreateHardLinkA, Mine_CreateHardLinkA);
 | |
|     DetourAttach(&(PVOID&)Real_CreateHardLinkW, Mine_CreateHardLinkW);
 | |
|     DetourAttach(&(PVOID&)Real_CreateDirectoryW, Mine_CreateDirectoryW);
 | |
|     DetourAttach(&(PVOID&)Real_CreateDirectoryExW, Mine_CreateDirectoryExW);
 | |
|     DetourAttach(&(PVOID&)Real_CreateFileW, Mine_CreateFileW);
 | |
|     DetourAttach(&(PVOID&)Real_CreatePipe, Mine_CreatePipe);
 | |
|     DetourAttach(&(PVOID&)Real_CreateFileMappingW, Mine_CreateFileMappingW);
 | |
|     DetourAttach(&(PVOID&)Real_CloseHandle, Mine_CloseHandle);
 | |
|     DetourAttach(&(PVOID&)Real_DuplicateHandle, Mine_DuplicateHandle);
 | |
|     DetourAttach(&(PVOID&)Real_CreateProcessW, Mine_CreateProcessW);
 | |
|     DetourAttach(&(PVOID&)Real_CreateProcessA, Mine_CreateProcessA);
 | |
|     DetourAttach(&(PVOID&)Real_DeleteFileW, Mine_DeleteFileW);
 | |
|     DetourAttach(&(PVOID&)Real_DeviceIoControl, Mine_DeviceIoControl);
 | |
|     DetourAttach(&(PVOID&)Real_GetFileAttributesW, Mine_GetFileAttributesW);
 | |
|     DetourAttach(&(PVOID&)Real_MoveFileA, Mine_MoveFileA);
 | |
|     DetourAttach(&(PVOID&)Real_MoveFileW, Mine_MoveFileW);
 | |
|     DetourAttach(&(PVOID&)Real_MoveFileExA, Mine_MoveFileExA);
 | |
|     DetourAttach(&(PVOID&)Real_MoveFileExW, Mine_MoveFileExW);
 | |
|     DetourAttach(&(PVOID&)Real_MoveFileWithProgressW, Mine_MoveFileWithProgressW);
 | |
|     DetourAttach(&(PVOID&)Real_SetStdHandle, Mine_SetStdHandle);
 | |
|     DetourAttach(&(PVOID&)Real_LoadLibraryA, Mine_LoadLibraryA);
 | |
|     DetourAttach(&(PVOID&)Real_LoadLibraryW, Mine_LoadLibraryW);
 | |
|     DetourAttach(&(PVOID&)Real_LoadLibraryExA, Mine_LoadLibraryExA);
 | |
|     DetourAttach(&(PVOID&)Real_LoadLibraryExW, Mine_LoadLibraryExW);
 | |
|     DetourAttach(&(PVOID&)Real_SetFilePointer, Mine_SetFilePointer);
 | |
|     DetourAttach(&(PVOID&)Real_SetFilePointerEx, Mine_SetFilePointerEx);
 | |
|     DetourAttach(&(PVOID&)Real_ReadFile, Mine_ReadFile);
 | |
|     DetourAttach(&(PVOID&)Real_ReadFileEx, Mine_ReadFileEx);
 | |
|     DetourAttach(&(PVOID&)Real_WriteFile, Mine_WriteFile);
 | |
|     DetourAttach(&(PVOID&)Real_WriteFileEx, Mine_WriteFileEx);
 | |
|     DetourAttach(&(PVOID&)Real_WriteConsoleA, Mine_WriteConsoleA);
 | |
|     DetourAttach(&(PVOID&)Real_WriteConsoleW, Mine_WriteConsoleW);
 | |
|     DetourAttach(&(PVOID&)Real_ExpandEnvironmentStringsA, Mine_ExpandEnvironmentStringsA);
 | |
|     DetourAttach(&(PVOID&)Real_ExpandEnvironmentStringsW, Mine_ExpandEnvironmentStringsW);
 | |
|     DetourAttach(&(PVOID&)Real_GetEnvironmentVariableA, Mine_GetEnvironmentVariableA);
 | |
|     DetourAttach(&(PVOID&)Real_GetEnvironmentVariableW, Mine_GetEnvironmentVariableW);
 | |
| 
 | |
|     return DetourTransactionCommit();
 | |
| }
 | |
| 
 | |
| LONG DetachDetours(VOID)
 | |
| {
 | |
|     DetourTransactionBegin();
 | |
|     DetourUpdateThread(GetCurrentThread());
 | |
| 
 | |
|     DetourDetach(&(PVOID&)Real_EntryPoint, Mine_EntryPoint);
 | |
|     DetourAttach(&(PVOID&)Real_ExitProcess, Mine_ExitProcess);
 | |
|     DetourDetach(&(PVOID&)Real_CopyFileExA, Mine_CopyFileExA);
 | |
|     DetourDetach(&(PVOID&)Real_CopyFileExW, Mine_CopyFileExW);
 | |
|     DetourDetach(&(PVOID&)Real_PrivCopyFileExW, Mine_PrivCopyFileExW);
 | |
|     DetourDetach(&(PVOID&)Real_CreateHardLinkA, Mine_CreateHardLinkA);
 | |
|     DetourDetach(&(PVOID&)Real_CreateHardLinkW, Mine_CreateHardLinkW);
 | |
|     DetourDetach(&(PVOID&)Real_CreateDirectoryW, Mine_CreateDirectoryW);
 | |
|     DetourDetach(&(PVOID&)Real_CreateDirectoryExW, Mine_CreateDirectoryExW);
 | |
|     DetourDetach(&(PVOID&)Real_CreateFileW, Mine_CreateFileW);
 | |
|     DetourDetach(&(PVOID&)Real_CreatePipe, Mine_CreatePipe);
 | |
|     DetourDetach(&(PVOID&)Real_CreateFileMappingW, Mine_CreateFileMappingW);
 | |
|     DetourDetach(&(PVOID&)Real_CloseHandle, Mine_CloseHandle);
 | |
|     DetourDetach(&(PVOID&)Real_DuplicateHandle, Mine_DuplicateHandle);
 | |
|     DetourDetach(&(PVOID&)Real_CreateProcessW, Mine_CreateProcessW);
 | |
|     DetourDetach(&(PVOID&)Real_CreateProcessA, Mine_CreateProcessA);
 | |
|     DetourDetach(&(PVOID&)Real_DeleteFileW, Mine_DeleteFileW);
 | |
|     DetourDetach(&(PVOID&)Real_DeviceIoControl, Mine_DeviceIoControl);
 | |
|     DetourDetach(&(PVOID&)Real_GetFileAttributesW, Mine_GetFileAttributesW);
 | |
|     DetourDetach(&(PVOID&)Real_MoveFileA, Mine_MoveFileA);
 | |
|     DetourDetach(&(PVOID&)Real_MoveFileW, Mine_MoveFileW);
 | |
|     DetourDetach(&(PVOID&)Real_MoveFileExA, Mine_MoveFileExA);
 | |
|     DetourDetach(&(PVOID&)Real_MoveFileExW, Mine_MoveFileExW);
 | |
|     DetourDetach(&(PVOID&)Real_MoveFileWithProgressW, Mine_MoveFileWithProgressW);
 | |
|     DetourDetach(&(PVOID&)Real_SetStdHandle, Mine_SetStdHandle);
 | |
|     DetourDetach(&(PVOID&)Real_LoadLibraryA, Mine_LoadLibraryA);
 | |
|     DetourDetach(&(PVOID&)Real_LoadLibraryW, Mine_LoadLibraryW);
 | |
|     DetourDetach(&(PVOID&)Real_LoadLibraryExA, Mine_LoadLibraryExA);
 | |
|     DetourDetach(&(PVOID&)Real_LoadLibraryExW, Mine_LoadLibraryExW);
 | |
|     DetourDetach(&(PVOID&)Real_SetFilePointer, Mine_SetFilePointer);
 | |
|     DetourDetach(&(PVOID&)Real_SetFilePointerEx, Mine_SetFilePointerEx);
 | |
|     DetourDetach(&(PVOID&)Real_ReadFile, Mine_ReadFile);
 | |
|     DetourDetach(&(PVOID&)Real_ReadFileEx, Mine_ReadFileEx);
 | |
|     DetourDetach(&(PVOID&)Real_WriteFile, Mine_WriteFile);
 | |
|     DetourDetach(&(PVOID&)Real_WriteFileEx, Mine_WriteFileEx);
 | |
|     DetourDetach(&(PVOID&)Real_WriteConsoleA, Mine_WriteConsoleA);
 | |
|     DetourDetach(&(PVOID&)Real_WriteConsoleW, Mine_WriteConsoleW);
 | |
|     DetourDetach(&(PVOID&)Real_ExpandEnvironmentStringsA, Mine_ExpandEnvironmentStringsA);
 | |
|     DetourDetach(&(PVOID&)Real_ExpandEnvironmentStringsW, Mine_ExpandEnvironmentStringsW);
 | |
|     DetourDetach(&(PVOID&)Real_GetEnvironmentVariableA, Mine_GetEnvironmentVariableA);
 | |
|     DetourDetach(&(PVOID&)Real_GetEnvironmentVariableW, Mine_GetEnvironmentVariableW);
 | |
| 
 | |
|     if (Real_getenv) { DetourDetach(&(PVOID&)Real_getenv, Mine_getenv); }
 | |
|     if (Real_getenv_s) { DetourDetach(&(PVOID&)Real_getenv_s, Mine_getenv_s); }
 | |
|     if (Real_wgetenv) { DetourDetach(&(PVOID&)Real_wgetenv, Mine_wgetenv); }
 | |
|     if (Real_wgetenv_s) { DetourDetach(&(PVOID&)Real_wgetenv, Mine_wgetenv_s); }
 | |
|     if (Real_dupenv_s) { DetourDetach(&(PVOID&)Real_dupenv_s, Mine_dupenv_s); }
 | |
|     if (Real_wdupenv_s) { DetourDetach(&(PVOID&)Real_wdupenv_s, Mine_wdupenv_s); }
 | |
| 
 | |
|     return DetourTransactionCommit();
 | |
| }
 | |
| //
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| VOID NoteRead(PCSTR psz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(psz);
 | |
|     pInfo->m_fRead = TRUE;
 | |
| }
 | |
| 
 | |
| VOID NoteRead(PCWSTR pwz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(pwz);
 | |
|     pInfo->m_fRead = TRUE;
 | |
| }
 | |
| 
 | |
| VOID NoteWrite(PCSTR psz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(psz);
 | |
|     pInfo->m_fWrite = TRUE;
 | |
|     if (!pInfo->m_fRead) {
 | |
|         pInfo->m_fCantRead = TRUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID NoteWrite(PCWSTR pwz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(pwz);
 | |
|     pInfo->m_fWrite = TRUE;
 | |
|     if (!pInfo->m_fRead) {
 | |
|         pInfo->m_fCantRead = TRUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID NoteDelete(PCSTR psz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(psz);
 | |
|     if (pInfo->m_fWrite || pInfo->m_fRead) {
 | |
|         pInfo->m_fCleanup = TRUE;
 | |
|     }
 | |
|     else {
 | |
|         pInfo->m_fDelete = TRUE;
 | |
|     }
 | |
|     if (!pInfo->m_fRead) {
 | |
|         pInfo->m_fCantRead = TRUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID NoteDelete(PCWSTR pwz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(pwz);
 | |
|     if (pInfo->m_fWrite || pInfo->m_fRead) {
 | |
|         pInfo->m_fCleanup = TRUE;
 | |
|     }
 | |
|     else {
 | |
|         pInfo->m_fDelete = TRUE;
 | |
|     }
 | |
|     if (!pInfo->m_fRead) {
 | |
|         pInfo->m_fCantRead = TRUE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| VOID NoteCleanup(PCSTR psz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(psz);
 | |
|     pInfo->m_fCleanup = TRUE;
 | |
| }
 | |
| 
 | |
| VOID NoteCleanup(PCWSTR pwz)
 | |
| {
 | |
|     FileInfo *pInfo = FileNames::FindPartial(pwz);
 | |
|     pInfo->m_fCleanup = TRUE;
 | |
| }
 | |
| 
 | |
| ////////////////////////////////////////////////////////////// Logging System.
 | |
| //
 | |
| static BOOL s_bLog = 1;
 | |
| static LONG s_nTlsIndent = -1;
 | |
| static LONG s_nTlsThread = -1;
 | |
| static LONG s_nThreadCnt = 0;
 | |
| 
 | |
| LONG EnterFunc()
 | |
| {
 | |
|     DWORD dwErr = GetLastError();
 | |
| 
 | |
|     LONG nIndent = 0;
 | |
|     LONG nThread = 0;
 | |
|     if (s_nTlsIndent >= 0) {
 | |
|         nIndent = (LONG)(LONG_PTR)TlsGetValue(s_nTlsIndent);
 | |
|         TlsSetValue(s_nTlsIndent, (PVOID)(LONG_PTR)(nIndent + 1));
 | |
|     }
 | |
|     if (s_nTlsThread >= 0) {
 | |
|         nThread = (LONG)(LONG_PTR)TlsGetValue(s_nTlsThread);
 | |
|     }
 | |
| 
 | |
|     SetLastError(dwErr);
 | |
| 
 | |
|     return nIndent;
 | |
| }
 | |
| 
 | |
| VOID ExitFunc()
 | |
| {
 | |
|     DWORD dwErr = GetLastError();
 | |
| 
 | |
|     LONG nIndent = 0;
 | |
|     LONG nThread = 0;
 | |
|     if (s_nTlsIndent >= 0) {
 | |
|         nIndent = (LONG)(LONG_PTR)TlsGetValue(s_nTlsIndent) - 1;
 | |
|         ASSERT(nIndent >= 0);
 | |
|         TlsSetValue(s_nTlsIndent, (PVOID)(LONG_PTR)nIndent);
 | |
|     }
 | |
|     if (s_nTlsThread >= 0) {
 | |
|         nThread = (LONG)(LONG_PTR)TlsGetValue(s_nTlsThread);
 | |
|     }
 | |
| 
 | |
|     SetLastError(dwErr);
 | |
| }
 | |
| 
 | |
| VOID Print(const CHAR *psz, ...)
 | |
| {
 | |
|     DWORD dwErr = GetLastError();
 | |
| 
 | |
|     if (s_bLog && psz) {
 | |
|         va_list  args;
 | |
|         va_start(args, psz);
 | |
| 
 | |
|         TblogV(psz, args);
 | |
| 
 | |
|         va_end(args);
 | |
|     }
 | |
| 
 | |
|     SetLastError(dwErr);
 | |
| }
 | |
| 
 | |
| VOID AssertFailed(CONST PCHAR pszMsg, CONST PCHAR pszFile, ULONG nLine)
 | |
| {
 | |
|     Tblog("ASSERT(%hs) failed in %s, line %d.\n", pszMsg, pszFile, nLine);
 | |
| }
 | |
| 
 | |
| //////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| // DLL module information
 | |
| //
 | |
| BOOL ThreadAttach(HMODULE hDll)
 | |
| {
 | |
|     (void)hDll;
 | |
| 
 | |
|     if (s_nTlsIndent >= 0) {
 | |
|         TlsSetValue(s_nTlsIndent, (PVOID)0);
 | |
|     }
 | |
|     if (s_nTlsThread >= 0) {
 | |
|         LONG nThread = InterlockedIncrement(&s_nThreadCnt);
 | |
|         TlsSetValue(s_nTlsThread, (PVOID)(LONG_PTR)nThread);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| BOOL ThreadDetach(HMODULE hDll)
 | |
| {
 | |
|     (void)hDll;
 | |
| 
 | |
|     if (s_nTlsIndent >= 0) {
 | |
|         TlsSetValue(s_nTlsIndent, (PVOID)0);
 | |
|     }
 | |
|     if (s_nTlsThread >= 0) {
 | |
|         TlsSetValue(s_nTlsThread, (PVOID)0);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| BOOL ProcessAttach(HMODULE hDll)
 | |
| {
 | |
|     InitializeCriticalSection(&s_csPipe);
 | |
|     InitializeCriticalSection(&s_csChildPayload);
 | |
| 
 | |
|     Procs::Initialize();
 | |
|     EnvVars::Initialize();
 | |
|     FileNames::Initialize();
 | |
|     OpenFiles::Initialize();
 | |
| 
 | |
|     s_bLog = FALSE;
 | |
|     s_nTlsIndent = TlsAlloc();
 | |
|     s_nTlsThread = TlsAlloc();
 | |
| 
 | |
|     s_hInst = hDll;
 | |
|     s_hKernel32 = NULL;
 | |
| 
 | |
|     PBYTE xCreate = (PBYTE)DetourCodeFromPointer((PVOID)Real_CreateProcessW, NULL);
 | |
|     PTBLOG_PAYLOAD pPayload = NULL;
 | |
| 
 | |
|     for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
 | |
|         ULONG cbData;
 | |
|         PVOID pvData = DetourFindPayload(hMod, s_guidTrace, &cbData);
 | |
| 
 | |
|         if (pvData != NULL && pPayload == NULL) {
 | |
|             pPayload = (PTBLOG_PAYLOAD)pvData;
 | |
|         }
 | |
| 
 | |
|         ULONG cbMod = DetourGetModuleSize(hMod);
 | |
| 
 | |
|         if (((PBYTE)hMod) < xCreate && ((PBYTE)hMod + cbMod) > xCreate) {
 | |
|             s_hKernel32 = hMod;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ZeroMemory(&s_Payload, sizeof(s_Payload));
 | |
| 
 | |
|     if (pPayload == NULL) {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     CopyMemory(&s_Payload, pPayload, sizeof(s_Payload));
 | |
| 
 | |
|     LoadStdHandleName(STD_INPUT_HANDLE, s_Payload.wzStdin, FALSE);
 | |
|     LoadStdHandleName(STD_OUTPUT_HANDLE, s_Payload.wzStdout, s_Payload.fStdoutAppend);
 | |
|     LoadStdHandleName(STD_ERROR_HANDLE, s_Payload.wzStderr, s_Payload.fStderrAppend);
 | |
|     s_nTraceProcessId = s_Payload.nTraceProcessId;
 | |
| 
 | |
|     GetModuleFileNameA(s_hInst, s_szDllPath, ARRAYSIZE(s_szDllPath));
 | |
| 
 | |
|     // Find hidden functions.
 | |
|     Real_PrivCopyFileExW =
 | |
|         (BOOL (WINAPI *)(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD))
 | |
|         GetProcAddress(s_hKernel32, "PrivCopyFileExW");
 | |
|     if (Real_PrivCopyFileExW == NULL) {
 | |
|         DEBUG_BREAK();
 | |
|     }
 | |
| 
 | |
|     LONG error = AttachDetours();
 | |
|     if (error != NO_ERROR) {
 | |
|         DEBUG_BREAK();
 | |
|         Tblog("<!-- Error attaching detours: %d -->\n", error);
 | |
|     }
 | |
| 
 | |
|     ThreadAttach(hDll);
 | |
| 
 | |
|     s_bLog = TRUE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| BOOL ProcessDetach(HMODULE hDll)
 | |
| {
 | |
|     ThreadDetach(hDll);
 | |
|     s_bLog = FALSE;
 | |
| 
 | |
|     LONG error = DetachDetours();
 | |
|     if (error != NO_ERROR) {
 | |
|         Tblog("<!-- Error detaching detours: %d -->\n", error);
 | |
|     }
 | |
| 
 | |
|     TblogClose();
 | |
| 
 | |
|     if (s_nTlsIndent >= 0) {
 | |
|         TlsFree(s_nTlsIndent);
 | |
|     }
 | |
|     if (s_nTlsThread >= 0) {
 | |
|         TlsFree(s_nTlsThread);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| inline VOID UpdateIfRoom(PWCHAR& pwzDst, PWCHAR pwzDstEnd, WCHAR c)
 | |
| {
 | |
|     if (pwzDst < pwzDstEnd) {
 | |
|         *pwzDst++ = c;  // Write character if room in buffer.
 | |
|     }
 | |
|     else {
 | |
|         pwzDst++;       // If no room, just advance pointer (to alloc calculation)
 | |
|     }
 | |
| }
 | |
| 
 | |
| static PCHAR RemoveReturns(PCHAR pszBuffer)
 | |
| {
 | |
|     PCHAR pszIn = pszBuffer;
 | |
|     PCHAR pszOut = pszBuffer;
 | |
| 
 | |
|     while (*pszIn) {
 | |
|         if (*pszIn == '\r') {
 | |
|             pszIn++;
 | |
|             continue;
 | |
|         }
 | |
|         *pszOut++ = *pszIn++;
 | |
|     }
 | |
|     *pszOut = '\0';
 | |
| 
 | |
|     return pszBuffer;
 | |
| }
 | |
| 
 | |
| static PWCHAR RemoveReturns(PWCHAR pwzBuffer)
 | |
| {
 | |
|     PWCHAR pwzIn = pwzBuffer;
 | |
|     PWCHAR pwzOut = pwzBuffer;
 | |
| 
 | |
|     while (*pwzIn) {
 | |
|         if (*pwzIn == '\r') {
 | |
|             pwzIn++;
 | |
|             continue;
 | |
|         }
 | |
|         *pwzOut++ = *pwzIn++;
 | |
|     }
 | |
|     *pwzOut = '\0';
 | |
| 
 | |
|     return pwzBuffer;
 | |
| }
 | |
| 
 | |
| PBYTE LoadFile(HANDLE hFile, DWORD cbFile)
 | |
| {
 | |
|     PBYTE pbFile = (PBYTE)GlobalAlloc(GPTR, cbFile + 3);
 | |
|     if (pbFile == NULL) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     DWORD cbRead = 0;
 | |
|     Real_SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
 | |
|     Real_ReadFile(hFile, pbFile, cbFile, &cbRead, NULL);
 | |
| 
 | |
|     // Make sure the file is zero terminated.
 | |
|     pbFile[cbRead + 0] = 0;
 | |
|     pbFile[cbRead + 1] = 0;
 | |
|     pbFile[cbRead + 2] = 0;
 | |
| 
 | |
|     return pbFile;
 | |
| }
 | |
| 
 | |
| PWCHAR More(PCWSTR pwzPath, PWCHAR pwzDst, PWCHAR pwzDstEnd)
 | |
| {
 | |
|     HANDLE hFile = Real_CreateFileW(pwzPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
 | |
|     if (hFile == INVALID_HANDLE_VALUE) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     FileInfo *pInfo = FileNames::FindPartial(pwzPath);
 | |
|     pInfo->m_fAbsorbed = true;
 | |
| 
 | |
|     DWORD cbFile = Real_SetFilePointer(hFile, 0, NULL, FILE_END);
 | |
|     DWORD cbRead = 0;
 | |
| 
 | |
|     PCHAR pszFile = (PCHAR)GlobalAlloc(GPTR, cbFile + 2);   // 2 bytes null for Unicode or Ascii.
 | |
|     if (pszFile != NULL) {
 | |
|         Real_SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
 | |
|         Real_ReadFile(hFile, pszFile, cbFile, &cbRead, NULL);
 | |
| 
 | |
|         if (((PUCHAR)pszFile)[0] == 0xff && ((PUCHAR)pszFile)[1] == 0xfe) {
 | |
|             // Unicode
 | |
|             PWCHAR pwzFile = ((PWCHAR)pszFile) + 1;
 | |
|             PCWSTR pwzIn = pwzFile;
 | |
|             while (*pwzIn) {
 | |
|                 if (*pwzIn == ' ' || *pwzIn == '\t' || *pwzIn == '\r' || *pwzIn == '\n') {
 | |
|                     UpdateIfRoom(pwzDst, pwzDstEnd, ' ');
 | |
|                     while (*pwzIn == ' ' || *pwzIn == '\t' || *pwzIn == '\r' || *pwzIn == '\n') {
 | |
|                         pwzIn++;
 | |
|                     }
 | |
|                 }
 | |
|                 else {
 | |
|                     UpdateIfRoom(pwzDst, pwzDstEnd, *pwzIn++);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             PCSTR pszIn = pszFile;
 | |
|             while (*pszIn) {
 | |
|                 if (*pszIn == ' ' || *pszIn == '\t' || *pszIn == '\r' || *pszIn == '\n') {
 | |
|                     UpdateIfRoom(pwzDst, pwzDstEnd, ' ');
 | |
|                     while (*pszIn == ' ' || *pszIn == '\t' || *pszIn == '\r' || *pszIn == '\n') {
 | |
|                         pszIn++;
 | |
|                     }
 | |
|                 }
 | |
|                 else {
 | |
|                     UpdateIfRoom(pwzDst, pwzDstEnd, *pszIn++);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         GlobalFree(pszFile);
 | |
|     }
 | |
| 
 | |
|     Real_CloseHandle(hFile);
 | |
| 
 | |
|     return pwzDst;
 | |
| }
 | |
| 
 | |
| // This function is called twice.  On the first call, pwzDstEnd <= pwzDst and
 | |
| // no data is copied, but pwzDst is advanced so we can see how big of a
 | |
| // buffer is needed to hold the command line.
 | |
| //
 | |
| // On the second call, the command line is actually populated.
 | |
| PWCHAR LoadCommandLine(PCWSTR pwz, PWCHAR pwzDst, PWCHAR pwzDstEnd)
 | |
| {
 | |
|     while (*pwz) {
 | |
|         PCWSTR pwzArgBeg = NULL;
 | |
|         PCWSTR pwzArgEnd = NULL;
 | |
|         WCHAR cQuote = '\0';
 | |
|         BOOL fMore = false;
 | |
| 
 | |
|         if (*pwz == '@') {
 | |
|             fMore = true;
 | |
|             pwz++;
 | |
|         }
 | |
| 
 | |
|         if (*pwz == '\"' || *pwz == '\'') {
 | |
|             cQuote = *pwz++;
 | |
| 
 | |
|             pwzArgBeg = pwz;
 | |
|             while (*pwz != '\0' && *pwz != cQuote) {
 | |
|                 pwz++;
 | |
|             }
 | |
|             pwzArgEnd = pwz;
 | |
| 
 | |
|             if (*pwz == cQuote) {
 | |
|                 pwz++;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             pwzArgBeg = pwz;
 | |
|             while (*pwz != '\0' && *pwz != ' ' && *pwz != '\t' && *pwz != '\n' && *pwz != '\r') {
 | |
|                 pwz++;
 | |
|             }
 | |
|             pwzArgEnd = pwz;
 | |
|         }
 | |
| 
 | |
|         if (fMore) {
 | |
|             // More arguments!
 | |
|             WCHAR wzPath[MAX_PATH];
 | |
|             PWCHAR pwzPath = wzPath;
 | |
|             PCWSTR pwzTmp = pwzArgBeg + 1;
 | |
|             while (pwzTmp < pwzArgEnd && pwzPath < wzPath + ARRAYSIZE(wzPath)-2) {
 | |
|                 *pwzPath++ = *pwzTmp++;
 | |
|             }
 | |
|             *pwzPath = '\0';
 | |
| 
 | |
|             PWCHAR pwzOut = More(wzPath, pwzDst, pwzDstEnd);
 | |
|             if (pwzOut != NULL) {
 | |
|                 pwzDst = pwzOut;
 | |
| 
 | |
|                 cQuote = 0;
 | |
|                 pwzArgBeg = pwzArgEnd;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (cQuote) {
 | |
|             UpdateIfRoom(pwzDst, pwzDstEnd, cQuote);
 | |
|         }
 | |
|         for (; pwzArgBeg < pwzArgEnd; pwzArgBeg++) {
 | |
|             UpdateIfRoom(pwzDst, pwzDstEnd, *pwzArgBeg);
 | |
|         }
 | |
|         if (cQuote) {
 | |
|             UpdateIfRoom(pwzDst, pwzDstEnd, cQuote);
 | |
|         }
 | |
| 
 | |
|         if (*pwz) {
 | |
|             UpdateIfRoom(pwzDst, pwzDstEnd, ' ');
 | |
|         }
 | |
| 
 | |
|         // skip over separating spaces.
 | |
|         while (*pwz == ' ' || *pwz == '\t' || *pwz == '\n' || *pwz == '\r') {
 | |
|             pwz++;
 | |
|         }
 | |
|     }
 | |
|     return pwzDst;
 | |
| }
 | |
| 
 | |
| void TestHandle(PCSTR pszName, HANDLE h)
 | |
| {
 | |
|     FileInfo *pInfo = OpenFiles::RecallFile(h);
 | |
| 
 | |
|     if (pInfo != NULL) {
 | |
| #if 1 // Ignore PIPEs.
 | |
|         if (FileNames::PrefixMatch(pInfo->m_pwzPath, L"\\\\.\\PIPE\\")) {
 | |
|             // Ignore;
 | |
|         }
 | |
|         else
 | |
| #endif
 | |
|             if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conout$")) {
 | |
|             // Ignore;
 | |
|         }
 | |
|         else if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\conin$")) {
 | |
|             // Ignore;
 | |
|         }
 | |
|         else if (FileNames::SuffixMatch(pInfo->m_pwzPath, L"\\nul")) {
 | |
|             // Ignore;
 | |
|         }
 | |
|         else {
 | |
|             Tblog("<%hs%hs>%le</%hs>\n",
 | |
|                   pszName, pInfo->m_fAppend ? " append=\"true\"" : "", pInfo->m_pwzPath, pszName);
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         Tblog("<!-- hand: %hs (%x) ***Unknown*** -->\n", pszName, h);
 | |
|     }
 | |
| }
 | |
| 
 | |
| LONG WINAPI DetourAttachIf(PVOID *ppPointer, PVOID pDetour)
 | |
| {
 | |
|     if (*ppPointer == NULL) {
 | |
|         Tblog("<!-- DetourAttachIf failed: %p -->\n", pDetour);
 | |
|         return NO_ERROR;
 | |
|     }
 | |
| 
 | |
|     PDETOUR_TRAMPOLINE pRealTrampoline;
 | |
|     PVOID pRealTarget;
 | |
|     PVOID pRealDetour;
 | |
| 
 | |
|     LONG err = DetourAttachEx(ppPointer, pDetour, &pRealTrampoline, &pRealTarget, &pRealDetour);
 | |
|     if (err == NO_ERROR) {
 | |
|         // Tblog("<!-- DetourAttachIf %p at %p -->\n", pDetour, pRealTarget);
 | |
|         return NO_ERROR;
 | |
|     }
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| int WINAPI Mine_EntryPoint(VOID)
 | |
| {
 | |
|     // This function is invoked instead of the process EntryPoint (Real_EntryPoint).
 | |
| 
 | |
|     TblogOpen();
 | |
| 
 | |
|     SaveEnvironment();
 | |
| 
 | |
|     {
 | |
|         CHAR szExeName[MAX_PATH];
 | |
|         CHAR szId[128];
 | |
|         CHAR szParent[128];
 | |
|         WCHAR wzPath[MAX_PATH];
 | |
|         PCHAR pszExeName = szExeName;
 | |
| 
 | |
|         // Get the base command line (skipping over the executable name)
 | |
|         PCWSTR pwzLine = GetCommandLineW();
 | |
|         if (*pwzLine == '\"') {
 | |
|             pwzLine++;
 | |
|             while (*pwzLine && *pwzLine != '\"') {
 | |
|                 pwzLine++;
 | |
|             }
 | |
|             if (*pwzLine == '\"') {
 | |
|                 pwzLine++;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             while (*pwzLine && *pwzLine != ' ' && *pwzLine != '\t') {
 | |
|                 pwzLine++;
 | |
|             }
 | |
|         }
 | |
|         while (*pwzLine && (*pwzLine == ' ' || *pwzLine == '\t')) {
 | |
|             pwzLine++;
 | |
|         }
 | |
| 
 | |
|         // Get the root executable name.
 | |
|         if (GetModuleFileNameA(0, szExeName, ARRAYSIZE(szExeName))) {
 | |
|             PCHAR psz = szExeName;
 | |
| 
 | |
|             while (*psz) {
 | |
|                 psz++;
 | |
|             }
 | |
| 
 | |
|             while (psz > szExeName && psz[-1] != ':' && psz[-1] != '\\' && psz[-1] != '/') {
 | |
|                 psz--;
 | |
|             }
 | |
|             pszExeName = psz;
 | |
|             while (*psz && *psz != '.') {
 | |
|                 psz++;
 | |
|             }
 | |
|             *psz = '\0';
 | |
|         }
 | |
|         else {
 | |
|             szExeName[0] = '\0';
 | |
|         }
 | |
| 
 | |
|         // Start the XML process node.
 | |
|         Tblog("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 | |
|         {
 | |
|             PCHAR pszId = szId;
 | |
|             PCHAR pszParent = szParent;
 | |
|             for (DWORD i = 0; i < s_Payload.nGeneology; i++) {
 | |
|                 pszId = SafePrintf(pszId, 16, "%d.", s_Payload.rGeneology[i]);
 | |
|                 if (i < s_Payload.nGeneology - 1) {
 | |
|                     pszParent = SafePrintf(pszParent, 16, "%d.", s_Payload.rGeneology[i]);
 | |
|                 }
 | |
|             }
 | |
|             *pszId = '\0';
 | |
|             *pszParent = '\0';
 | |
| 
 | |
|             if (szParent[0] == '\0') {
 | |
|                 Tblog("<t:Process id=\"::%hs::\"", szId);
 | |
|             }
 | |
|             else {
 | |
|                 Tblog("<t:Process id=\"::%hs::\" parentId=\"::%hs::\"", szId, szParent);
 | |
|             }
 | |
| 
 | |
|             Tblog(" par=\"%ls\" exe=\"%hs\"", s_Payload.wzParents, pszExeName);
 | |
| 
 | |
|             BOOL drop = false;
 | |
|             PCWSTR pwzz = s_Payload.wzzDrop;
 | |
|             while (*pwzz) {
 | |
|                 if (Compare(pwzz, pszExeName) == 0) {
 | |
|                     // match
 | |
|                     drop = true;
 | |
|                     break;
 | |
|                 }
 | |
|                 pwzz += Size(pwzz) + 1;
 | |
|             }
 | |
|             if (drop) {
 | |
|                 Tblog(" drop=\"true\"");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         {
 | |
|             PWCHAR pwz = s_Payload.wzParents;
 | |
|             while (*pwz) {
 | |
|                 pwz++;
 | |
|             }
 | |
|             *pwz++ = '/';
 | |
|             PCSTR psz = pszExeName;
 | |
|             while (*psz) {
 | |
|                 *pwz++ = *psz++;
 | |
|             }
 | |
|             *pwz = '\0';
 | |
|         }
 | |
| 
 | |
| 
 | |
|         if (HasChar(pwzLine, '|')) {
 | |
|             Tblog(" pipes=\"true\"");
 | |
|         }
 | |
|         if (HasChar(pwzLine, '>')) {
 | |
|             Tblog(" redirects=\"true\"");
 | |
|         }
 | |
| 
 | |
|         Tblog(" xmlns:t=\"http://schemas.microsoft.com/research/tracebld/2008\">\n");
 | |
| 
 | |
|         // Get the directory.
 | |
|         DWORD dwSize = GetCurrentDirectoryA(ARRAYSIZE(szExeName), szExeName);
 | |
|         if (dwSize > 0 && dwSize < ARRAYSIZE(szExeName)) {
 | |
|             Tblog("<t:Directory>%hs</t:Directory>\n", szExeName);
 | |
|         }
 | |
| 
 | |
|         // Get the real executable name.
 | |
|         wzPath[0] = '\0';
 | |
|         if (GetModuleFileNameA(0, szExeName, ARRAYSIZE(szExeName))) {
 | |
|             FileInfo *pInfo = FileNames::FindPartial(szExeName);
 | |
|             Tblog("<t:Executable>%ls</t:Executable>\n",
 | |
|                   FileNames::ParameterizeName(wzPath, ARRAYSIZE(wzPath), pInfo));
 | |
|         }
 | |
| 
 | |
|         // Construct the processed command line.
 | |
|         PWCHAR pwzDstEnd = (PWCHAR)pwzLine;
 | |
|         PWCHAR pwzDst = pwzDstEnd;
 | |
|         pwzDst = LoadCommandLine(pwzLine, pwzDst, pwzDstEnd);
 | |
|         DWORD wcNew = (DWORD)((pwzDst - pwzDstEnd) + 1);
 | |
|         PWCHAR pwzFin = (PWCHAR)GlobalAlloc(GPTR, wcNew * sizeof(WCHAR));
 | |
|         pwzDst = pwzFin;
 | |
|         pwzDstEnd = pwzFin + wcNew;
 | |
|         pwzDst = LoadCommandLine(pwzLine, pwzDst, pwzDstEnd);
 | |
|         *pwzDst = '\0';
 | |
| 
 | |
|         FileNames::ParameterizeLine(pwzFin, pwzFin + wcNew);
 | |
|         if (HasSpace(wzPath)) {
 | |
|             Tblog("<t:Line>"%le" %le</t:Line>\n", wzPath, pwzFin);
 | |
|         }
 | |
|         else {
 | |
|             Tblog("<t:Line>%le %le</t:Line>\n", wzPath, pwzFin);
 | |
|         }
 | |
| 
 | |
|         TestHandle("t:StdIn", GetStdHandle(STD_INPUT_HANDLE));
 | |
|         TestHandle("t:StdOut", GetStdHandle(STD_OUTPUT_HANDLE));
 | |
|         TestHandle("t:StdErr", GetStdHandle(STD_ERROR_HANDLE));
 | |
|     }
 | |
| 
 | |
|     if (FindMsvcr()) {
 | |
|         FindProc(&(PVOID&)Real_getenv, "getenv");
 | |
|         FindProc(&(PVOID&)Real_wgetenv, "_wgetenv");
 | |
|         FindProc(&(PVOID&)Real_getenv_s, "getenv_s");
 | |
|         FindProc(&(PVOID&)Real_wgetenv_s, "_wgetenv_s");
 | |
|         FindProc(&(PVOID&)Real_dupenv_s, "_dupenv_s");
 | |
|         FindProc(&(PVOID&)Real_wdupenv_s, "_wdupenv_s");
 | |
| 
 | |
|         DetourTransactionBegin();
 | |
|         DetourUpdateThread(GetCurrentThread());
 | |
| 
 | |
|         DetourAttachIf(&(PVOID&)Real_getenv, Mine_getenv);
 | |
|         DetourAttachIf(&(PVOID&)Real_getenv_s, Mine_getenv_s);
 | |
|         DetourAttachIf(&(PVOID&)Real_wgetenv, Mine_wgetenv);
 | |
|         DetourAttachIf(&(PVOID&)Real_wgetenv, Mine_wgetenv_s);
 | |
|         DetourAttachIf(&(PVOID&)Real_dupenv_s, Mine_dupenv_s);
 | |
|         DetourAttachIf(&(PVOID&)Real_wdupenv_s, Mine_wdupenv_s);
 | |
| 
 | |
|         DetourTransactionCommit();
 | |
|     }
 | |
| 
 | |
|     return Real_EntryPoint();
 | |
| }
 | |
| 
 | |
| VOID WINAPI Mine_ExitProcess(UINT a0)
 | |
| {
 | |
|     if (a0 & 0x80000000) {
 | |
|         Tblog("<t:Return>%d</t:Return>\n", -(int)a0);
 | |
|     }
 | |
|     else {
 | |
|         Tblog("<t:Return>%d</t:Return>\n", a0);
 | |
|     }
 | |
| 
 | |
|     FileNames::Dump();
 | |
|     EnvVars::Dump();
 | |
| 
 | |
|     TblogClose();
 | |
| 
 | |
|     Real_ExitProcess(a0);
 | |
| }
 | |
| 
 | |
| BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved)
 | |
| {
 | |
|     (void)hModule;
 | |
|     (void)lpReserved;
 | |
| 
 | |
|     if (DetourIsHelperProcess()) {
 | |
|         return TRUE;
 | |
|     }
 | |
| 
 | |
|     if (dwReason == DLL_PROCESS_ATTACH) {
 | |
|         DetourRestoreAfterWith();
 | |
|         Real_EntryPoint = (int (WINAPI *)(VOID))DetourGetEntryPoint(NULL);
 | |
|         return ProcessAttach(hModule);
 | |
|     }
 | |
|     else if (dwReason == DLL_PROCESS_DETACH) {
 | |
|         return ProcessDetach(hModule);
 | |
|     }
 | |
|     else if (dwReason == DLL_THREAD_ATTACH) {
 | |
|         return ThreadAttach(hModule);
 | |
|     }
 | |
|     else if (dwReason == DLL_THREAD_DETACH) {
 | |
|         return ThreadDetach(hModule);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| //
 | |
| ///////////////////////////////////////////////////////////////// End of File.
 |