diff options
Diffstat (limited to 'private/sdktools/instaler')
41 files changed, 13257 insertions, 0 deletions
diff --git a/private/sdktools/instaler/compinst.c b/private/sdktools/instaler/compinst.c new file mode 100644 index 000000000..9c6df1338 --- /dev/null +++ b/private/sdktools/instaler/compinst.c @@ -0,0 +1,899 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + showinst.c + +Abstract: + + This program compares the actions described by two Installation Modification Log file + created by the INSTALER program + +Author: + + Steve Wood (stevewo) 15-Jan-1996 + +Revision History: + +--*/ + +#include "instutil.h" +#include "iml.h" + +BOOLEAN VerboseOutput; + +BOOLEAN +CompareIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2 + ); + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + char *s; + PWSTR ImlPathAlt = NULL; + PINSTALLATION_MODIFICATION_LOGFILE pIml1 = NULL; + PINSTALLATION_MODIFICATION_LOGFILE pIml2 = NULL; + + InitCommonCode( "COMPINST", + "InstallationName2 [-v]", + "-v verbose output\n" + ); + VerboseOutput = FALSE; + while (--argc) { + s = *++argv; + if (*s == '-' || *s == '/') { + while (*++s) { + switch( tolower( *s ) ) { + case 'v': + VerboseOutput = TRUE; + break; + default: + CommonSwitchProcessing( &argc, &argv, *s ); + break; + } + } + } + else + if (!CommonArgProcessing( &argc, &argv )) { + if (ImlPathAlt != NULL) { + Usage( "Too many installation names specified - '%s'", (ULONG)s ); + } + + ImlPathAlt = FormatImlPath( InstalerDirectory, GetArgAsUnicode( s ) ); + } + } + + if (ImlPath == NULL || ImlPathAlt == NULL) { + Usage( "Must specify two installation names to compare", 0 ); + } + + if (!SetCurrentDirectory( InstalerDirectory )) { + FatalError( "Unable to change to '%ws' directory (%u)", + (ULONG)InstalerDirectory, + GetLastError() + ); + } + + pIml1 = LoadIml( ImlPath ); + if (pIml1 == NULL) { + FatalError( "Unable to load '%ws' (%u)", + (ULONG)ImlPath, + GetLastError() + ); + } + + pIml2 = LoadIml( ImlPathAlt ); + if (pIml2 == NULL) { + FatalError( "Unable to load '%ws' (%u)", + (ULONG)ImlPathAlt, + GetLastError() + ); + } + + printf( "Displaying differences between:\n" ); + printf( " Installation 1: %ws\n", ImlPath ); + printf( " Installation 2: %ws\n", ImlPathAlt ); + exit( CompareIml( pIml1, pIml2 ) == FALSE ); + return 0; +} + +typedef struct _IML_GENERIC_RECORD { + POFFSET Next; // IML_GENERIC_RECORD + ULONG Action; + POFFSET Name; // WCHAR + POFFSET Records; // IML_GENERIC_RECORD +} IML_GENERIC_RECORD, *PIML_GENERIC_RECORD; + + +typedef +VOID +(*PIML_PRINT_RECORD_ROUTINE)( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PIML_GENERIC_RECORD pGeneric, + PWSTR Parents[], + ULONG Depth, + ULONG i + ); + +typedef +BOOLEAN +(*PIML_COMPARE_CONTENTS_ROUTINE)( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PIML_GENERIC_RECORD pGeneric1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2, + PIML_GENERIC_RECORD pGeneric2, + PWSTR Parents[] + ); + + +PINSTALLATION_MODIFICATION_LOGFILE pSortIml; + +int +_CRTAPI1 +CompareGeneric( + const void *Reference1, + const void *Reference2 + ) +{ + PIML_GENERIC_RECORD p1 = *(PIML_GENERIC_RECORD *)Reference1; + PIML_GENERIC_RECORD p2 = *(PIML_GENERIC_RECORD *)Reference2; + + if (p1->Name == 0) { + if (p2->Name == 0) { + return 0; + } + else { + return -1; + } + } + else + if (p2->Name == 0) { + return 1; + } + + return _wcsicmp( MP( PWSTR, pSortIml, p1->Name ), + MP( PWSTR, pSortIml, p2->Name ) + ); +} + + +PIML_GENERIC_RECORD * +GetSortedGenericListAsArray( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PIML_GENERIC_RECORD pGeneric + ) +{ + PIML_GENERIC_RECORD p, *pp; + ULONG n; + + p = pGeneric; + n = 1; + while (p != NULL) { + n += 1; + p = MP( PIML_GENERIC_RECORD, pIml, p->Next ); + } + + pp = HeapAlloc( GetProcessHeap(), 0, n * sizeof( *pp ) ); + p = pGeneric; + n = 0; + while (p != NULL) { + pp[ n++ ] = p; + p = MP( PIML_GENERIC_RECORD, pIml, p->Next ); + } + pp[ n ] = NULL; + + pSortIml = pIml; + qsort( (void *)pp, n, sizeof( *pp ), CompareGeneric ); + pSortIml = NULL; + return pp; +} + +BOOLEAN +CompareGenericIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PIML_GENERIC_RECORD pGeneric1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2, + PIML_GENERIC_RECORD pGeneric2, + PWSTR Parents[], + ULONG Depth, + PIML_PRINT_RECORD_ROUTINE PrintRecordRoutine, + PIML_COMPARE_CONTENTS_ROUTINE CompareContentsRoutine + ) +{ + PVOID pBufferToFree1; + PVOID pBufferToFree2; + PIML_GENERIC_RECORD *ppGeneric1; + PIML_GENERIC_RECORD *ppGeneric2; + PIML_GENERIC_RECORD pShow1; + PIML_GENERIC_RECORD pShow2; + BOOLEAN Result = FALSE; + PWSTR s1, s2; + int cmpResult; + + ppGeneric1 = GetSortedGenericListAsArray( pIml1, pGeneric1 ); + if (ppGeneric1 == NULL) { + return FALSE; + } + pBufferToFree1 = ppGeneric1; + + ppGeneric2 = GetSortedGenericListAsArray( pIml2, pGeneric2 ); + if (ppGeneric2 == NULL) { + HeapFree( GetProcessHeap(), 0, pBufferToFree1 ); + return FALSE; + } + pBufferToFree2 = ppGeneric2; + + pGeneric1 = *ppGeneric1++; + pGeneric2 = *ppGeneric2++; + + while (TRUE) { + pShow1 = NULL; + pShow2 = NULL; + if (pGeneric1 == NULL) { + if (pGeneric2 == NULL) { + break; + } + + // + // pGeneric2 is new + // + + pShow2 = pGeneric2; + pGeneric2 = *ppGeneric2++; + Result = FALSE; + } + else + if (pGeneric2 == NULL) { + // + // pGeneric1 is new + // + pShow1 = pGeneric1; + pGeneric1 = *ppGeneric1++; + Result = FALSE; + } + else { + s1 = MP( PWSTR, pIml1, pGeneric1->Name ); + s2 = MP( PWSTR, pIml2, pGeneric2->Name ); + + if (s1 == NULL) { + if (s2 == NULL) { + cmpResult = 0; + } + else { + cmpResult = -1; + } + } + else + if (s2 == NULL) { + cmpResult = 1; + } + else { + cmpResult = _wcsicmp( s1, s2 ); + } + if (cmpResult == 0) { + if (Depth > 1) { + Parents[ Depth - 1 ] = MP( PWSTR, pIml1, pGeneric1->Name ); + Result = CompareGenericIml( pIml1, + MP( PIML_GENERIC_RECORD, pIml1, pGeneric1->Records ), + pIml2, + MP( PIML_GENERIC_RECORD, pIml2, pGeneric2->Records ), + Parents, + Depth - 1, + PrintRecordRoutine, + CompareContentsRoutine + ); + } + else { + Result = (*CompareContentsRoutine)( pIml1, pGeneric1, + pIml2, pGeneric2, + Parents + ); + } + + pGeneric1 = *ppGeneric1++; + pGeneric2 = *ppGeneric2++; + } + else + if (cmpResult > 0) { + pShow2 = pGeneric2; + pGeneric2 = *ppGeneric2++; + } + else { + pShow1 = pGeneric1; + pGeneric1 = *ppGeneric1++; + } + } + + if (pShow1) { + (*PrintRecordRoutine)( pIml1, pShow1, Parents, Depth, 1 ); + } + + if (pShow2) { + (*PrintRecordRoutine)( pIml2, pShow2, Parents, Depth, 2 ); + } + } + + HeapFree( GetProcessHeap(), 0, pBufferToFree1 ); + HeapFree( GetProcessHeap(), 0, pBufferToFree2 ); + return Result; +} + + +char *FileActionStrings[] = { + "CreateNewFile", + "ModifyOldFile", + "DeleteOldFile", + "RenameOldFile", + "ModifyFileDateTime", + "ModifyFileAttributes" +}; + + +PWSTR +FormatFileTime( + LPFILETIME LastWriteTime + ) +{ + FILETIME LocalFileTime; + SYSTEMTIME DateTime; + static WCHAR DateTimeBuffer[ 128 ]; + + FileTimeToLocalFileTime( LastWriteTime, &LocalFileTime ); + FileTimeToSystemTime( &LocalFileTime, &DateTime ); + + _snwprintf( DateTimeBuffer, + 128, + L"%02u/%02u/%04u %02u:%02u:%02u", + (ULONG)DateTime.wMonth, + (ULONG)DateTime.wDay, + (ULONG)DateTime.wYear, + (ULONG)DateTime.wHour, + (ULONG)DateTime.wMinute, + (ULONG)DateTime.wSecond + ); + + return DateTimeBuffer; +} + + +VOID +PrintFileRecordIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PIML_GENERIC_RECORD pGeneric, + PWSTR Parents[], + ULONG Depth, + ULONG i + ) +{ + PIML_FILE_RECORD pFile = (PIML_FILE_RECORD)pGeneric; + + printf( "File: %ws\n %u: %s\n", + MP( PWSTR, pIml, pFile->Name ), + i, FileActionStrings[ pFile->Action ] + ); +} + +BOOLEAN +CompareFileContentsIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PIML_GENERIC_RECORD pGeneric1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2, + PIML_GENERIC_RECORD pGeneric2, + PWSTR Parents[] + ) +{ + PIML_FILE_RECORD pFile1 = (PIML_FILE_RECORD)pGeneric1; + PIML_FILE_RECORD pFile2 = (PIML_FILE_RECORD)pGeneric2; + PIML_FILE_RECORD_CONTENTS pFileContents1; + PIML_FILE_RECORD_CONTENTS pFileContents2; + BOOLEAN ActionsDiffer = FALSE; + BOOLEAN DatesDiffer = FALSE; + BOOLEAN AttributesDiffer = FALSE; + BOOLEAN SizesDiffer = FALSE; + BOOLEAN ContentsDiffer = FALSE; + BOOLEAN Result = TRUE; + PCHAR s1, s2; + ULONG n; + + pFileContents1 = MP( PIML_FILE_RECORD_CONTENTS, pIml1, pFile1->NewFile ); + pFileContents2 = MP( PIML_FILE_RECORD_CONTENTS, pIml2, pFile2->NewFile ); + + if (pFile1->Action != pFile2->Action) { + ActionsDiffer = TRUE; + Result = FALSE; + } + else + if (pFileContents1 != NULL && pFileContents2 != NULL) { + if (pFile1->Action != CreateNewFile && + ((pFileContents1->LastWriteTime.dwHighDateTime != + pFileContents2->LastWriteTime.dwHighDateTime + ) || + (pFileContents1->LastWriteTime.dwLowDateTime != + pFileContents2->LastWriteTime.dwLowDateTime + ) + ) + ) { + DatesDiffer = TRUE; + Result = FALSE; + } + + if (pFileContents1->FileAttributes != pFileContents2->FileAttributes) { + AttributesDiffer = TRUE; + Result = FALSE; + } + + if (pFileContents1->FileSize != pFileContents2->FileSize) { + SizesDiffer = TRUE; + Result = FALSE; + } + else + if (pFileContents1->Contents == 0 || + pFileContents2->Contents == 0 || + memcmp( MP( PVOID, pIml1, pFileContents1->Contents ), + MP( PVOID, pIml2, pFileContents2->Contents ), + pFileContents1->FileSize + ) != 0 + ) { + s1 = MP( PVOID, pIml1, pFileContents1->Contents ); + s2 = MP( PVOID, pIml2, pFileContents2->Contents ); + if (s1 == NULL || s2 == NULL) { + n = 0; + } + else { + n = pFileContents1->FileSize; + } + while (n) { + if (*s1 != *s2) { + n = pFileContents1->FileSize - n; + break; + } + + n -= 1; + s1 += 1; + s2 += 1; + } + + ContentsDiffer = TRUE; + Result = FALSE; + } + } + + if (!Result) { + printf( "File: %ws\n", MP( PWSTR, pIml1, pFile1->Name ) ); + if (ActionsDiffer) { + printf( " 1: Action - %s\n", FileActionStrings[ pFile1->Action ] ); + printf( " 2: Action - %s\n", FileActionStrings[ pFile2->Action ] ); + } + if (DatesDiffer) { + printf( " 1: LastWriteTime - %ws\n", + FormatFileTime( &pFileContents1->LastWriteTime ) + ); + printf( " 2: LastWriteTime - %ws\n", + FormatFileTime( &pFileContents2->LastWriteTime ) + ); + } + if (AttributesDiffer) { + printf( " 1: Attributes - 0x%08x\n", pFileContents1->FileAttributes ); + printf( " 2: Attributes - 0x%08x\n", pFileContents2->FileAttributes ); + } + if (SizesDiffer) { + printf( " 1: File Size - 0x%08x\n", pFileContents1->FileSize ); + printf( " 2: File Size - 0x%08x\n", pFileContents2->FileSize ); + } + if (ContentsDiffer) { + printf( " 1: Contents Differs\n" ); + printf( " 2: from each other at offset %08x\n", n ); + } + } + + return Result; +} + + +char *KeyActionStrings[] = { + "CreateNewKey", + "DeleteOldKey", + "ModifyKeyValues" +}; + +char *ValueActionStrings[] = { + "CreateNewValue", + "DeleteOldValue", + "ModifyOldValue" +}; + + +char *ValueTypeStrings[] = { + "REG_NONE", + "REG_SZ", + "REG_EXPAND_SZ", + "REG_BINARY", + "REG_DWORD", + "REG_DWORD_BIG_ENDIAN", + "REG_LINK", + "REG_MULTI_SZ", + "REG_RESOURCE_LIST", + "REG_FULL_RESOURCE_DESCRIPTOR", + "REG_RESOURCE_REQUIREMENTS_LIST" +}; + +VOID +PrintKeyValueRecordIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PIML_GENERIC_RECORD pGeneric, + PWSTR Parents[], + ULONG Depth, + ULONG i + ) +{ + PIML_KEY_RECORD pKey = (PIML_KEY_RECORD)pGeneric; + PIML_VALUE_RECORD pValue = (PIML_VALUE_RECORD)pGeneric; + + if (Depth == 2) { + printf( "Key: %ws\n %u: %s\n", + MP( PWSTR, pIml, pKey->Name ), + i, KeyActionStrings[ pKey->Action ] + ); + } + else { + if (Parents[ 1 ] != NULL) { + printf( "Key: %ws\n", Parents[ 1 ] ); + Parents[ 1 ] = NULL; + } + + printf( " Value: %ws\n %u: %s\n", + MP( PWSTR, pIml, pValue->Name ), + i, ValueActionStrings[ pValue->Action ] + ); + } +} + +UCHAR BlanksForPadding[] = + " "; + +VOID +PrintValueContents( + PCHAR PrefixString, + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PIML_VALUE_RECORD_CONTENTS pValueContents + ) +{ + ULONG ValueType; + ULONG ValueLength; + PVOID ValueData; + ULONG cbPrefix, cb, i, j; + PWSTR pw; + PULONG p; + + ValueType = pValueContents->Type; + ValueLength = pValueContents->Length; + ValueData = MP( PVOID, pIml, pValueContents->Data ); + + cbPrefix = printf( "%s", PrefixString ); + cb = cbPrefix + printf( "%s", ValueTypeStrings[ ValueType ] ); + + switch( ValueType ) { + case REG_SZ: + case REG_LINK: + case REG_EXPAND_SZ: + pw = (PWSTR)ValueData; + printf( " (%u) \"%.*ws\"\n", ValueLength, ValueLength/sizeof(WCHAR), pw ); + break; + + case REG_MULTI_SZ: + pw = (PWSTR)ValueData; + i = 0; + if (*pw) + while (i < (ValueLength - 1) / sizeof( WCHAR )) { + if (i > 0) { + printf( " \\\n%.*s", cbPrefix, BlanksForPadding ); + } + printf( "\"%ws\" ", pw+i ); + do { + ++i; + } + while (pw[i] != UNICODE_NULL); + + ++i; + } + printf( "\n" ); + break; + + case REG_DWORD: + case REG_DWORD_BIG_ENDIAN: + printf( " 0x%08x\n", *(PULONG)ValueData ); + break; + + case REG_RESOURCE_LIST: + case REG_FULL_RESOURCE_DESCRIPTOR: + case REG_RESOURCE_REQUIREMENTS_LIST: + case REG_BINARY: + case REG_NONE: + cb = printf( " [0x%08lx]", ValueLength ); + + if (ValueLength != 0) { + p = (PULONG)ValueData; + i = (ValueLength + 3) / sizeof( ULONG ); + for (j=0; j<i; j++) { + if ((cbPrefix + cb + 11) > 78) { + printf( " \\\n%.*s", cbPrefix, BlanksForPadding ); + cb = 0; + } + else { + cb += printf( " " ); + } + + cb += printf( "0x%08lx", *p++ ); + } + } + + printf( "\n" ); + break; + } +} + +BOOLEAN +CompareKeyValueContentsIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PIML_GENERIC_RECORD pGeneric1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2, + PIML_GENERIC_RECORD pGeneric2, + PWSTR Parents[] + ) +{ + PIML_VALUE_RECORD pValue1 = (PIML_VALUE_RECORD)pGeneric1; + PIML_VALUE_RECORD pValue2 = (PIML_VALUE_RECORD)pGeneric2; + PIML_VALUE_RECORD_CONTENTS pValueContents1; + PIML_VALUE_RECORD_CONTENTS pValueContents2; + BOOLEAN ActionsDiffer = FALSE; + BOOLEAN TypesDiffer = FALSE; + BOOLEAN LengthsDiffer = FALSE; + BOOLEAN ContentsDiffer = FALSE; + BOOLEAN Result = TRUE; + PCHAR s1, s2; + ULONG n; + + pValueContents1 = MP( PIML_VALUE_RECORD_CONTENTS, pIml1, pValue1->NewValue ); + pValueContents2 = MP( PIML_VALUE_RECORD_CONTENTS, pIml2, pValue2->NewValue ); + + if (pValue1->Action != pValue2->Action) { + ActionsDiffer = TRUE; + Result = FALSE; + } + else + if (pValueContents1 != NULL && pValueContents2 != NULL) { + if (pValue1->Action != CreateNewValue && + (pValueContents1->Type != pValueContents2->Type) + ) { + TypesDiffer = TRUE; + Result = FALSE; + } + + if (pValueContents1->Length != pValueContents2->Length) { + LengthsDiffer = TRUE; + Result = FALSE; + } + else + if (pValueContents1->Data == 0 || + pValueContents2->Data == 0 || + memcmp( MP( PVOID, pIml1, pValueContents1->Data ), + MP( PVOID, pIml2, pValueContents2->Data ), + pValueContents1->Length + ) != 0 + ) { + s1 = MP( PVOID, pIml1, pValueContents1->Data ); + s2 = MP( PVOID, pIml2, pValueContents2->Data ); + if (s1 == NULL || s2 == NULL) { + n = 0; + } + else { + n = pValueContents1->Length; + } + while (n) { + if (*s1 != *s2) { + n = pValueContents1->Length - n; + break; + } + + n -= 1; + s1 += 1; + s2 += 1; + } + + ContentsDiffer = TRUE; + Result = FALSE; + } + } + + if (!Result) { + if (Parents[ 2 ] != NULL) { + printf( "Key: %ws\n", Parents[ 2 ] ); + Parents[ 2 ] = NULL; + } + + printf( " Value: %ws\n", MP( PWSTR, pIml1, pValue1->Name ) ); + if (ActionsDiffer) { + printf( " 1: Action - %s\n", ValueActionStrings[ pValue1->Action ] ); + printf( " 2: Action - %s\n", ValueActionStrings[ pValue2->Action ] ); + } + if (TypesDiffer || LengthsDiffer || ContentsDiffer ) { + PrintValueContents( " 1: ", pIml1, pValueContents1 ); + PrintValueContents( " 2: ", pIml2, pValueContents2 ); + } + } + + return Result; +} + + +char *IniActionStrings[] = { + "CreateNewIniFile", + "ModifyOldIniFile" +}; + +char *SectionActionStrings[] = { + "CreateNewSection", + "DeleteOldSection", + "ModifySectionVariables" +}; + +char *VariableActionStrings[] = { + "CreateNewVariable", + "DeleteOldVariable", + "ModifyOldVariable" +}; + +VOID +PrintIniSectionVariableRecordIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PIML_GENERIC_RECORD pGeneric, + PWSTR Parents[], + ULONG Depth, + ULONG i + ) +{ + PIML_INI_RECORD pIni = (PIML_INI_RECORD)pGeneric; + PIML_INISECTION_RECORD pSection = (PIML_INISECTION_RECORD)pGeneric; + PIML_INIVARIABLE_RECORD pVariable = (PIML_INIVARIABLE_RECORD)pGeneric; + + if (Depth == 3) { + printf( "Ini File: %ws\n %u: %s\n", + MP( PWSTR, pIml, pIni->Name ), + i, IniActionStrings[ pIni->Action ] + ); + } + else + if (Depth == 2) { + if (Parents[ 2 ] != NULL) { + printf( "Ini File: %ws\n", Parents[ 2 ] ); + Parents[ 2 ] = NULL; + } + + printf( " Section: %ws\n %u: %s\n", + MP( PWSTR, pIml, pSection->Name ), + i, SectionActionStrings[ pSection->Action ] + ); + } + else { + if (Parents[ 2 ] != NULL) { + printf( "Ini File: %ws\n", Parents[ 2 ] ); + Parents[ 2 ] = NULL; + } + + if (Parents[ 1 ] != NULL) { + printf( " Section: %ws\n", Parents[ 1 ] ); + Parents[ 1 ] = NULL; + } + + printf( " Variable: %ws\n %u: %s\n", + MP( PWSTR, pIml, pVariable->Name ), + i, VariableActionStrings[ pVariable->Action ] + ); + } +} + +BOOLEAN +CompareIniSectionVariableContentsIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PIML_GENERIC_RECORD pGeneric1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2, + PIML_GENERIC_RECORD pGeneric2, + PWSTR Parents[] + ) +{ + PIML_INIVARIABLE_RECORD pVariable1 = (PIML_INIVARIABLE_RECORD)pGeneric1; + PIML_INIVARIABLE_RECORD pVariable2 = (PIML_INIVARIABLE_RECORD)pGeneric2; + PWSTR pVariableContents1; + PWSTR pVariableContents2; + BOOLEAN ActionsDiffer = FALSE; + BOOLEAN ContentsDiffer = FALSE; + BOOLEAN Result = TRUE; + + pVariableContents1 = MP( PWSTR, pIml1, pVariable1->NewValue ); + pVariableContents2 = MP( PWSTR, pIml2, pVariable2->NewValue ); + + if (pVariable1->Action != pVariable2->Action) { + ActionsDiffer = TRUE; + Result = FALSE; + } + else + if (pVariableContents1 != NULL && pVariableContents2 != NULL) { + if (wcscmp( pVariableContents1, pVariableContents2 ) != 0) { + ContentsDiffer = TRUE; + Result = FALSE; + } + } + + if (!Result) { + if (Parents[ 2 ] != NULL) { + printf( "Ini File: %ws\n", Parents[ 2 ] ); + Parents[ 2 ] = NULL; + } + + if (Parents[ 1 ] != NULL) { + printf( " Section: %ws\n", Parents[ 1 ] ); + Parents[ 1 ] = NULL; + } + + printf( " Variable: %ws\n", MP( PWSTR, pIml1, pVariable1->Name ) ); + if (ActionsDiffer) { + printf( " 1: Action - %s\n", VariableActionStrings[ pVariable1->Action ] ); + printf( " 2: Action - %s\n", VariableActionStrings[ pVariable2->Action ] ); + } + if (ContentsDiffer) { + printf( " 1: '%ws'\n", pVariableContents1 ); + printf( " 2: '%ws'\n", pVariableContents2 ); + } + } + + return Result; +} + + + + +BOOLEAN +CompareIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml1, + PINSTALLATION_MODIFICATION_LOGFILE pIml2 + ) +{ + BOOLEAN Result = TRUE; + PWSTR Parents[ 3 ]; + + Result &= CompareGenericIml( pIml1, MP( PIML_GENERIC_RECORD, pIml1, pIml1->FileRecords ), + pIml2, MP( PIML_GENERIC_RECORD, pIml2, pIml2->FileRecords ), + NULL, + 1, + PrintFileRecordIml, + CompareFileContentsIml + ); + + memset( Parents, 0, sizeof( Parents ) ); + Result &= CompareGenericIml( pIml1, MP( PIML_GENERIC_RECORD, pIml1, pIml1->KeyRecords ), + pIml2, MP( PIML_GENERIC_RECORD, pIml2, pIml2->KeyRecords ), + Parents, + 2, + PrintKeyValueRecordIml, + CompareKeyValueContentsIml + ); + + memset( Parents, 0, sizeof( Parents ) ); + Result &= CompareGenericIml( pIml1, MP( PIML_GENERIC_RECORD, pIml1, pIml1->IniRecords ), + pIml2, MP( PIML_GENERIC_RECORD, pIml2, pIml2->IniRecords ), + Parents, + 3, + PrintIniSectionVariableRecordIml, + CompareIniSectionVariableContentsIml + ); + + return Result; +} diff --git a/private/sdktools/instaler/compinst.rc b/private/sdktools/instaler/compinst.rc new file mode 100644 index 000000000..a5f44b528 --- /dev/null +++ b/private/sdktools/instaler/compinst.rc @@ -0,0 +1,12 @@ +#include "instaler.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Instaler Compare Program" +#define VER_INTERNALNAME_STR "COMPINST\0" +#define VER_ORIGINALFILENAME_STR "COMPINST.EXE" + +#include "common.ver" + +RCINCLUDE errormsg.rc diff --git a/private/sdktools/instaler/debug.c b/private/sdktools/instaler/debug.c new file mode 100644 index 000000000..c20b9eed4 --- /dev/null +++ b/private/sdktools/instaler/debug.c @@ -0,0 +1,481 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + debug.c + +Abstract: + + Main loop for INSTALER program + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +DWORD +DebugEventHandler( + LPDEBUG_EVENT DebugEvent + ); + +VOID +InstallBreakpointsForDLL( + PPROCESS_INFO Process, + LPVOID BaseOfDll + ); + +VOID +RemoveBreakpointsForDLL( + PPROCESS_INFO Process, + LPVOID BaseOfDll + ); + +char *DebugEventNames[] = { + "Unknown debug event", + "EXCEPTION_DEBUG_EVENT", + "CREATE_THREAD_DEBUG_EVENT", + "CREATE_PROCESS_DEBUG_EVENT", + "EXIT_THREAD_DEBUG_EVENT", + "EXIT_PROCESS_DEBUG_EVENT", + "LOAD_DLL_DEBUG_EVENT", + "UNLOAD_DLL_DEBUG_EVENT", + "OUTPUT_DEBUG_STRING_EVENT", + "RIP_EVENT", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + "Unknown debug event", + NULL +}; + + +VOID +DebugEventLoop( VOID ) +{ + DEBUG_EVENT DebugEvent; + DWORD ContinueStatus; + DWORD OldPriority; + + // + // We want to process debug events quickly + // + + OldPriority = GetPriorityClass( GetCurrentProcess() ); + SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ); + + do { + if (!WaitForDebugEvent( &DebugEvent, INFINITE )) { + DeclareError( INSTALER_WAITDEBUGEVENT_FAILED, GetLastError() ); + ExitProcess( 1 ); + } + + if (DebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { + if (DebugEvent.u.Exception.ExceptionRecord.ExceptionCode != STATUS_BREAKPOINT && + DebugEvent.u.Exception.ExceptionRecord.ExceptionCode != STATUS_SINGLE_STEP + ) { + DbgEvent( DBGEVENT, ( "Debug exception event - Code: %x Address: %x Info: [%u] %x %x %x %x\n", + DebugEvent.u.Exception.ExceptionRecord.ExceptionCode, + DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress, + DebugEvent.u.Exception.ExceptionRecord.NumberParameters, + DebugEvent.u.Exception.ExceptionRecord.ExceptionInformation[ 0 ], + DebugEvent.u.Exception.ExceptionRecord.ExceptionInformation[ 1 ], + DebugEvent.u.Exception.ExceptionRecord.ExceptionInformation[ 2 ], + DebugEvent.u.Exception.ExceptionRecord.ExceptionInformation[ 3 ] + ) + ); + } + } + else { + DbgEvent( DBGEVENT, ( "Debug %s (%x) event\n", + DebugEventNames[ DebugEvent.dwDebugEventCode ], + DebugEvent.dwDebugEventCode + ) + ); + } + ContinueStatus = DebugEventHandler( &DebugEvent ); + if (!ContinueDebugEvent( DebugEvent.dwProcessId, + DebugEvent.dwThreadId, + ContinueStatus + ) + ) { + DeclareError( INSTALER_CONTDEBUGEVENT_FAILED, GetLastError() ); + ExitProcess( 1 ); + } + } + while (!IsListEmpty( &ProcessListHead )); + + + // + // Drop back to old priority to interact with user. + // + + SetPriorityClass( GetCurrentProcess(), OldPriority ); +} + + +DWORD +DebugEventHandler( + LPDEBUG_EVENT DebugEvent + ) +{ + DWORD ContinueStatus; + PPROCESS_INFO Process; + PTHREAD_INFO Thread; + PBREAKPOINT_INFO Breakpoint; + + ContinueStatus = (DWORD)DBG_CONTINUE; + if (FindProcessAndThreadForEvent( DebugEvent, &Process, &Thread )) { + switch (DebugEvent->dwDebugEventCode) { + case CREATE_PROCESS_DEBUG_EVENT: + // + // Create process event includes first thread of process + // as well. Remember process and thread in our process tree + // + + if (AddProcess( DebugEvent, &Process )) { + InheritHandles( Process ); + AddThread( DebugEvent, Process, &Thread ); + } + break; + + case EXIT_PROCESS_DEBUG_EVENT: + // + // Exit process event includes last thread of process + // as well. Remove process and thread from our process tree + // + + if (DeleteThread( Process, Thread )) { + DeleteProcess( Process ); + } + break; + + case CREATE_THREAD_DEBUG_EVENT: + // + // Create thread. Remember thread in our process tree. + // + + AddThread( DebugEvent, Process, &Thread ); + break; + + case EXIT_THREAD_DEBUG_EVENT: + // + // Exit thread. Remove thread from our process tree. + // + + DeleteThread( Process, Thread ); + break; + + case LOAD_DLL_DEBUG_EVENT: + // + // DLL just mapped into process address space. See if it is one + // of the ones we care about and if so, install the necessary + // breakpoints. + // + + InstallBreakpointsForDLL( Process, DebugEvent->u.LoadDll.lpBaseOfDll ); + break; + + case UNLOAD_DLL_DEBUG_EVENT: + // + // DLL just unmapped from process address space. See if it is one + // of the ones we care about and if so, remove the breakpoints we + // installed when it was mapped. + // + + RemoveBreakpointsForDLL( Process, DebugEvent->u.UnloadDll.lpBaseOfDll ); + break; + + case OUTPUT_DEBUG_STRING_EVENT: + case RIP_EVENT: + // + // Ignore these + // + break; + + case EXCEPTION_DEBUG_EVENT: + // + // Assume we wont handle this exception + // + + ContinueStatus = (DWORD)DBG_EXCEPTION_NOT_HANDLED; + switch (DebugEvent->u.Exception.ExceptionRecord.ExceptionCode) { + // + // Breakpoint exception. + // + + case STATUS_BREAKPOINT: + EnterCriticalSection( &BreakTable ); + if (Thread->BreakpointToStepOver != NULL) { + // + // If this breakpoint was in place to step over an API entry + // point breakpoint, then deal with it by ending single + // step mode, resuming all threads in the process and + // reinstalling the API breakpoint we just stepped over. + // Finally return handled for this exception so the + // thread can proceed. + // + + EndSingleStepBreakpoint( Process, Thread ); + HandleThreadsForSingleStep( Process, Thread, FALSE ); + InstallBreakpoint( Process, Thread->BreakpointToStepOver ); + Thread->BreakpointToStepOver = NULL; + ContinueStatus = (DWORD)DBG_EXCEPTION_HANDLED; + } + else { + // + // Otherwise, see if this breakpoint is either an API entry + // point breakpoint for the process or a return address + // breakpoint for a thread in the process. + // + Breakpoint = FindBreakpoint( DebugEvent->u.Exception.ExceptionRecord.ExceptionAddress, + Process, + Thread + ); + if (Breakpoint != NULL) { + // + // This is one of our breakpoints, call the breakpoint + // handler. + // + if (HandleBreakpoint( Process, Thread, Breakpoint )) { + // + // Now single step over this breakpoint, by removing it and + // setting a breakpoint at the next instruction (or using + // single stepmode if the processor supports it). We also + // suspend all the threads in the process except this one so + // we know the next breakpoint/single step exception we see + // for this process will be for this one. + // + + Thread->BreakpointToStepOver = Breakpoint; + RemoveBreakpoint( Process, Breakpoint ); + HandleThreadsForSingleStep( Process, Thread, TRUE ); + BeginSingleStepBreakpoint( Process, Thread ); + } + else { + Thread->BreakpointToStepOver = NULL; + } + + ContinueStatus = (DWORD)DBG_EXCEPTION_HANDLED; + } + else { + DbgEvent( DBGEVENT, ( "Skipping over hardcoded breakpoint at %x\n", + DebugEvent->u.Exception.ExceptionRecord.ExceptionAddress + ) + ); + + // + // If not one of our breakpoints, assume it is a hardcoded + // breakpoint and skip over it. This will get by the one + // breakpoint in LdrInit triggered by the process being + // invoked with DEBUG_PROCESS. + // + + if (SkipOverHardcodedBreakpoint( Process, + Thread, + DebugEvent->u.Exception.ExceptionRecord.ExceptionAddress + ) + ) { + // + // If we successfully skipped over this hard-coded breakpoint + // then return handled for this exception. + // + + ContinueStatus = (DWORD)DBG_EXCEPTION_HANDLED; + } + } + } + LeaveCriticalSection( &BreakTable ); + break; + + case STATUS_SINGLE_STEP: + // + // We should only see this exception on processors that + // support a single step mode. + // + + EnterCriticalSection( &BreakTable ); + if (Thread->BreakpointToStepOver != NULL) { + EndSingleStepBreakpoint( Process, Thread ); + HandleThreadsForSingleStep( Process, Thread, FALSE ); + InstallBreakpoint( Process, Thread->BreakpointToStepOver ); + Thread->BreakpointToStepOver = NULL; + ContinueStatus = (DWORD)DBG_EXCEPTION_HANDLED; + } + LeaveCriticalSection( &BreakTable ); + break; + + case STATUS_VDM_EVENT: + // + // Returning NOT_HANDLED will cause the default behavior to + // occur. + // + break; + + default: + DbgEvent( DBGEVENT, ( "Unknown exception: %08x at %08x\n", + DebugEvent->u.Exception.ExceptionRecord.ExceptionCode, + DebugEvent->u.Exception.ExceptionRecord.ExceptionAddress + ) + ); + break; + } + break; + + default: + DbgEvent( DBGEVENT, ( "Unknown debug event\n" ) ); + break; + } + } + return( ContinueStatus ); +} + + +VOID +InstallBreakpointsForDLL( + PPROCESS_INFO Process, + LPVOID BaseOfDll + ) +{ + UCHAR ModuleIndex, ApiIndex; + PBREAKPOINT_INFO Breakpoint; + + // + // Loop over module table to see if the base address of this DLL matches + // one of the module handles we want to set breakpoints in. If not, ignore + // event. + // + + for (ModuleIndex=0; ModuleIndex<MAXIMUM_MODULE_INDEX; ModuleIndex++) { + if (ModuleInfo[ ModuleIndex ].ModuleHandle == BaseOfDll) { + // + // Loop over the list of API entry points for this module and set + // a process specific breakpoint at the first instruction of each + // entrypoint. + // + + for (ApiIndex=0; ApiIndex<MAXIMUM_API_INDEX; ApiIndex++) { + if (ModuleIndex == ApiInfo[ ApiIndex ].ModuleIndex) { + if (CreateBreakpoint( ApiInfo[ ApiIndex ].EntryPointAddress, + Process, + NULL, // process specific + ApiIndex, + NULL, + &Breakpoint + ) + ) { + Breakpoint->ModuleName = ModuleInfo[ ApiInfo[ ApiIndex ].ModuleIndex ].ModuleName; + Breakpoint->ProcedureName = ApiInfo[ ApiIndex ].EntryPointName; + DbgEvent( DBGEVENT, ( "Installed breakpoint for %ws!%s at %08x\n", + Breakpoint->ModuleName, + Breakpoint->ProcedureName, + ApiInfo[ ApiIndex ].EntryPointAddress + ) + ); + } + } + } + break; + } + } +} + +VOID +RemoveBreakpointsForDLL( + PPROCESS_INFO Process, + LPVOID BaseOfDll + ) +{ + UCHAR ModuleIndex, ApiIndex; + + // + // Loop over module index to see if the base address of this DLL matches + // one of the module handles we set breakpoints in above. If not, ignore + // event. + // + + for (ModuleIndex=0; ModuleIndex<MAXIMUM_MODULE_INDEX; ModuleIndex++) { + if (ModuleInfo[ ModuleIndex ].ModuleHandle == BaseOfDll) { + // + // Loop over the list of API entry points for this module and remove + // each process specific breakpoint set above for each entrypoint. + // + + for (ApiIndex=0; ApiIndex<MAXIMUM_API_INDEX; ApiIndex++) { + if (ModuleIndex == ApiInfo[ ApiIndex ].ModuleIndex) { + DestroyBreakpoint( ApiInfo[ ApiIndex ].EntryPointAddress, + Process, + NULL // process specific + ); + } + } + break; + } + } +} + + +BOOLEAN +InstallBreakpoint( + PPROCESS_INFO Process, + PBREAKPOINT_INFO Breakpoint + ) +{ + if (!Breakpoint->SavedInstructionValid && + !ReadMemory( Process, + Breakpoint->Address, + &Breakpoint->SavedInstruction, + SizeofBreakpointInstruction, + "save instruction" + ) + ) { + return FALSE; + } + else + if (!WriteMemory( Process, + Breakpoint->Address, + BreakpointInstruction, + SizeofBreakpointInstruction, + "breakpoint instruction" + ) + ) { + return FALSE; + } + else { + Breakpoint->SavedInstructionValid = TRUE; + return TRUE; + } +} + +BOOLEAN +RemoveBreakpoint( + PPROCESS_INFO Process, + PBREAKPOINT_INFO Breakpoint + ) +{ + if (!Breakpoint->SavedInstructionValid || + !WriteMemory( Process, + Breakpoint->Address, + &Breakpoint->SavedInstruction, + SizeofBreakpointInstruction, + "restore saved instruction" + ) + ) { + return FALSE; + } + else { + return TRUE; + } +} diff --git a/private/sdktools/instaler/dir.bmp b/private/sdktools/instaler/dir.bmp Binary files differnew file mode 100644 index 000000000..d8794617d --- /dev/null +++ b/private/sdktools/instaler/dir.bmp diff --git a/private/sdktools/instaler/error.c b/private/sdktools/instaler/error.c new file mode 100644 index 000000000..2241d8642 --- /dev/null +++ b/private/sdktools/instaler/error.c @@ -0,0 +1,202 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + error.c + +Abstract: + + Error handle module for the INSTALER program + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +VOID +TraceDisplay( + const char *FormatString, + ... + ) +{ + va_list arglist; + + va_start( arglist, FormatString ); + vprintf( FormatString, arglist ); + if (InstalerLogFile) { + vfprintf( InstalerLogFile, FormatString, arglist ); + } + va_end( arglist ); + fflush( stdout ); + return; +} + +VOID +CDECL +DeclareError( + UINT ErrorCode, + UINT SupplementalErrorCode, + ... + ) +{ + va_list arglist; + HMODULE ModuleHandle; + DWORD Flags, Size; + WCHAR MessageBuffer[ 512 ]; + + va_start( arglist, SupplementalErrorCode ); + + if ((ErrorCode & 0x0FFF0000) >> 16 == FACILITY_APPLICATION) { + ModuleHandle = InstalerModuleHandle; + Flags = FORMAT_MESSAGE_FROM_HMODULE; + } + else + if ((ErrorCode & 0x0FFF0000) == FACILITY_NT) { + ErrorCode ^= FACILITY_NT; + ModuleHandle = ModuleInfo[ NTDLL_MODULE_INDEX ].ModuleHandle; + Flags = FORMAT_MESSAGE_FROM_HMODULE; + } + else { + ModuleHandle = NULL; + Flags = FORMAT_MESSAGE_FROM_SYSTEM; + } + + Size = FormatMessage( Flags, + (LPCVOID)ModuleHandle, + ErrorCode, + 0, + MessageBuffer, + sizeof( MessageBuffer ) / sizeof( WCHAR ), + &arglist + ); + va_end( arglist ); + + if (Size != 0) { + printf( "INSTALER: %ws", MessageBuffer ); + } + else { + printf( "INSTALER: Unable to get message text for %08x\n", ErrorCode ); + } + + if (ModuleHandle == InstalerModuleHandle && + SupplementalErrorCode != 0 && + SupplementalErrorCode != ERROR_GEN_FAILURE && + SupplementalErrorCode != STATUS_UNSUCCESSFUL + ) { + if ((SupplementalErrorCode & 0x0FFF0000) == FACILITY_NT) { + SupplementalErrorCode ^= FACILITY_NT; + ModuleHandle = ModuleInfo[ NTDLL_MODULE_INDEX ].ModuleHandle; + Flags = FORMAT_MESSAGE_FROM_HMODULE; + } + else { + ModuleHandle = NULL; + Flags = FORMAT_MESSAGE_FROM_SYSTEM; + } + Size = FormatMessage( Flags, + (LPCVOID)ModuleHandle, + SupplementalErrorCode, + 0, + MessageBuffer, + sizeof( MessageBuffer ) / sizeof( WCHAR ), + NULL + ); + if (Size != 0) { + while (Size != 0 && MessageBuffer[ Size ] <= L' ') { + MessageBuffer[ Size ] = UNICODE_NULL; + Size -= 1; + } + + printf( " '%ws'\n", MessageBuffer ); + } + else { + printf( "INSTALER: Unable to get message text for %08x\n", SupplementalErrorCode ); + } + } + + + + return; +} + +WCHAR MessageBoxTitle[ MAX_PATH ]; + + +UINT +CDECL +AskUser( + UINT MessageBoxFlags, + UINT MessageId, + UINT NumberOfArguments, + ... + ) +{ + va_list arglist; + HMODULE ModuleHandle; + DWORD Flags, Size; + WCHAR MessageBuffer[ 512 ]; + PWSTR s; + ULONG Args[ 24 ]; + PULONG p; + + if (MessageBoxTitle[ 0 ] == UNICODE_NULL) { + Args[ 0 ] = (ULONG)InstallationName; + Args[ 1 ] = 0; + Size = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID)InstalerModuleHandle, + INSTALER_ASKUSER_TITLE, + 0, + MessageBoxTitle, + sizeof( MessageBoxTitle ) / sizeof( WCHAR ), + (va_list *)Args + ); + if (Size == 0) { + _snwprintf( MessageBoxTitle, + sizeof( MessageBoxTitle ) / sizeof( WCHAR ), + L"Application Installation Monitor Program - %ws", + InstallationName + ); + } + else { + if ((s = wcschr( MessageBoxTitle, L'\r' )) || + (s = wcschr( MessageBoxTitle, L'\n' )) + ) { + *s = UNICODE_NULL; + } + } + } + + va_start( arglist, NumberOfArguments ); + p = Args; + while (NumberOfArguments--) { + *p++ = va_arg( arglist, ULONG ); + } + *p++ = 0; + va_end( arglist ); + + Size = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID)InstalerModuleHandle, + MessageId, + 0, + MessageBuffer, + sizeof( MessageBuffer ) / sizeof( WCHAR ), + (va_list *)Args + ); + + if (Size != 0) { + return MessageBox( NULL, + MessageBuffer, + MessageBoxTitle, + MB_SETFOREGROUND | MessageBoxFlags + ); + } + else { + return IDOK; + } +} diff --git a/private/sdktools/instaler/errormsg.mc b/private/sdktools/instaler/errormsg.mc new file mode 100644 index 000000000..4c91402ef --- /dev/null +++ b/private/sdktools/instaler/errormsg.mc @@ -0,0 +1,219 @@ +;/*++ BUILD Version: 0001 // Increment this if a change has global effects +; +;Copyright (c) 1991-1992 Microsoft Corporation +; +;Module Name: +; +; errormsg.h +; +;Abstract: +; +; This file contains the error code definitions and message for the +; INSTALER program. +; +;Author: +; +; Steve Wood (stevewo) 09-Aug-1994 +; +;--*/ +; +;#ifndef _INSTALER_ERRORMSG_ +;#define _INSTALER_ERRORMSG_ +; +; + +SeverityNames=(Success=0x0:APP_SEVERITY_SUCCESS + Informational=0x1:APP_SEVERITY_INFORMATIONAL + Warning=0x2:APP_SEVERITY_WARNING + Error=0x3:APP_SEVERITY_ERROR + ) + +FacilityNames=(Application=0x100:FACILITY_APPLICATION) + +;#define FACILITY_NT 0x0FFF0000 + +MessageId=0001 Severity=Error Facility=Application SymbolicName=INSTALER_MISSING_MODULE +Language=English +Unable to find %1 dynamic link library. +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_MISSING_ENTRYPOINT +Language=English +Unable to find %1 entry point in %2 dynamic link library. +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_CANT_DEBUG_PROGRAM +Language=English +Unable to debug '%1' +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_WAITDEBUGEVENT_FAILED +Language=English +Unable to wait for debug event. +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_CONTDEBUGEVENT_FAILED +Language=English +Unable to continue debug event. +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_DUPLICATE_PROCESS_ID +Language=English +Duplicate Process Id (%1!x!). +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_MISSING_PROCESS_ID +Language=English +Missing Process Id (%1!x!). +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_DUPLICATE_THREAD_ID +Language=English +Duplicate Thread Id (%1!x!) for Process Id (%2!x!) +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_MISSING_THREAD_ID +Language=English +Missing Thread Id (%1!x!) for Process Id (%2!x!) +. + +MessageId= Severity=Error Facility=Application SymbolicName=INSTALER_CANT_ACCESS_FILE +Language=English +Unable to access file (%1!ws!) for comparison. Assuming different. +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_ASKUSER_TITLE +Language=English +Application Installation Monitor - %1!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_ASKUSER_ROOTSCAN +Language=English +The application installation program is about to scan root directory of %1!ws! +Press cancel if you don't want the program to do that. +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_ASKUSER_GETVERSION +Language=English +The application installation program is about to ask for the version of +the operating system. Press OK if you want to tell the truth. Press +cancel if you want to lie to the program and tell it that it is running +on Windows 95 +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_ASKUSER_REGCONNECT +Language=English +The application installation program is about to connect to the registry of a +remote machine (%1!ws!) The INSTALER program is unable to track changes made to +a remote registry. Press OK if you want to proceed anyway. Press cancel if you +want to fail the program's attempt to connect to the registry of the remote machine. +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_SET_DIRECTORY +Language=English +%2!05u! Current Directory now: %1!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_INI_CREATE +Language=English +%5!05u! Created: %1!ws! [%2!ws!] %3!ws! = '%4!ws!' +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_INI_DELETE +Language=English +%5!05u! Deleted: %1!ws! [%2!ws!] %3!ws! = '%4!ws!' +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_INI_CHANGE +Language=English +%6!05u! Changed: %1!ws! [%2!ws!] %3!ws! = '%4!ws!' (was '%5!ws!') +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_INI_DELETE_SECTION +Language=English +%3!05u! Deleted: %1!ws! [%2!ws!] +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_SCAN_DIRECTORY +Language=English +%4!05u! Scanned %3!u! entries from directory: %1!ws!\%2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_CREATE_FILE +Language=English +%3!05u! Created %1!ws!: %2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_WRITE_FILE +Language=English +%3!05u! Writing %1!ws!: %2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_READ_FILE +Language=English +%3!05u! Reading %1!ws!: %2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_DELETE_FILE +Language=English +%3!05u! Deleted %1!ws!: %2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_DELETE_TEMP_FILE +Language=English +%3!05u! Deleted %1!ws!: %2!ws! (temporary) +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_RENAME_FILE +Language=English +%4!05u! Renamed %1!ws!: %2!ws! + to: %3!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_RENAME_TEMP_FILE +Language=English +%4!05u! Renamed %1!ws!: %2!ws! (temporary) + to: %3!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_WRITE_KEY +Language=English +%2!05u! Opened key for write: %1!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_READ_KEY +Language=English +%2!05u! Opened key for read: %1!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_DELETE_KEY +Language=English +%2!05u! Deleted key: %1!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_DELETE_TEMP_KEY +Language=English +%2!05u! Deleted key: %1!ws! (temporary) +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_SET_KEY_VALUE +Language=English +%3!05u! Set value (%1!ws!) for key: %2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_DELETE_KEY_VALUE +Language=English +%3!05u! Deleted value (%1!ws!) for key: %2!ws! +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_DELETE_KEY_TEMP_VALUE +Language=English +%3!05u! Deleted value (%1!ws!) for key: %2!ws! (temporary) +. + +MessageId= Severity=Informational Facility=Application SymbolicName=INSTALER_EVENT_GETVERSION +Language=English +%2!05u! GetVersion will return %1!ws! +. + +;#endif // _INSTALER_ERRORMSG_ diff --git a/private/sdktools/instaler/event.c b/private/sdktools/instaler/event.c new file mode 100644 index 000000000..492504f63 --- /dev/null +++ b/private/sdktools/instaler/event.c @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + event.c + +Abstract: + + Log formatted events to a file and possibly the console too + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +VOID +CDECL +LogEvent( + UINT MessageId, + UINT NumberOfArguments, + ... + ) +{ + va_list arglist; + HMODULE ModuleHandle; + DWORD Flags, Size; + WCHAR MessageBuffer[ 512 ]; + PWSTR s; + ULONG Args[ 24 ]; + PULONG p; + + va_start( arglist, NumberOfArguments ); + p = Args; + while (NumberOfArguments--) { + *p++ = va_arg( arglist, ULONG ); + } + *p++ = ((GetTickCount() - StartProcessTickCount) / 1000); // Seconds since the start + *p++ = 0; + va_end( arglist ); + + Size = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID)InstalerModuleHandle, + MessageId, + 0, + MessageBuffer, + sizeof( MessageBuffer ) / sizeof( WCHAR ), + (va_list *)Args + ); + if (Size != 0) { + s = MessageBuffer; + while (s = wcschr( s, L'\r' )) { + if (s[1] == '\n') { + wcscpy( s, s+1 ); + } + else { + s += 1; + } + } + printf( "%ws", MessageBuffer ); + if (InstalerLogFile) { + fprintf( InstalerLogFile, "%ws", MessageBuffer ); + } + } + else { + printf( "INSTALER: Unable to get message text for %08x\n", MessageId ); + } + + return; +} diff --git a/private/sdktools/instaler/file.bmp b/private/sdktools/instaler/file.bmp Binary files differnew file mode 100644 index 000000000..24824e130 --- /dev/null +++ b/private/sdktools/instaler/file.bmp diff --git a/private/sdktools/instaler/file.c b/private/sdktools/instaler/file.c new file mode 100644 index 000000000..ea310c54c --- /dev/null +++ b/private/sdktools/instaler/file.c @@ -0,0 +1,440 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + file.c + +Abstract: + + This module implements the functions to save references to files for the + INSTALER program. Part of each reference is a handle to a backup copy + of a file if the reference is a write/delete/rename. + +Author: + + Steve Wood (stevewo) 22-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + + +BOOLEAN +CreateFileReference( + PWSTR Name, + BOOLEAN WriteAccess, + PFILE_REFERENCE *ReturnedReference + ) +{ + PFILE_REFERENCE p; + PWSTR BackupFileName; + WIN32_FIND_DATAW FindFileData; + HANDLE FindFileHandle; + + *ReturnedReference = NULL; + p = FindFileReference( Name ); + if (p != NULL) { + if (p->WriteAccess) { + *ReturnedReference = p; + return TRUE; + } + } + else { + p = AllocMem( sizeof( *p ) ); + if (p == NULL) { + return FALSE; + } + + InsertTailList( &FileReferenceListHead, &p->Entry ); + NumberOfFileReferences += 1; + p->Name = Name; + } + + BackupFileName = L""; + FindFileHandle = NULL; + if ((p->WriteAccess = WriteAccess) && + (FindFileHandle = FindFirstFileW( p->Name, &FindFileData )) != INVALID_HANDLE_VALUE + ) { + if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + p->DirectoryFile = TRUE; + } + else { + p->BackupFileAttributes = FindFileData.dwFileAttributes; + p->BackupLastWriteTime = FindFileData.ftLastWriteTime; + p->BackupFileSize.LowPart = FindFileData.nFileSizeLow; + p->BackupFileSize.HighPart = FindFileData.nFileSizeHigh; + BackupFileName = CreateBackupFileName( &p->BackupFileUniqueId ); + if (BackupFileName == NULL || + !CopyFileW( Name, BackupFileName, TRUE ) + ) { + p->BackupFileUniqueId = 0xFFFF; // Backup failed. + DeclareError( INSTALER_CANT_ACCESS_FILE, GetLastError(), Name ); + } + } + } + else { + p->Created = p->WriteAccess; + } + + if (FindFileHandle != NULL) { + FindClose( FindFileHandle ); + } + + *ReturnedReference = p; + return TRUE; +} + + +BOOLEAN +CompleteFileReference( + PFILE_REFERENCE p, + BOOLEAN CallSuccessful, + BOOLEAN Deleted, + PFILE_REFERENCE RenameReference + ) +{ + DWORD dwFileAttributes; + + if (!CallSuccessful) { + DestroyFileReference( p ); + return FALSE; + } + + if (RenameReference) { + if (RenameReference->Created) { + LogEvent( INSTALER_EVENT_RENAME_TEMP_FILE, + 3, + RenameReference->DirectoryFile ? L"directory" : L"file", + RenameReference->Name, + p->Name + ); + + RenameReference->Name = p->Name; + DestroyFileReference( p ); + return FALSE; + } + + RenameReference->Deleted = TRUE; + + LogEvent( INSTALER_EVENT_RENAME_FILE, + 3, + RenameReference->DirectoryFile ? L"directory" : L"file", + RenameReference->Name, + p->Name + ); + } + else + if (Deleted && p->Created) { + LogEvent( INSTALER_EVENT_DELETE_TEMP_FILE, + 2, + p->DirectoryFile ? L"directory" : L"file", + p->Name + ); + DestroyFileReference( p ); + return FALSE; + } + else { + if (wcschr( p->Name, '\\' ) == NULL) { + // + // If no path separator, must be volume open. Treat + // as directory and dont touch file + // + p->DirectoryFile = TRUE; + } + else + if ((dwFileAttributes = GetFileAttributes( p->Name )) != 0xFFFFFFFF) { + p->DirectoryFile = (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + + if (Deleted) { + LogEvent( INSTALER_EVENT_DELETE_FILE, + 2, + p->DirectoryFile ? L"directory" : L"file", + p->Name + ); + } + else + if (p->WriteAccess) { + if (p->Created) { + LogEvent( INSTALER_EVENT_CREATE_FILE, + 2, + p->DirectoryFile ? L"directory" : L"file", + p->Name + ); + } + else { + LogEvent( INSTALER_EVENT_WRITE_FILE, + 2, + p->DirectoryFile ? L"directory" : L"file", + p->Name + ); + } + } + else { + LogEvent( INSTALER_EVENT_READ_FILE, + 2, + p->DirectoryFile ? L"directory" : L"file", + p->Name + ); + } + } + + p->Deleted = Deleted; + return TRUE; +} + + +BOOLEAN +DestroyFileReference( + PFILE_REFERENCE p + ) +{ + PWSTR BackupFileName; + + if (!p->Created && + (BackupFileName = FormatTempFileName( NULL, &p->BackupFileUniqueId )) + ) { + DeleteFileW( BackupFileName ); + } + + if (p->DateModified || p->AttributesModified) { + return FALSE; + } + + RemoveEntryList( &p->Entry ); + NumberOfFileReferences -= 1; + FreeMem( &p ); + return TRUE; +} + + + +PVOID +MapFileForRead( + PWSTR FileName, + PULONG FileSize + ) +{ + HANDLE FileHandle, MappingHandle; + PVOID FileData; + ULONG HighFileSize; + + FileData = NULL; + FileHandle = CreateFileW( FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (FileHandle != INVALID_HANDLE_VALUE) { + *FileSize = GetFileSize( FileHandle, &HighFileSize ); + if (*FileSize == 0) { + CloseHandle( FileHandle ); + return (PVOID)0xFFFFFFFF; + } + + MappingHandle = CreateFileMappingW( FileHandle, + NULL, + PAGE_READONLY, + 0, + *FileSize, + NULL + ); + CloseHandle( FileHandle ); + if (MappingHandle != NULL) { + FileData = MapViewOfFile( MappingHandle, + FILE_MAP_READ, + 0, + 0, + *FileSize + ); + CloseHandle( MappingHandle ); + } + } + + return FileData; +} + + +BOOLEAN +AreFileContentsEqual( + PWSTR FileName1, + PWSTR FileName2 + ) +{ + PVOID FileData1, FileData2; + ULONG FileSize1, FileSize2; + BOOLEAN Result; + + Result = FALSE; + if (FileData1 = MapFileForRead( FileName1, &FileSize1 )) { + if (FileData2 = MapFileForRead( FileName2, &FileSize2 )) { + if (FileSize1 == FileSize2 && + RtlCompareMemory( FileData1, FileData2, FileSize1 ) == FileSize1 + ) { + Result = TRUE; + } + if (FileData2 != (PVOID)0xFFFFFFFF) { + UnmapViewOfFile( FileData2 ); + } + } + else { + DeclareError( INSTALER_CANT_ACCESS_FILE, GetLastError(), FileName2 ); + } + + if (FileData1 != (PVOID)0xFFFFFFFF) { + UnmapViewOfFile( FileData1 ); + } + } + else { + DeclareError( INSTALER_CANT_ACCESS_FILE, GetLastError(), FileName1 ); + } + + return Result; +} + +BOOLEAN +IsNewFileSameAsBackup( + PFILE_REFERENCE p + ) +{ + WIN32_FIND_DATAW FindFileData; + HANDLE FindFileHandle; + PWSTR BackupFileName; + + if ((FindFileHandle = FindFirstFileW( p->Name, &FindFileData )) != INVALID_HANDLE_VALUE) { + FindClose( FindFileHandle ); + if (p->BackupFileAttributes != FindFileData.dwFileAttributes) { + p->AttributesModified = TRUE; + } + + if (p->BackupLastWriteTime.dwLowDateTime != FindFileData.ftLastWriteTime.dwLowDateTime || + p->BackupLastWriteTime.dwHighDateTime != FindFileData.ftLastWriteTime.dwHighDateTime + ) { + p->DateModified = TRUE; + } + + if (BackupFileName = FormatTempFileName( NULL, &p->BackupFileUniqueId )) { + if (p->BackupFileSize.LowPart != FindFileData.nFileSizeLow || + p->BackupFileSize.HighPart != FindFileData.nFileSizeHigh || + !AreFileContentsEqual( BackupFileName, p->Name ) + ) { + p->ContentsModified = TRUE; + return FALSE; + } + } + + return TRUE; + } + else { + return FALSE; + } +} + +PFILE_REFERENCE +FindFileReference( + PWSTR Name + ) +{ + PFILE_REFERENCE p; + PLIST_ENTRY Head, Next; + + Head = &FileReferenceListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, FILE_REFERENCE, Entry ); + if (p->Name == Name) { + return p; + } + + Next = Next->Flink; + } + + return NULL; +} + + +VOID +DumpFileReferenceList( + FILE *LogFile + ) +{ + PFILE_REFERENCE p; + PLIST_ENTRY Head, Next; + + Head = &FileReferenceListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, FILE_REFERENCE, Entry ); + if (p->WriteAccess) { + if (!p->Deleted) { + if (p->BackupFileUniqueId == 0) { + if (p->Created) { + ImlAddFileRecord( pImlNew, + CreateNewFile, + p->Name, + NULL, + NULL, + 0 + ); + } + } + else { + if (p->ContentsModified) { + if (ImlAddFileRecord( pImlNew, + ModifyOldFile, + p->Name, + FormatTempFileName( NULL, &p->BackupFileUniqueId ), + NULL, + 0 + ) + ) { + DeleteFile( FormatTempFileName( NULL, &p->BackupFileUniqueId ) ); + } + } + else + if (p->DateModified) { + ImlAddFileRecord( pImlNew, + ModifyFileDateTime, + p->Name, + NULL, + &p->BackupLastWriteTime, + p->BackupFileAttributes + ); + } + else { + ImlAddFileRecord( pImlNew, + ModifyFileAttributes, + p->Name, + NULL, + &p->BackupLastWriteTime, + p->BackupFileAttributes + ); + } + } + } + else { + if (ImlAddFileRecord( pImlNew, + DeleteOldFile, + p->Name, + FormatTempFileName( NULL, &p->BackupFileUniqueId ), + NULL, + 0 + ) + ) { + DeleteFile( FormatTempFileName( NULL, &p->BackupFileUniqueId ) ); + } + } + } + + Next = Next->Flink; + } + + return; +} diff --git a/private/sdktools/instaler/fileman.c b/private/sdktools/instaler/fileman.c new file mode 100644 index 000000000..7ebcd0f2f --- /dev/null +++ b/private/sdktools/instaler/fileman.c @@ -0,0 +1,226 @@ +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#include "resource.h" +#include "hlist.h" + + +#define TYPE_FILE 1 +#define TYPE_DIR 2 + + +LRESULT WndProc(HWND,UINT,WPARAM,LPARAM); + +HINSTANCE hControlLib; +HINSTANCE hInst; +HBITMAP hFileBmp; +HBITMAP hDirBmp; +HWND hwndList; + + +BOOL HListInitialize(HMODULE); + + + +int _cdecl +main( + int argc, + char *argv[] + ) +{ + WNDCLASS wndclass; + HWND hwnd; + MSG msg; + + + hInst = GetModuleHandle( NULL ); + + HListInitialize( hInst ); + + hFileBmp = LoadBitmap( hInst, MAKEINTRESOURCE(FILEBMP) ); + hDirBmp = LoadBitmap( hInst, MAKEINTRESOURCE(DIRBMP) ); + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInst; + wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = GetStockObject (WHITE_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = "test"; + RegisterClass (&wndclass); + + hwnd = CreateWindow( + "test", + "Test Custon Control App", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + GetModuleHandle(NULL), + NULL ); + + ShowWindow( hwnd, SW_SHOW ); + UpdateWindow( hwnd ); + + while (GetMessage( &msg, NULL, 0, 0 )) { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + return 0; +} + +DWORD CALLBACK +ExpansionCallback( + LPDWORD type, + LPSTR *str, + LPSTR ref, + DWORD level, + DWORD nchild + ) +{ + static WIN32_FIND_DATA fd = {0}; + static HANDLE hFind = NULL; + static CHAR Dir[MAX_PATH*3]; + CHAR NewDir[MAX_PATH*3]; + LPSTR p; + + + if ((!hFind) && (*type == TYPE_FILE)) { + MessageBeep( 0 ); + return HLB_END; + } + + if (!hFind) { + if (nchild) { + // + // this node needs to be collapsed + // + return HLB_COLLAPSE; + } + + if (!GetCurrentDirectory( sizeof(Dir), Dir )) { + return HLB_IGNORE; + } + p = ref; + NewDir[0] = 0; + while (p && *p) { + p += (strlen(p) + 1); + } + while (p != ref) { + p -= 2; + while (*p && p != ref) { + p--; + } + if (!*p) { + p++; + } + strcat( NewDir, p ); + strcat( NewDir, "\\" ); + } + if (!SetCurrentDirectory( NewDir )) { + return HLB_END; + } + hFind = FindFirstFile( "*.*", &fd ); + if (hFind == INVALID_HANDLE_VALUE) { + hFind = NULL; + MessageBeep( 0 ); + return HLB_END; + } + } else { + if (!FindNextFile( hFind, &fd )) { + FindClose( hFind ); + SetCurrentDirectory( Dir ); + hFind = NULL; + return HLB_END; + } + } + + + *str = fd.cFileName; + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + *type = TYPE_DIR; + } else { + *type = TYPE_FILE; + } + + if (level && fd.cFileName[0] == '.') { + return HLB_IGNORE; + } + + return HLB_EXPAND; +} + +VOID +FillListBox( + VOID + ) +{ + WIN32_FIND_DATA fd; + HANDLE hFind; + DWORD type; + + + hFind = FindFirstFile( "*.*", &fd ); + if (hFind == INVALID_HANDLE_VALUE) { + return; + } + + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + type = TYPE_DIR; + } else { + type = TYPE_FILE; + } + SendMessage( hwndList, HLB_ADDSTRING, type, (LPARAM) fd.cFileName ); + } while(FindNextFile( hFind, &fd )); + + FindClose( hFind ); +} + +LRESULT +WndProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + RECT cRect; + + + switch (message) { + case WM_CREATE: + GetClientRect( hwnd, &cRect ); + hwndList = CreateWindow( + "HList", + NULL, + WS_CHILD | WS_VISIBLE, + cRect.left, + cRect.top, + cRect.right - cRect.left, + cRect.bottom - cRect.top, + hwnd, + NULL, + GetModuleHandle(NULL), + NULL ); + SendMessage( hwndList, HLB_REGISTER_CALLBACK, 0, (LPARAM)ExpansionCallback ); + SendMessage( hwndList, HLB_REGISTER_TYPE, TYPE_FILE, (LPARAM)hFileBmp ); + SendMessage( hwndList, HLB_REGISTER_TYPE, TYPE_DIR, (LPARAM)hDirBmp ); + FillListBox(); + break; + + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + } + + return DefWindowProc( hwnd, message, wParam, lParam ); +} diff --git a/private/sdktools/instaler/handledb.c b/private/sdktools/instaler/handledb.c new file mode 100644 index 000000000..f3ade0c56 --- /dev/null +++ b/private/sdktools/instaler/handledb.c @@ -0,0 +1,172 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + handledb.c + +Abstract: + + This module contains the code to maintain an open handle data base for the + INSTALER program. This is used to track path names associated with open + handles so we can construct full paths from relative opens. + +Author: + + Steve Wood (stevewo) 11-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +char *HandleTypes[] = { + "File/Key", + "File", + "Key" +}; + +POPENHANDLE_INFO +FindOpenHandle( + PPROCESS_INFO Process, + HANDLE Handle, + ULONG Type + ) +{ + PLIST_ENTRY Next, Head; + POPENHANDLE_INFO p; + + Head = &Process->OpenHandleListHead; + Next = Head->Flink; + while (Next != Head) { + p = CONTAINING_RECORD( Next, OPENHANDLE_INFO, Entry ); + if (p->Handle == Handle && (Type == (ULONG)-1 || p->Type == Type)) { + return p; + } + + Next = Next->Flink; + } + + return NULL; +} + +BOOLEAN +AddOpenHandle( + PPROCESS_INFO Process, + HANDLE Handle, + ULONG Type, + PWSTR Name, + BOOLEAN InheritHandle + ) +{ + POPENHANDLE_INFO p; + + if (Type == (ULONG)-1) { + return FALSE; + } + + if (FindOpenHandle( Process, Handle, Type ) != NULL) { + return FALSE; + } + + p = AllocMem( sizeof( *p ) ); + if (p == NULL) { + return FALSE; + } + + p->Handle = Handle; + p->Type = (USHORT)Type; + p->Inherit = InheritHandle; + p->Name = Name; + p->LengthOfName = (USHORT)(wcslen( Name ) * sizeof( WCHAR )); + if (Type == HANDLE_TYPE_FILE && p->LengthOfName == (3 * sizeof( WCHAR ))) { + p->RootDirectory = TRUE; + } + + InsertHeadList( &Process->OpenHandleListHead, &p->Entry ); + + return TRUE; +} + + +BOOLEAN +DeleteOpenHandle( + PPROCESS_INFO Process, + HANDLE Handle, + ULONG Type + ) +{ + POPENHANDLE_INFO p; + + p = FindOpenHandle( Process, Handle, Type ); + if (p == NULL) { + // + // We will see lots of close calls for handles we dont care + // about. Ignore them quietly. + // + return FALSE; + } + + RemoveEntryList( &p->Entry ); + FreeMem( &p->QueryName ); + FreeMem( &p ); + return TRUE; +} + + +static BOOLEAN IgnoredFirstProcess = FALSE; + +VOID +InheritHandles( + PPROCESS_INFO Process + ) +{ + PPROCESS_INFO ParentProcess; + PLIST_ENTRY Prev, Head; + POPENHANDLE_INFO p; + + if (Process->ProcessInformation.InheritedFromUniqueProcessId == 0) { + return; + } + + ParentProcess = FindProcessById( Process->ProcessInformation.InheritedFromUniqueProcessId ); + if (ParentProcess == NULL) { + if (!IgnoredFirstProcess) { + IgnoredFirstProcess = TRUE; + } + else { + DbgEvent( INTERNALERROR, ("Unable to find parent process (%x)\n", Process->ProcessInformation.InheritedFromUniqueProcessId ) ); + } + + return; + } + + Head = &ParentProcess->OpenHandleListHead; + Prev = Head->Blink; + while (Prev != Head) { + p = CONTAINING_RECORD( Prev, OPENHANDLE_INFO, Entry ); + if (p->Inherit) { + if (!AddOpenHandle( Process, + p->Handle, + p->Type, + p->Name, + TRUE + ) + ) { + DbgEvent( INTERNALERROR, ("Unable to inherit %s handle (%x) for '%ws' from process (%x)\n", + HandleTypes[ 1+p->Type ], + p->Handle, + p->Name, + Process->ProcessInformation.InheritedFromUniqueProcessId + ) + ); + } + } + + Prev = Prev->Blink; + } + + return; +} diff --git a/private/sdktools/instaler/handler.c b/private/sdktools/instaler/handler.c new file mode 100644 index 000000000..f28754648 --- /dev/null +++ b/private/sdktools/instaler/handler.c @@ -0,0 +1,2355 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + handler.c + +Abstract: + + This module contains the individual API handler routines for the INSTALER program + +Author: + + Steve Wood (stevewo) 10-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" +#include <ntstatus.dbg> + + +BOOLEAN +HandleBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PBREAKPOINT_INFO Breakpoint + ) +{ + BOOLEAN Result; + API_SAVED_PARAMETERS SavedParameters; + UCHAR ApiIndex; + PBREAKPOINT_INFO ReturnBreakpoint; + + Result = FALSE; + ApiIndex = Breakpoint->ApiIndex; + if (ApiInfo[ ApiIndex ].ModuleIndex < Thread->ModuleIndexCurrentlyIn) { + return TRUE; + } + + DbgEvent( DBGEVENT, ( "Processing Breakpoint at %ws!%s\n", + Breakpoint->ModuleName, + Breakpoint->ProcedureName + ) + ); + + if (!Breakpoint->SavedParametersValid) { + memset( &SavedParameters, 0, sizeof( SavedParameters ) ); + + Result = TRUE; + if (ExtractProcedureParameters( Process, + Thread, + (PVOID)&SavedParameters.ReturnAddress, + ApiInfo[ ApiIndex ].SizeOfParameters, + (PULONG)&SavedParameters.InputParameters + ) + ) { + if (ApiInfo[ ApiIndex ].EntryPointHandler == NULL || + (ApiInfo[ ApiIndex ].EntryPointHandler)( Process, + Thread, + &SavedParameters + ) + ) { + if (SavedParameters.ReturnAddress == NULL) { + Result = FALSE; + } + else + if (CreateBreakpoint( SavedParameters.ReturnAddress, + Process, + Thread, // thread specific + ApiIndex, + &SavedParameters, + &ReturnBreakpoint + ) + ) { + ReturnBreakpoint->ModuleName = L"Return from"; + ReturnBreakpoint->ProcedureName = Breakpoint->ProcedureName; + Thread->ModuleIndexCurrentlyIn = ApiInfo[ ApiIndex ].ModuleIndex; + } + } + } + +#if DBG + TrimTemporaryBuffer(); +#endif + } + else { + if (UndoReturnAddressBreakpoint( Process, Thread ) && + ExtractProcedureReturnValue( Process, + Thread, + &Breakpoint->SavedParameters.ReturnValue, + ApiInfo[ ApiIndex ].SizeOfReturnValue + ) + ) { + Breakpoint->SavedParameters.ReturnValueValid = TRUE; + if (ApiInfo[ ApiIndex ].EntryPointHandler != NULL) { + (ApiInfo[ ApiIndex ].EntryPointHandler)( Process, + Thread, + &Breakpoint->SavedParameters + ); + } + } + + Thread->ModuleIndexCurrentlyIn = 0; + FreeSavedCallState( &Breakpoint->SavedParameters.SavedCallState ); + DestroyBreakpoint( Breakpoint->Address, Process, Thread ); +#if DBG + TrimTemporaryBuffer(); +#endif + Result = FALSE; + } + + return Result; +} + + +BOOLEAN +CreateSavedCallState( + PPROCESS_INFO Process, + PAPI_SAVED_CALL_STATE SavedCallState, + API_ACTION Action, + ULONG Type, + PWSTR FullName, + ... + ) +{ + va_list arglist; + + va_start( arglist, FullName ); + SavedCallState->Action = Action; + SavedCallState->Type = Type; + SavedCallState->FullName = FullName; + switch (Action) { + case OpenPath: + SavedCallState->PathOpen.InheritHandle = va_arg( arglist, BOOLEAN ); + SavedCallState->PathOpen.WriteAccessRequested = va_arg( arglist, BOOLEAN ); + SavedCallState->PathOpen.ResultHandleAddress = va_arg( arglist, PHANDLE ); + break; + + case RenamePath: + SavedCallState->PathRename.NewName = va_arg( arglist, PWSTR ); + SavedCallState->PathRename.ReplaceIfExists = va_arg( arglist, BOOLEAN ); + break; + + case DeletePath: + case QueryPath: + case SetValue: + case DeleteValue: + break; + + case WriteIniValue: + SavedCallState->SetIniValue.SectionName = va_arg( arglist, PWSTR ); + SavedCallState->SetIniValue.VariableName = va_arg( arglist, PWSTR ); + SavedCallState->SetIniValue.VariableValue = va_arg( arglist, PWSTR ); + break; + + case WriteIniSection: + SavedCallState->SetIniSection.SectionName = va_arg( arglist, PWSTR ); + SavedCallState->SetIniSection.SectionValue = va_arg( arglist, PWSTR ); + break; + + default: + return FALSE; + } + va_end( arglist ); + + return TRUE; +} + +VOID +FreeSavedCallState( + PAPI_SAVED_CALL_STATE CallState + ) +{ + switch (CallState->Action) { + case WriteIniValue: + FreeMem( &CallState->SetIniValue.VariableValue ); + break; + + case WriteIniSection: + FreeMem( &CallState->SetIniSection.SectionValue ); + break; + } + + return; +} + + + +BOOLEAN +CaptureObjectAttributes( + PPROCESS_INFO Process, + POBJECT_ATTRIBUTES ObjectAttributesAddress, + POBJECT_ATTRIBUTES ObjectAttributes, + PUNICODE_STRING ObjectName + ) +{ + if (ObjectAttributesAddress != NULL && + ReadMemory( Process, + ObjectAttributesAddress, + ObjectAttributes, + sizeof( *ObjectAttributes ), + "object attributes" + ) && + ObjectAttributes->ObjectName != NULL && + ReadMemory( Process, + ObjectAttributes->ObjectName, + ObjectName, + sizeof( *ObjectName ), + "object name string" + ) + ) { + return TRUE; + } + else { + return FALSE; + } +} + +BOOLEAN +CaptureFullName( + PPROCESS_INFO Process, + ULONG Type, + HANDLE RootDirectory, + PWSTR Name, + ULONG Length, + PWSTR *ReturnedFullName + ) +{ + POPENHANDLE_INFO HandleInfo; + UNICODE_STRING FullName; + ULONG LengthOfName; + PWSTR s; + BOOLEAN Result; + + *ReturnedFullName = NULL; + if (RootDirectory != NULL) { + HandleInfo = FindOpenHandle( Process, + RootDirectory, + Type + ); + if (HandleInfo == NULL) { + // + // If handle not found then we dont care about this open + // as it is relative to a device that is not local. + // + return FALSE; + } + } + else { + HandleInfo = NULL; + } + + LengthOfName = Length + sizeof( UNICODE_NULL ); + if (HandleInfo != NULL) { + LengthOfName += HandleInfo->LengthOfName + + sizeof( OBJ_NAME_PATH_SEPARATOR ); + } + + FullName.Buffer = AllocMem( LengthOfName ); + if (FullName.Buffer == NULL) { + return FALSE; + } + + s = FullName.Buffer; + if (HandleInfo != NULL) { + RtlMoveMemory( s, + HandleInfo->Name, + HandleInfo->LengthOfName + ); + s = &FullName.Buffer[ HandleInfo->LengthOfName / sizeof( WCHAR ) ]; + if (s[-1] != OBJ_NAME_PATH_SEPARATOR) { + *s++ = OBJ_NAME_PATH_SEPARATOR; + } + } + + if (!ReadMemory( Process, + Name, + s, + Length, + "object name buffer" + ) + ) { + FreeMem( &FullName.Buffer ); + return FALSE; + } + + s = &s[ Length / sizeof( WCHAR ) ]; + *s = UNICODE_NULL; + FullName.Length = (PCHAR)s - (PCHAR)FullName.Buffer; + FullName.MaximumLength = (USHORT)(FullName.Length + sizeof( UNICODE_NULL )); + if (HandleInfo == NULL && Type == HANDLE_TYPE_FILE) { + Result = IsDriveLetterPath( &FullName ); + } + else { + Result = TRUE; + } + *ReturnedFullName = AddName( &FullName ); + FreeMem( &FullName.Buffer ); + return Result; +} + + +BOOLEAN +CaptureOpenState( + PPROCESS_INFO Process, + PAPI_SAVED_PARAMETERS Parameters, + POBJECT_ATTRIBUTES ObjectAttributesAddress, + BOOLEAN WriteAccess, + PHANDLE ResultHandleAddress, + ULONG Type + ) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING ObjectName; + PWSTR FullName; + BOOLEAN Result; + + Result = FALSE; + if (CaptureObjectAttributes( Process, + ObjectAttributesAddress, + &ObjectAttributes, + &ObjectName + ) && + CaptureFullName( Process, + Type, + ObjectAttributes.RootDirectory, + ObjectName.Buffer, + ObjectName.Length, + &FullName + ) && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + OpenPath, + Type, + FullName, + (BOOLEAN)((ObjectAttributes.Attributes & OBJ_INHERIT) != 0), + WriteAccess, + ResultHandleAddress + ) + ) { + if (Type == HANDLE_TYPE_FILE) { + Result = CreateFileReference( FullName, + Parameters->SavedCallState.PathOpen.WriteAccessRequested, + (PFILE_REFERENCE *)&Parameters->SavedCallState.Reference + ); + } + else { + Result = CreateKeyReference( FullName, + Parameters->SavedCallState.PathOpen.WriteAccessRequested, + (PKEY_REFERENCE *)&Parameters->SavedCallState.Reference + ); + } + } + + return Result; +} + + +BOOLEAN +CompleteOpenState( + PPROCESS_INFO Process, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PAPI_SAVED_CALL_STATE p = &Parameters->SavedCallState; + HANDLE Handle; + BOOLEAN CallSuccessful; + PFILE_REFERENCE FileReference; + PKEY_REFERENCE KeyReference; + + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong ) && + ReadMemory( Process, + p->PathOpen.ResultHandleAddress, + &Handle, + sizeof( Handle ), + "result handle" + ) && + AddOpenHandle( Process, + Handle, + p->Type, + p->FullName, + p->PathOpen.InheritHandle + ) + ) { + CallSuccessful = TRUE; + } + else { + CallSuccessful = FALSE; + } + IncrementOpenCount( p->FullName, CallSuccessful ); + + if (p->Type == HANDLE_TYPE_FILE) { + FileReference = (PFILE_REFERENCE)p->Reference; + CompleteFileReference( FileReference, + CallSuccessful, + FALSE, + NULL + ); + } + else + if (p->Type == HANDLE_TYPE_KEY) { + KeyReference = (PKEY_REFERENCE)p->Reference; + CompleteKeyReference( (PKEY_REFERENCE)p->Reference, + CallSuccessful, + FALSE + ); + } + + return TRUE; +} + +#if TRACE_ENABLED + + +ENUM_TYPE_NAMES FileAccessNames[] = { + FILE_READ_DATA, "FILE_READ_DATA", + FILE_READ_DATA, "FILE_READ_DATA", + FILE_WRITE_DATA, "FILE_WRITE_DATA", + FILE_APPEND_DATA, "FILE_APPEND_DATA", + FILE_READ_EA, "FILE_READ_EA", + FILE_WRITE_EA, "FILE_WRITE_EA", + FILE_EXECUTE, "FILE_EXECUTE", + FILE_DELETE_CHILD, "FILE_DELETE_CHILD", + FILE_READ_ATTRIBUTES, "FILE_READ_ATTRIBUTES", + FILE_WRITE_ATTRIBUTES, "FILE_WRITE_ATTRIBUTES", + DELETE, "DELETE", + READ_CONTROL, "READ_CONTROL", + WRITE_DAC, "WRITE_DAC", + WRITE_OWNER, "WRITE_OWNER", + SYNCHRONIZE, "SYNCHRONIZE", + GENERIC_READ, "GENERIC_READ", + GENERIC_WRITE, "GENERIC_WRITE", + GENERIC_EXECUTE, "GENERIC_EXECUTE", + GENERIC_ALL, "GENERIC_ALL", + 0xFFFFFFFF, "%x" +}; + + +ENUM_TYPE_NAMES FileShareNames[] = { + FILE_SHARE_READ, "FILE_SHARE_READ", + FILE_SHARE_WRITE, "FILE_SHARE_WRITE", + FILE_SHARE_DELETE, "FILE_SHARE_DELETE", + 0xFFFFFFFF, "FILE_SHARE_NONE" +}; + +ENUM_TYPE_NAMES FileCreateDispositionNames[] = { + FILE_SUPERSEDE, "FILE_SUPERSEDE", + FILE_OPEN, "FILE_OPEN", + FILE_CREATE, "FILE_CREATE", + FILE_OPEN_IF, "FILE_OPEN_IF", + FILE_OVERWRITE, "FILE_OVERWRITE", + FILE_OVERWRITE_IF, "FILE_OVERWRITE_IF", + 0xFFFFFFFF, "%x" +}; + +ENUM_TYPE_NAMES FileCreateOptionNames[] = { + FILE_DIRECTORY_FILE, "FILE_DIRECTORY_FILE", + FILE_WRITE_THROUGH, "FILE_WRITE_THROUGH", + FILE_SEQUENTIAL_ONLY, "FILE_SEQUENTIAL_ONLY", + FILE_NO_INTERMEDIATE_BUFFERING, "FILE_NO_INTERMEDIATE_BUFFERING", + FILE_SYNCHRONOUS_IO_ALERT, "FILE_SYNCHRONOUS_IO_ALERT", + FILE_SYNCHRONOUS_IO_NONALERT, "FILE_SYNCHRONOUS_IO_NONALERT", + FILE_NON_DIRECTORY_FILE, "FILE_NON_DIRECTORY_FILE", + FILE_CREATE_TREE_CONNECTION, "FILE_CREATE_TREE_CONNECTION", + FILE_COMPLETE_IF_OPLOCKED, "FILE_COMPLETE_IF_OPLOCKED", + FILE_NO_EA_KNOWLEDGE, "FILE_NO_EA_KNOWLEDGE", + FILE_RANDOM_ACCESS, "FILE_RANDOM_ACCESS", + FILE_DELETE_ON_CLOSE, "FILE_DELETE_ON_CLOSE", + FILE_OPEN_BY_FILE_ID, "FILE_OPEN_BY_FILE_ID", + FILE_OPEN_FOR_BACKUP_INTENT, "FILE_OPEN_FOR_BACKUP_INTENT", + FILE_NO_COMPRESSION, "FILE_NO_COMPRESSION", + 0xFFFFFFFF, "%x" +}; + + +ENUM_TYPE_NAMES FileIoStatusInfoNames[] = { + FILE_SUPERSEDED, "FILE_SUPERSEDED", + FILE_OPENED, "FILE_OPENED", + FILE_CREATED, "FILE_CREATED", + FILE_OVERWRITTEN, "FILE_OVERWRITTEN", + FILE_EXISTS, "FILE_EXISTS", + FILE_DOES_NOT_EXIST, "FILE_DOES_NOT_EXIST", + 0xFFFFFFFF, "%x" +}; + + +ENUM_TYPE_NAMES SetFileInfoClassNames[] = { + FileDirectoryInformation, "FileDirectoryInformation", + FileFullDirectoryInformation, "FileFullDirectoryInformation", + FileBothDirectoryInformation, "FileBothDirectoryInformation", + FileBasicInformation, "FileBasicInformation", + FileStandardInformation, "FileStandardInformation", + FileInternalInformation, "FileInternalInformation", + FileEaInformation, "FileEaInformation", + FileAccessInformation, "FileAccessInformation", + FileNameInformation, "FileNameInformation", + FileRenameInformation, "FileRenameInformation", + FileLinkInformation, "FileLinkInformation", + FileNamesInformation, "FileNamesInformation", + FileDispositionInformation, "FileDispositionInformation", + FilePositionInformation, "FilePositionInformation", + FileFullEaInformation, "FileFullEaInformation", + FileModeInformation, "FileModeInformation", + FileAlignmentInformation, "FileAlignmentInformation", + FileAllInformation, "FileAllInformation", + FileAllocationInformation, "FileAllocationInformation", + FileEndOfFileInformation, "FileEndOfFileInformation", + FileAlternateNameInformation, "FileAlternateNameInformation", + FileStreamInformation, "FileStreamInformation", + FilePipeInformation, "FilePipeInformation", + FilePipeLocalInformation, "FilePipeLocalInformation", + FilePipeRemoteInformation, "FilePipeRemoteInformation", + FileMailslotQueryInformation, "FileMailslotQueryInformation", + FileMailslotSetInformation, "FileMailslotSetInformation", + FileCompressionInformation, "FileCompressionInformation", + FileCopyOnWriteInformation, "FileCopyOnWriteInformation", + FileCompletionInformation, "FileCompletionInformation", + FileMoveClusterInformation, "FileMoveClusterInformation", + 0xFFFFFFFF, "%x" +}; + +ENUM_TYPE_NAMES KeyCreateOptionNames[] = { + REG_OPTION_VOLATILE, "REG_OPTION_VOLATILE", + REG_OPTION_CREATE_LINK, "REG_OPTION_CREATE_LINK", + REG_OPTION_BACKUP_RESTORE, "REG_OPTION_BACKUP_RESTORE", + 0xFFFFFFFF, "%x" +}; + +ENUM_TYPE_NAMES KeyDispositionNames[] = { + REG_CREATED_NEW_KEY, "REG_CREATED_NEW_KEY", + REG_OPENED_EXISTING_KEY, "REG_OPENED_EXISTING_KEY", + 0xFFFFFFFF, "%x" +}; + + +#endif // TRACE_ENABLED + +BOOLEAN +IsFileWriteAccessRequested( + ACCESS_MASK DesiredAccess, + ULONG CreateDisposition + ) +{ + if (DesiredAccess & (GENERIC_WRITE | + GENERIC_ALL | + DELETE | + FILE_WRITE_DATA | + FILE_APPEND_DATA + ) + ) { + return TRUE; + } + + if (CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +NtCreateFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PCREATEFILE_PARAMETERS p = &Parameters->InputParameters.CreateFile; + BOOLEAN Result; + + if (!Parameters->ReturnValueValid) { + Result = CaptureOpenState( Process, + Parameters, + p->ObjectAttributes, + IsFileWriteAccessRequested( p->DesiredAccess, p->CreateDisposition ), + p->FileHandle, + HANDLE_TYPE_FILE + ); + + + if (Result + // && Parameters->SavedCallState.PathOpen.WriteAccessRequested + ) { + DbgEvent( CREATEEVENT, ( "NtCreateFile called:\n" + " Name: %ws\n" + " Access: %s\n" + " Share: %s\n" + " Create: %s\n" + " Options:%s\n", + Parameters->SavedCallState.FullName, + FormatEnumType( 0, + FileAccessNames, + p->DesiredAccess, + TRUE + ), + FormatEnumType( 1, + FileShareNames, + p->ShareAccess, + TRUE + ), + FormatEnumType( 2, + FileCreateDispositionNames, + p->CreateDisposition, + FALSE + ), + FormatEnumType( 3, + FileCreateOptionNames, + p->CreateOptions, + TRUE + ) + ) + ); + } + } + else { + Result = CompleteOpenState( Process, + Parameters + ); + if (Result + // && Parameters->SavedCallState.PathOpen.WriteAccessRequested + ) { + IO_STATUS_BLOCK IoStatusBlock; + + ReadMemory( Process, + p->IoStatusBlock, + &IoStatusBlock, + sizeof( IoStatusBlock ), + "IoStatusBlock" + ); + DbgEvent( CREATEEVENT, ( "*** Returned %s [%s %s]\n", + FormatEnumType( 0, + (PENUM_TYPE_NAMES)ntstatusSymbolicNames, + Parameters->ReturnValue.ReturnedLong, + FALSE + ), + FormatEnumType( 1, + (PENUM_TYPE_NAMES)ntstatusSymbolicNames, + IoStatusBlock.Status, + FALSE + ), + FormatEnumType( 2, + FileIoStatusInfoNames, + IoStatusBlock.Information, + FALSE + ) + ) + ); + } + } + + return Result; +} + +BOOLEAN +NtOpenFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + POPENFILE_PARAMETERS p = &Parameters->InputParameters.OpenFile; + BOOLEAN Result; + + if (!Parameters->ReturnValueValid) { + Result = CaptureOpenState( Process, + Parameters, + p->ObjectAttributes, + IsFileWriteAccessRequested( p->DesiredAccess, FILE_OPEN ), + p->FileHandle, + HANDLE_TYPE_FILE + ); + if (Result + // && Parameters->SavedCallState.PathOpen.WriteAccessRequested + ) { + DbgEvent( CREATEEVENT, ( "NtOpenFile called:\n" + " Name: %ws\n" + " Access: %s\n" + " Share: %s\n" + " Options:%s\n", + Parameters->SavedCallState.FullName, + FormatEnumType( 0, + FileAccessNames, + p->DesiredAccess, + TRUE + ), + FormatEnumType( 1, + FileShareNames, + p->ShareAccess, + TRUE + ), + FormatEnumType( 2, + FileCreateOptionNames, + p->OpenOptions, + TRUE + ) + ) + ); + } + } + else { + Result = CompleteOpenState( Process, + Parameters + ); + if (Result + // && Parameters->SavedCallState.PathOpen.WriteAccessRequested + ) { + IO_STATUS_BLOCK IoStatusBlock; + + ReadMemory( Process, + p->IoStatusBlock, + &IoStatusBlock, + sizeof( IoStatusBlock ), + "IoStatusBlock" + ); + DbgEvent( CREATEEVENT, ( "*** Returned %s [%s %s]\n", + FormatEnumType( 0, + (PENUM_TYPE_NAMES)ntstatusSymbolicNames, + Parameters->ReturnValue.ReturnedLong, + FALSE + ), + FormatEnumType( 1, + (PENUM_TYPE_NAMES)ntstatusSymbolicNames, + IoStatusBlock.Status, + FALSE + ), + FormatEnumType( 2, + FileIoStatusInfoNames, + IoStatusBlock.Information, + FALSE + ) + ) + ); + } + } + + return Result; +} + +BOOLEAN +NtDeleteFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PDELETEFILE_PARAMETERS p = &Parameters->InputParameters.DeleteFile; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING ObjectName; + PWSTR FullName; + BOOLEAN Result, CallSuccessful; + PFILE_REFERENCE FileReference; + + if (!Parameters->ReturnValueValid) { + if (CaptureObjectAttributes( Process, + p->ObjectAttributes, + &ObjectAttributes, + &ObjectName + ) && + CaptureFullName( Process, + HANDLE_TYPE_FILE, + ObjectAttributes.RootDirectory, + ObjectName.Buffer, + ObjectName.Length, + &FullName + ) && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + DeletePath, + HANDLE_TYPE_FILE, + FullName + ) + ) { + Result = CreateFileReference( FullName, + TRUE, + (PFILE_REFERENCE *)&Parameters->SavedCallState.Reference + ); + } + else { + Result = FALSE; + } + + return Result; + } + else { + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong )) { + CallSuccessful = TRUE; + } + else { + CallSuccessful = FALSE; + } + + FileReference = (PFILE_REFERENCE)Parameters->SavedCallState.Reference; + CompleteFileReference( FileReference, + CallSuccessful, + TRUE, + NULL + ); + + return TRUE; + } +} + +#undef DeleteFile + + +BOOLEAN +NtSetInformationFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PSETINFORMATIONFILE_PARAMETERS p = &Parameters->InputParameters.SetInformationFile; + POPENHANDLE_INFO HandleInfo; + FILE_RENAME_INFORMATION RenameInformation; + FILE_DISPOSITION_INFORMATION DispositionInformation; + PWSTR NewName, OldName; + PFILE_REFERENCE OldFileReference; + PFILE_REFERENCE NewFileReference; + BOOLEAN Result, CallSuccessful; + + HandleInfo = FindOpenHandle( Process, + p->FileHandle, + HANDLE_TYPE_FILE + ); + if (HandleInfo == NULL) { + Result = FALSE; + } + else + if (p->FileInformationClass == FileRenameInformation) { + // + // Renaming an open file. + // + if (!Parameters->ReturnValueValid) { + if (ReadMemory( Process, + p->FileInformation, + &RenameInformation, + FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName ), + "rename information" + ) && + CaptureFullName( Process, + HANDLE_TYPE_FILE, + RenameInformation.RootDirectory, + &((PFILE_RENAME_INFORMATION)(p->FileInformation))->FileName[ 0 ], + RenameInformation.FileNameLength, + &NewName + ) && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + RenamePath, + HANDLE_TYPE_FILE, + HandleInfo->Name, + NewName, + RenameInformation.ReplaceIfExists + ) + ) { + Result = CreateFileReference( NewName, + RenameInformation.ReplaceIfExists, + (PFILE_REFERENCE *)&Parameters->SavedCallState.Reference + ); + } + else { + Result = FALSE; + } + } + else { + OldName = NULL; + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong )) { + CallSuccessful = TRUE; + OldFileReference = FindFileReference( HandleInfo->Name ); + if (OldFileReference) { + OldName = OldFileReference->Name; + } + } + else { + CallSuccessful = FALSE; + OldFileReference = NULL; + } + + NewFileReference = (PFILE_REFERENCE)Parameters->SavedCallState.Reference; + NewName = NewFileReference->Name; + CompleteFileReference( NewFileReference, + CallSuccessful, + (BOOLEAN)(!NewFileReference->Created), + OldFileReference + ); + Result = TRUE; + } + } + else + if (p->FileInformationClass == FileDispositionInformation) { + // + // Marking an open file for delete. + // + if (!Parameters->ReturnValueValid) { + if (ReadMemory( Process, + p->FileInformation, + &DispositionInformation, + sizeof( DispositionInformation ), + "disposition information" + ) && + DispositionInformation.DeleteFile && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + DeletePath, + HANDLE_TYPE_FILE, + HandleInfo->Name + ) + ) { + Result = TRUE; + } + else { + Result = FALSE; + } + } + else { + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong )) { + if (OldFileReference = FindFileReference( HandleInfo->Name )) { + if (OldFileReference->Created) { + LogEvent( INSTALER_EVENT_DELETE_TEMP_FILE, + 2, + OldFileReference->DirectoryFile ? L"directory" : L"file", + OldFileReference->Name + ); + DestroyFileReference( OldFileReference ); + } + else { + OldFileReference->Deleted = TRUE; + LogEvent( INSTALER_EVENT_DELETE_FILE, + 2, + OldFileReference->DirectoryFile ? L"directory" : L"file", + OldFileReference->Name + ); + } + } + } + + Result = TRUE; + } + } + else { + Result = FALSE; + } + + return Result; +} + + + + +BOOLEAN +CaptureUnicodeString( + PPROCESS_INFO Process, + PUNICODE_STRING UnicodeStringAddress, + PWSTR *ReturnedString + ) +{ + UNICODE_STRING UnicodeString; + PWSTR s; + + s = NULL; + if (ReadMemory( Process, + UnicodeStringAddress, + &UnicodeString, + sizeof( UnicodeString ), + "unicode string" + ) && + ((s = AllocMem( UnicodeString.Length + sizeof( UNICODE_NULL ) )) != NULL) && + ReadMemory( Process, + UnicodeString.Buffer, + s, + UnicodeString.Length, + "unicode string buffer" + ) + ) { + *ReturnedString = s; + return TRUE; + } + + FreeMem( &s ); + return FALSE; +} + + +BOOLEAN +NtQueryAttributesFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PQUERYATTRIBUTESFILE_PARAMETERS p = &Parameters->InputParameters.QueryAttributesFile; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING ObjectName; + PWSTR FullName; + NTSTATUS Status; + BOOLEAN Result; + CHAR Buffer[ MAX_PATH ]; + + if (!Parameters->ReturnValueValid) { + FullName = NULL; + Result = FALSE; + if (CaptureObjectAttributes( Process, + p->ObjectAttributes, + &ObjectAttributes, + &ObjectName + ) && + CaptureFullName( Process, + HANDLE_TYPE_FILE, + ObjectAttributes.RootDirectory, + ObjectName.Buffer, + ObjectName.Length, + &FullName + ) && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + QueryPath, + HANDLE_TYPE_FILE, + FullName + ) + ) { + Result = CreateFileReference( FullName, + FALSE, + (PFILE_REFERENCE *)&Parameters->SavedCallState.Reference + ); + } + else { + Result = FALSE; + } + + return Result; + } + else { + FILE_BASIC_INFORMATION FileInformation; + + ReadMemory( Process, + p->FileInformation, + &FileInformation, + sizeof( FileInformation ), + "FileInformation" + ); + return TRUE; + } +} + +BOOLEAN +NtQueryDirectoryFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PQUERYDIRECTORYFILE_PARAMETERS p = &Parameters->InputParameters.QueryDirectoryFile; + POPENHANDLE_INFO HandleInfo; + PWSTR FileName; + NTSTATUS Status; + BOOLEAN Result; + PULONG pNextEntryOffset; + ULONG NextEntryOffset; + ULONG EntriesReturned; + + if (!Parameters->ReturnValueValid) { + FileName = NULL; + Result = FALSE; + if ((HandleInfo = FindOpenHandle( Process, + p->FileHandle, + HANDLE_TYPE_FILE + ) + ) != NULL && + p->FileName != NULL && + CaptureUnicodeString( Process, + p->FileName, + &FileName + ) + ) { + if (HandleInfo->RootDirectory && + !wcscmp( FileName, L"*" ) || !wcscmp( FileName, L"*.*" ) + ) { + if (AskUserOnce) { + AskUserOnce = FALSE; + if (AskUser( MB_OKCANCEL, + INSTALER_ASKUSER_ROOTSCAN, + 1, + HandleInfo->Name + ) == IDCANCEL + ) { + FailAllScansOfRootDirectories = TRUE; + } + } + + Parameters->AbortCall = FailAllScansOfRootDirectories; + } + + if (FileName) { + HandleInfo->QueryName = FileName; + } + } + + return TRUE; + } + else { + if (Parameters->AbortCall) { + // + // If we get here, then user wanted to fail this call. + // + Status = STATUS_NO_MORE_FILES; + SetProcedureReturnValue( Process, + Thread, + &Status, + sizeof( Status ) + ); + return TRUE; + } + else { + if ((HandleInfo = FindOpenHandle( Process, + p->FileHandle, + HANDLE_TYPE_FILE + ) + ) != NULL + ) { + // + // If successful, count entries returned + // + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong )) { + // + // Return buffer is a set of records, the first DWORD of each contains + // the offset to the next one or zero to indicate the end. Count them. + // + pNextEntryOffset = (PULONG)p->FileInformation; + EntriesReturned = 1; + while (ReadMemory( Process, + pNextEntryOffset, + &NextEntryOffset, + sizeof( NextEntryOffset ), + "DirectoryInformation" + ) && + NextEntryOffset != 0 + ) { + pNextEntryOffset = (PULONG)((PCHAR)pNextEntryOffset + NextEntryOffset); + EntriesReturned += 1; + } + + LogEvent( INSTALER_EVENT_SCAN_DIRECTORY, + 3, + HandleInfo->Name, + HandleInfo->QueryName ? HandleInfo->QueryName : L"*", + EntriesReturned + ); + + } + else { + FreeMem( &HandleInfo->QueryName ); + } + } + } + + return TRUE; + } +} + + +BOOLEAN +IsKeyWriteAccessRequested( + ACCESS_MASK DesiredAccess + ) +{ + if (DesiredAccess & (GENERIC_WRITE | + GENERIC_ALL | + DELETE | + KEY_SET_VALUE | + KEY_CREATE_SUB_KEY | + KEY_CREATE_LINK + ) + ) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +NtCreateKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PCREATEKEY_PARAMETERS p = &Parameters->InputParameters.CreateKey; + BOOLEAN Result; + + if (!Parameters->ReturnValueValid) { + Result = CaptureOpenState( Process, + Parameters, + p->ObjectAttributes, + IsKeyWriteAccessRequested( p->DesiredAccess ), + p->KeyHandle, + HANDLE_TYPE_KEY + ); + } + else { + Result = CompleteOpenState( Process, + Parameters + ); + } + + return Result; +} + +BOOLEAN +NtOpenKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + POPENKEY_PARAMETERS p = &Parameters->InputParameters.OpenKey; + BOOLEAN Result; + + if (!Parameters->ReturnValueValid) { + Result = CaptureOpenState( Process, + Parameters, + p->ObjectAttributes, + IsKeyWriteAccessRequested( p->DesiredAccess ), + p->KeyHandle, + HANDLE_TYPE_KEY + ); + } + else { + Result = CompleteOpenState( Process, + Parameters + ); + } + + return Result; +} + +BOOLEAN +NtDeleteKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PDELETEKEY_PARAMETERS p = &Parameters->InputParameters.DeleteKey; + POPENHANDLE_INFO HandleInfo; + PKEY_REFERENCE OldKeyReference; + BOOLEAN Result; + + // + // Marking an open key for delete. + // + HandleInfo = FindOpenHandle( Process, + p->KeyHandle, + HANDLE_TYPE_KEY + ); + if (HandleInfo == NULL) { + Result = FALSE; + } + else + if (!Parameters->ReturnValueValid) { + if (CreateSavedCallState( Process, + &Parameters->SavedCallState, + DeletePath, + HANDLE_TYPE_KEY, + HandleInfo->Name + ) + ) { + Result = TRUE; + } + else { + Result = FALSE; + } + } + else { + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong )) { + if (OldKeyReference = FindKeyReference( HandleInfo->Name )) { + if (OldKeyReference->Created) { + LogEvent( INSTALER_EVENT_DELETE_TEMP_KEY, + 1, + OldKeyReference->Name + ); + DestroyKeyReference( OldKeyReference ); + } + else { + MarkKeyDeleted( OldKeyReference ); + LogEvent( INSTALER_EVENT_DELETE_KEY, + 1, + OldKeyReference->Name + ); + } + } + } + + Result = TRUE; + } + + return Result; +} + +BOOLEAN +CaptureValueName( + PPROCESS_INFO Process, + PUNICODE_STRING Name, + PWSTR *ReturnedValueName + ) +{ + UNICODE_STRING ValueName; + PWSTR s; + + *ReturnedValueName = NULL; + if (Name == NULL || + !ReadMemory( Process, + Name, + &ValueName, + sizeof( ValueName ), + "value name string" + ) + ) { + return FALSE; + } + + s = AllocMem( ValueName.Length + sizeof( UNICODE_NULL ) ); + if (s == NULL) { + return FALSE; + } + + if (!ReadMemory( Process, + ValueName.Buffer, + s, + ValueName.Length, + "value name buffer" + ) + ) { + FreeMem( &s ); + return FALSE; + } + + s[ ValueName.Length / sizeof( WCHAR ) ] = UNICODE_NULL; + ValueName.Buffer = s; + ValueName.MaximumLength = (USHORT)(ValueName.Length + sizeof( UNICODE_NULL )); + *ReturnedValueName = AddName( &ValueName ); + FreeMem( &ValueName.Buffer ); + return TRUE; +} + + +BOOLEAN +NtSetValueKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PSETVALUEKEY_PARAMETERS p = &Parameters->InputParameters.SetValueKey; + POPENHANDLE_INFO HandleInfo; + PWSTR ValueName; + PKEY_REFERENCE KeyReference; + PVALUE_REFERENCE ValueReference; + BOOLEAN Result; + + // + // Setting a value + // + HandleInfo = FindOpenHandle( Process, + p->KeyHandle, + HANDLE_TYPE_KEY + ); + if (HandleInfo == NULL) { + Result = FALSE; + } + else + if (!Parameters->ReturnValueValid) { + if (CaptureValueName( Process, + p->ValueName, + &ValueName + ) && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + SetValue, + HANDLE_TYPE_KEY, + ValueName + ) + ) { + Result = TRUE; + } + else { + Result = FALSE; + } + } + else { + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong ) && + (KeyReference = FindKeyReference( HandleInfo->Name )) + ) { + CreateValueReference( Process, + KeyReference, + Parameters->SavedCallState.FullName, + p->TitleIndex, + p->Type, + p->Data, + p->DataLength, + &ValueReference + ); + + if (ValueReference != NULL) { + LogEvent( INSTALER_EVENT_SET_KEY_VALUE, + 2, + ValueReference->Name, + KeyReference->Name + ); + } + } + + Result = TRUE; + } + + return Result; +} + +BOOLEAN +NtDeleteValueKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PDELETEVALUEKEY_PARAMETERS p = &Parameters->InputParameters.DeleteValueKey; + POPENHANDLE_INFO HandleInfo; + PWSTR ValueName; + PKEY_REFERENCE KeyReference; + PVALUE_REFERENCE ValueReference; + BOOLEAN Result; + + // + // Marking a value for delete. + // + HandleInfo = FindOpenHandle( Process, + p->KeyHandle, + HANDLE_TYPE_KEY + ); + if (HandleInfo == NULL) { + Result = FALSE; + } + else + if (!Parameters->ReturnValueValid) { + if (CaptureValueName( Process, + p->ValueName, + &ValueName + ) && + CreateSavedCallState( Process, + &Parameters->SavedCallState, + DeleteValue, + HANDLE_TYPE_KEY, + ValueName + ) + ) { + Result = TRUE; + } + else { + Result = FALSE; + } + } + else { + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong ) && + (KeyReference = FindKeyReference( HandleInfo->Name )) && + (ValueReference = FindValueReference( KeyReference, Parameters->SavedCallState.FullName )) + ) { + if (ValueReference->Created) { + LogEvent( INSTALER_EVENT_DELETE_KEY_TEMP_VALUE, + 2, + ValueReference->Name, + KeyReference->Name + ); + DestroyValueReference( ValueReference ); + } + else { + ValueReference->Deleted = TRUE; + LogEvent( INSTALER_EVENT_DELETE_KEY_VALUE, + 2, + ValueReference->Name, + KeyReference->Name + ); + } + } + + Result = TRUE; + } + + return Result; +} + + +BOOLEAN +NtCloseHandleHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PCLOSEHANDLE_PARAMETERS p = &Parameters->InputParameters.CloseHandle; + POPENHANDLE_INFO HandleInfo; + PFILE_REFERENCE FileReference; + + HandleInfo = FindOpenHandle( Process, p->Handle, (ULONG)-1 ); + if (!Parameters->ReturnValueValid) { + if (HandleInfo != NULL) { + return TRUE; + } + else { + return FALSE; + } + } + else { + if (NT_SUCCESS( Parameters->ReturnValue.ReturnedLong )) { + if (HandleInfo != NULL && + HandleInfo->Type == HANDLE_TYPE_FILE && + (FileReference = FindFileReference( HandleInfo->Name )) != NULL && + FileReference->WriteAccess && + !FileReference->Created && + !FileReference->DirectoryFile && + IsNewFileSameAsBackup( FileReference ) + ) { + DestroyFileReference( FileReference ); + FileReference = NULL; + } + + DeleteOpenHandle( Process, p->Handle, (ULONG)-1 ); + } + + return TRUE; + } +} + +UCHAR AnsiStringBuffer[ MAX_PATH+1 ]; +WCHAR UnicodeStringBuffer[ MAX_PATH+1 ]; + +BOOLEAN +CaptureAnsiAsUnicode( + PPROCESS_INFO Process, + LPCSTR Address, + BOOLEAN DoubleNullTermination, + PWSTR *ReturnedName, + PWSTR *ReturnedData + ) +{ + NTSTATUS Status; + ULONG BytesRead; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + + if (Address == NULL) { + if (ReturnedName != NULL) { + *ReturnedName = NULL; + } + else { + *ReturnedData = NULL; + } + return TRUE; + } + + BytesRead = FillTemporaryBuffer( Process, + (PVOID)Address, + FALSE, + DoubleNullTermination + ); + if (BytesRead != 0 && BytesRead < 0x7FFF) { + AnsiString.Buffer = TemporaryBuffer; + AnsiString.Length = (USHORT)BytesRead; + AnsiString.MaximumLength = (USHORT)BytesRead; + Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE ); + if (NT_SUCCESS( Status )) { + if (ReturnedName != NULL) { + *ReturnedName = AddName( &UnicodeString ); + RtlFreeUnicodeString( &UnicodeString ); + return TRUE; + } + else { + *ReturnedData = UnicodeString.Buffer; + return TRUE; + } + } + } + + return FALSE; +} + + +BOOLEAN +CaptureUnicode( + PPROCESS_INFO Process, + LPCWSTR Address, + BOOLEAN DoubleNullTermination, + PWSTR *ReturnedName, + PWSTR *ReturnedData + ) +{ + ULONG BytesRead; + UNICODE_STRING UnicodeString; + + if (Address == NULL) { + if (ReturnedName != NULL) { + *ReturnedName = NULL; + } + else { + *ReturnedData = NULL; + } + return TRUE; + } + + BytesRead = FillTemporaryBuffer( Process, + (PVOID)Address, + TRUE, + DoubleNullTermination + ); + if (BytesRead != 0 && (BytesRead & 1) == 0 && BytesRead <= 0xFFFC) { + if (ReturnedName != NULL) { + RtlInitUnicodeString( &UnicodeString, TemporaryBuffer ); + *ReturnedName = AddName( &UnicodeString ); + return TRUE; + } + else { + *ReturnedData = AllocMem( BytesRead + sizeof( UNICODE_NULL ) ); + if (*ReturnedData != NULL) { + memmove( *ReturnedData, TemporaryBuffer, BytesRead ); + return TRUE; + } + } + } + + return FALSE; +} + + +BOOLEAN +GetVersionHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + DWORD dwVersion; + + if (!Parameters->ReturnValueValid) { + if (AskUserOnce) { + AskUserOnce = FALSE; + if (AskUser( MB_OKCANCEL, + INSTALER_ASKUSER_GETVERSION, + 0 + ) == IDCANCEL + ) { + DefaultGetVersionToWin95 = TRUE; + } + else { + DefaultGetVersionToWin95 = FALSE; + } + } + + LogEvent( INSTALER_EVENT_GETVERSION, + 1, + DefaultGetVersionToWin95 ? L"Windows 95" : L"Windows NT" + ); + Parameters->AbortCall = DefaultGetVersionToWin95; + return Parameters->AbortCall; + } + else { + dwVersion = 0xC0000004; // What Windows 95 returns + SetProcedureReturnValue( Process, + Thread, + &dwVersion, + sizeof( dwVersion ) + ); + return TRUE; + } +} + +BOOLEAN +GetVersionExWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PGETVERSIONEXW_PARAMETERS p = &Parameters->InputParameters.GetVersionExW; + OSVERSIONINFOW VersionInformation; + + if (!Parameters->ReturnValueValid) { + if (AskUserOnce) { + AskUserOnce = FALSE; + if (AskUser( MB_OKCANCEL, + INSTALER_ASKUSER_GETVERSION, + 0 + ) == IDCANCEL + ) { + DefaultGetVersionToWin95 = TRUE; + } + else { + DefaultGetVersionToWin95 = FALSE; + } + } + + Parameters->AbortCall = DefaultGetVersionToWin95; + return Parameters->AbortCall; + } + else { + memset( &VersionInformation, 0, sizeof( VersionInformation ) ); + VersionInformation.dwMajorVersion = 4; + VersionInformation.dwBuildNumber = 0x3B6; // What Windows 95 returns + VersionInformation.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + WriteMemory( Process, + p->lpVersionInformation, + &VersionInformation, + sizeof( VersionInformation ), + "GetVersionExW" + ); + + return TRUE; + } +} + +BOOLEAN +SetCurrentDirectoryAHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PSETCURRENTDIRECTORYA_PARAMETERS p = &Parameters->InputParameters.SetCurrentDirectoryA; + PWSTR PathName; + WCHAR PathBuffer[ MAX_PATH ]; + + if (!Parameters->ReturnValueValid) { + if (CaptureAnsiAsUnicode( Process, p->lpPathName, FALSE, NULL, &PathName )) { + Parameters->CurrentDirectory = AllocMem( (wcslen( PathName ) + 1) * sizeof( WCHAR ) ); + if (Parameters->CurrentDirectory != NULL) { + wcscpy( Parameters->CurrentDirectory, PathName ); + return TRUE; + } + } + + return FALSE; + } + else { + if (Parameters->ReturnValue.ReturnedBool != 0) { + if (SetCurrentDirectory( Parameters->CurrentDirectory ) && + GetCurrentDirectory( MAX_PATH, PathBuffer ) + ) { + LogEvent( INSTALER_EVENT_SET_DIRECTORY, + 1, + PathBuffer + ); + } + } + + FreeMem( &Parameters->CurrentDirectory ); + return TRUE; + } +} + +BOOLEAN +SetCurrentDirectoryWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PSETCURRENTDIRECTORYW_PARAMETERS p = &Parameters->InputParameters.SetCurrentDirectoryW; + PWSTR PathName; + WCHAR PathBuffer[ MAX_PATH ]; + + if (!Parameters->ReturnValueValid) { + if (CaptureUnicode( Process, p->lpPathName, FALSE, NULL, &PathName )) { + Parameters->CurrentDirectory = AllocMem( (wcslen( PathName ) + 1) * sizeof( WCHAR ) ); + if (Parameters->CurrentDirectory != NULL) { + wcscpy( Parameters->CurrentDirectory, PathName ); + return TRUE; + } + } + + return FALSE; + } + else { + if (Parameters->ReturnValue.ReturnedBool != 0) { + if (SetCurrentDirectory( Parameters->CurrentDirectory ) && + GetCurrentDirectory( MAX_PATH, PathBuffer ) + ) { + LogEvent( INSTALER_EVENT_SET_DIRECTORY, + 1, + PathBuffer + ); + } + } + + FreeMem( &Parameters->CurrentDirectory ); + return TRUE; + } +} + +BOOLEAN +GetIniFilePath( + PWSTR IniFileName, + PWSTR *ReturnedIniFilePath + ) +{ + NTSTATUS Status; + UNICODE_STRING FileName, UnicodeString; + PWSTR FilePart; + DWORD n; + + if (IniFileName == NULL) { + RtlInitUnicodeString( &FileName, L"win.ini" ); + } + else { + RtlInitUnicodeString( &FileName, IniFileName ); + } + + if ((FileName.Length > sizeof( WCHAR ) && + FileName.Buffer[ 1 ] == L':' + ) || + (FileName.Length != 0 && + wcscspn( FileName.Buffer, L"\\/" ) != (FileName.Length / sizeof( WCHAR )) + ) + ) { + UnicodeString.MaximumLength = (USHORT)(MAX_PATH * sizeof( WCHAR )); + UnicodeString.Buffer = AllocMem( UnicodeString.MaximumLength ); + if (UnicodeString.Buffer == NULL) { + Status = STATUS_NO_MEMORY; + } + else { + UnicodeString.Length = 0; + n = GetFullPathNameW( FileName.Buffer, + UnicodeString.MaximumLength / sizeof( WCHAR ), + UnicodeString.Buffer, + &FilePart + ); + if (n > UnicodeString.MaximumLength) { + Status = STATUS_BUFFER_TOO_SMALL; + } + else { + UnicodeString.Length = (USHORT)(n * sizeof( WCHAR )); + Status = STATUS_SUCCESS; + } + } + } + else { + UnicodeString.Length = 0; + UnicodeString.MaximumLength = (USHORT)(WindowsDirectory.Length + + sizeof( WCHAR ) + + FileName.Length + + sizeof( UNICODE_NULL ) + ); + UnicodeString.Buffer = AllocMem( UnicodeString.MaximumLength ); + if (UnicodeString.Buffer == NULL) { + Status = STATUS_NO_MEMORY; + } + else { + RtlCopyUnicodeString( &UnicodeString, &WindowsDirectory ); + Status = RtlAppendUnicodeToString( &UnicodeString, + L"\\" + ); + if (NT_SUCCESS( Status )) { + Status = RtlAppendUnicodeStringToString( &UnicodeString, + &FileName + ); + } + } + } + + if (IniFileName != NULL) { + FreeMem( &IniFileName ); + } + + if (NT_SUCCESS( Status )) { + *ReturnedIniFilePath = AddName( &UnicodeString ); + FreeMem( &UnicodeString.Buffer ); + return TRUE; + } + else { + FreeMem( &UnicodeString.Buffer ); + return FALSE; + } +} + +BOOLEAN +WritePrivateProfileStringEntry( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters, + PWSTR IniFilePath, + PWSTR SectionName, + PWSTR VariableName, + PWSTR VariableValue + ) +{ + if (CreateSavedCallState( Process, + &Parameters->SavedCallState, + WriteIniValue, + HANDLE_TYPE_NONE, + IniFilePath, + SectionName, + VariableName, + VariableValue + ) && + CreateIniFileReference( IniFilePath, + (PINI_FILE_REFERENCE *)&Parameters->SavedCallState.Reference + ) + ) { + return TRUE; + } + else { + FreeMem( &VariableValue ); + return FALSE; + } +} + + +BOOLEAN +WritePrivateProfileStringExit( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PAPI_SAVED_CALL_STATE CallState; + PINI_FILE_REFERENCE IniFileReference; + PINI_SECTION_REFERENCE IniSectionReference; + PINI_VARIABLE_REFERENCE IniVariableReference; + + if (Parameters->ReturnValue.ReturnedLong != 0) { + CallState = &Parameters->SavedCallState; + if (CallState->FullName == NULL && + CallState->SetIniValue.SectionName == NULL && + CallState->SetIniValue.VariableName == NULL + ) { + // + // Ignore calls to flush INI cache + // + + return FALSE; + } + + IniFileReference = FindIniFileReference( CallState->FullName ); + IniSectionReference = FindIniSectionReference( IniFileReference, + CallState->SetIniValue.SectionName, + (BOOLEAN)(CallState->SetIniValue.VariableName != NULL) + ); + if (IniSectionReference != NULL) { + if (CallState->SetIniValue.VariableName == NULL) { + IniSectionReference->Deleted = TRUE; + LogEvent( INSTALER_EVENT_INI_DELETE_SECTION, + 2, + CallState->FullName, + CallState->SetIniValue.SectionName + ); + } + else { + IniVariableReference = FindIniVariableReference( IniSectionReference, + CallState->SetIniValue.VariableName, + (BOOLEAN)(CallState->SetIniValue.VariableValue != NULL) + ); + if (IniVariableReference != NULL) { + if (CallState->SetIniValue.VariableValue != NULL) { + FreeMem( &IniVariableReference->Value ); + IniVariableReference->Value = CallState->SetIniValue.VariableValue; + CallState->SetIniValue.VariableValue = NULL; + if (!IniVariableReference->Created) { + if (!wcscmp( IniVariableReference->Value, + IniVariableReference->OriginalValue + ) + ) { + FreeMem( &IniVariableReference->Value ); + } + else { + IniVariableReference->Modified = TRUE; + LogEvent( INSTALER_EVENT_INI_CHANGE, + 5, + CallState->FullName, + CallState->SetIniValue.SectionName, + CallState->SetIniValue.VariableName, + IniVariableReference->Value, + IniVariableReference->OriginalValue + ); + } + } + else { + LogEvent( INSTALER_EVENT_INI_CREATE, + 4, + CallState->FullName, + CallState->SetIniValue.SectionName, + CallState->SetIniValue.VariableName, + IniVariableReference->Value + ); + } + } + else + if (!IniVariableReference->Created) { + IniVariableReference->Deleted = TRUE; + LogEvent( INSTALER_EVENT_INI_DELETE, + 4, + CallState->FullName, + CallState->SetIniValue.SectionName, + CallState->SetIniValue.VariableName, + IniVariableReference->OriginalValue + ); + } + else { + DestroyIniVariableReference( IniVariableReference ); + } + } + } + } + } + + return TRUE; +} + + +BOOLEAN +WritePrivateProfileStringAHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PWRITEPRIVATEPROFILESTRINGA_PARAMETERS p = &Parameters->InputParameters.WritePrivateProfileStringA; + PWSTR SectionName, VariableName, FileName, VariableValue; + PWSTR IniFilePath; + + if (!Parameters->ReturnValueValid) { + FileName = NULL; + VariableValue = NULL; + if (CaptureAnsiAsUnicode( Process, p->lpFileName, FALSE, NULL, &FileName ) && + GetIniFilePath( FileName, &IniFilePath ) && + CaptureAnsiAsUnicode( Process, p->lpAppName, FALSE, &SectionName, NULL ) && + CaptureAnsiAsUnicode( Process, p->lpKeyName, FALSE, &VariableName, NULL ) && + CaptureAnsiAsUnicode( Process, p->lpString, FALSE, NULL, &VariableValue ) + ) { + if (FileName != NULL || SectionName != NULL) { + return WritePrivateProfileStringEntry( Process, + Thread, + Parameters, + IniFilePath, + SectionName, + VariableName, + VariableValue + ); + } + } + + return TRUE; + } + else { + return WritePrivateProfileStringExit( Process, + Thread, + Parameters + ); + } +} + +BOOLEAN +WritePrivateProfileStringWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PWRITEPRIVATEPROFILESTRINGW_PARAMETERS p = &Parameters->InputParameters.WritePrivateProfileStringW; + PWSTR SectionName, VariableName, FileName, VariableValue; + PWSTR IniFilePath; + + if (!Parameters->ReturnValueValid) { + FileName = NULL; + IniFilePath = NULL; + SectionName = NULL; + VariableName = NULL; + VariableValue = NULL; + if (CaptureUnicode( Process, p->lpFileName, FALSE, NULL, &FileName ) && + GetIniFilePath( FileName, &IniFilePath ) && + CaptureUnicode( Process, p->lpAppName, FALSE, &SectionName, NULL ) && + CaptureUnicode( Process, p->lpKeyName, FALSE, &VariableName, NULL ) && + CaptureUnicode( Process, p->lpString, FALSE, NULL, &VariableValue ) + ) { + if (FileName != NULL || SectionName != NULL) { + return WritePrivateProfileStringEntry( Process, + Thread, + Parameters, + IniFilePath, + SectionName, + VariableName, + VariableValue + ); + } + } + + return TRUE; + } + else { + return WritePrivateProfileStringExit( Process, + Thread, + Parameters + ); + } +} + + +BOOLEAN +WritePrivateProfileSectionEntry( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters, + PWSTR IniFilePath, + PWSTR SectionName, + PWSTR SectionValue + ) +{ + if (CreateSavedCallState( Process, + &Parameters->SavedCallState, + WriteIniSection, + HANDLE_TYPE_NONE, + IniFilePath, + SectionName, + SectionValue + ) && + CreateIniFileReference( IniFilePath, + (PINI_FILE_REFERENCE *)&Parameters->SavedCallState.Reference + ) + ) { + return TRUE; + } + else { + FreeMem( &SectionValue ); + return FALSE; + } +} + + +BOOLEAN +WritePrivateProfileSectionExit( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PAPI_SAVED_CALL_STATE CallState; + PINI_FILE_REFERENCE IniFileReference; + PINI_SECTION_REFERENCE IniSectionReference; + PINI_VARIABLE_REFERENCE IniVariableReference; + PWSTR VariableName, VariableValue; + UNICODE_STRING UnicodeString; + + if (Parameters->ReturnValue.ReturnedLong != 0) { + CallState = &Parameters->SavedCallState; + IniFileReference = FindIniFileReference( CallState->FullName ); + IniSectionReference = FindIniSectionReference( IniFileReference, + CallState->SetIniSection.SectionName, + (BOOLEAN)(CallState->SetIniSection.SectionValue != NULL) + ); + if (IniSectionReference != NULL) { + if (CallState->SetIniSection.SectionValue == NULL) { + IniSectionReference->Deleted = TRUE; + } + else { + VariableName = CallState->SetIniSection.SectionValue; + while (*VariableName) { + VariableValue = VariableName; + while (*VariableValue != UNICODE_NULL && *VariableValue != L'=') { + VariableValue += 1; + } + + if (*VariableValue != L'=') { + break; + } + + *VariableValue++ = UNICODE_NULL; + + RtlInitUnicodeString( &UnicodeString, VariableName ); + IniVariableReference = FindIniVariableReference( IniSectionReference, + AddName( &UnicodeString ), + (BOOLEAN)(*VariableValue != UNICODE_NULL) + ); + if (IniVariableReference != NULL) { + if (*VariableValue != UNICODE_NULL) { + FreeMem( &IniVariableReference->Value ); + IniVariableReference->Value = AllocMem( (wcslen( VariableValue ) + 1) * sizeof( WCHAR ) ); + wcscpy( IniVariableReference->Value, VariableValue ); + if (!IniVariableReference->Created) { + if (!wcscmp( IniVariableReference->Value, + IniVariableReference->OriginalValue + ) + ) { + FreeMem( &IniVariableReference->Value ); + } + else { + IniVariableReference->Modified = TRUE; + } + } + } + else + if (!IniVariableReference->Created) { + IniVariableReference->Deleted = TRUE; + } + else { + DestroyIniVariableReference( IniVariableReference ); + } + } + + VariableName = VariableValue; + while (*VariableName++ != UNICODE_NULL) { + } + } + } + } + } + + return TRUE; +} + + +BOOLEAN +WritePrivateProfileSectionAHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PWRITEPRIVATEPROFILESECTIONA_PARAMETERS p = &Parameters->InputParameters.WritePrivateProfileSectionA; + PWSTR SectionName, FileName, SectionValue; + PWSTR IniFilePath; + + if (!Parameters->ReturnValueValid) { + FileName = NULL; + SectionValue = NULL; + if (CaptureAnsiAsUnicode( Process, p->lpFileName, FALSE, NULL, &FileName ) && + GetIniFilePath( FileName, &IniFilePath ) && + CaptureAnsiAsUnicode( Process, p->lpAppName, FALSE, &SectionName, NULL ) && + CaptureAnsiAsUnicode( Process, p->lpString, TRUE, NULL, &SectionValue ) + ) { + return WritePrivateProfileSectionEntry( Process, + Thread, + Parameters, + IniFilePath, + SectionName, + SectionValue + ); + } + } + else { + return WritePrivateProfileSectionExit( Process, + Thread, + Parameters + ); + } +} + +BOOLEAN +WritePrivateProfileSectionWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PWRITEPRIVATEPROFILESECTIONW_PARAMETERS p = &Parameters->InputParameters.WritePrivateProfileSectionW; + PWSTR SectionName, FileName, SectionValue; + PWSTR IniFilePath; + + if (!Parameters->ReturnValueValid) { + FileName = NULL; + SectionValue = NULL; + if (CaptureUnicode( Process, p->lpFileName, FALSE, NULL, &FileName ) && + GetIniFilePath( FileName, &IniFilePath ) && + CaptureUnicode( Process, p->lpAppName, FALSE, &SectionName, NULL ) && + CaptureUnicode( Process, p->lpString, TRUE, NULL, &SectionValue ) + ) { + return WritePrivateProfileSectionEntry( Process, + Thread, + Parameters, + IniFilePath, + SectionName, + SectionValue + ); + } + } + else { + return WritePrivateProfileSectionExit( Process, + Thread, + Parameters + ); + } +} + + +BOOLEAN +RegConnectRegistryWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ) +{ + PREGCONNECTREGISTRYW_PARAMETERS p = &Parameters->InputParameters.RegConnectRegistryW; + PWSTR MachineName; + LONG ErrorCode; + HKEY hKey; + + if (!Parameters->ReturnValueValid) { + MachineName = NULL; + if (!CaptureUnicode( Process, p->lpMachineName, FALSE, NULL, &MachineName )) { + MachineName = L"Unknown"; + } + + if (AskUser( MB_OKCANCEL, + INSTALER_ASKUSER_REGCONNECT, + 1, + MachineName + ) == IDCANCEL + ) { + FreeMem( &MachineName ); + Parameters->AbortCall = TRUE; + return TRUE; + } + else { + FreeMem( &MachineName ); + return FALSE; + } + } + else + if (Parameters->ReturnValue.ReturnedLong == 0) { + ErrorCode = ERROR_ACCESS_DENIED; + if (SetProcedureReturnValue( Process, + Thread, + &ErrorCode, + sizeof( ErrorCode ) + ) + ) { + if (ReadMemory( Process, + p->phkResult, + &hKey, + sizeof( hKey ), + "phkResult" + ) + ) { + RegCloseKey( hKey ); + hKey = NULL; + WriteMemory( Process, + p->phkResult, + &hKey, + sizeof( hKey ), + "phkResult" + ); + } + } + } + + return TRUE; +} diff --git a/private/sdktools/instaler/hlist.c b/private/sdktools/instaler/hlist.c new file mode 100644 index 000000000..03172b5e2 --- /dev/null +++ b/private/sdktools/instaler/hlist.c @@ -0,0 +1,484 @@ +#include <windows.h> +#include <custcntl.h> +#include <commdlg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "hlist.h" + + +typedef DWORD (CALLBACK* HLISTCALLBACK)(LPDWORD,LPSTR*,LPSTR,DWORD,DWORD); + +#define XBITMAP 16 +#define YBITMAP 16 +#define MARGIN 6 +#define INDENT (XBITMAP + MARGIN) +#define MIDDLE ((XBITMAP/2) + MARGIN) +#define LINE_COLOR RGB(255,0,0) + +#define CLASS_NAME "HList" +#define DESCRIPTION "Heir List Box" + +#define DEFAULT_STYLE WS_CHILD | \ + WS_VISIBLE | \ + WS_VSCROLL | \ + WS_HSCROLL | \ + WS_BORDER | \ + LBS_NOTIFY | \ + LBS_NOINTEGRALHEIGHT | \ + LBS_WANTKEYBOARDINPUT | \ + LBS_SORT | \ + LBS_OWNERDRAWFIXED + + + +typedef struct _HLISTTYPE { + struct _HLISTTYPE *next; + DWORD type; + HBITMAP bitmap; +} HLISTTYPE, *LPHLISTTYPE; + +typedef struct _HLISTINFO { + HWND hwndList; + LPHLISTTYPE typeList; + HLISTCALLBACK lpCallback; +} HLISTINFO, *LPHLISTINFO; + +typedef struct _ITEMDATA { + struct _ITEMDATA *parent; + DWORD type; + DWORD level; + DWORD nchild; + DWORD childnum; + LPSTR str; + HBITMAP bitmap; +} ITEMDATA, *LPITEMDATA; + + +static HMODULE hInstance; + + +LRESULT HListWndProc(HWND,UINT,WPARAM,LPARAM); + + +BOOL +HListInitialize( + HMODULE hModule + ) +{ + WNDCLASS wndclass; + + + hInstance = hModule; + + wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; + wndclass.lpfnWndProc = HListWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 4; + wndclass.hInstance = hInstance; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = CLASS_NAME; + if (!RegisterClass( &wndclass )) { + return FALSE; + } + + return TRUE; +} + +VOID +CollapseNode( + HWND hwnd, + LPITEMDATA lpid, + DWORD nItem + ) +{ + DWORD i; + LPITEMDATA lpidChild; + + + for (i=0; i<lpid->nchild; i++) { + lpidChild = (LPITEMDATA) SendMessage( hwnd, LB_GETITEMDATA, nItem, 0 ); + if (lpidChild->nchild) { + CollapseNode( hwnd, lpidChild, nItem+1 ); + } + SendMessage( hwnd, LB_DELETESTRING, nItem, 0 ); + } + + lpid->nchild = 0; +} + +LRESULT +HListWndProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + RECT cRect; + HFONT hFont; + LPHLISTINFO hli; + LPHLISTTYPE hlt; + LPHLISTTYPE hltNext; + LPMEASUREITEMSTRUCT lpmis; + LPDELETEITEMSTRUCT lplis; + LPDRAWITEMSTRUCT lpdis; + HBITMAP hbmp; + HBITMAP hbmpOld; + HDC hdc; + TEXTMETRIC tm; + int x; + int y; + int nItem; + RECT rcBitmap; + LPITEMDATA lpid; + LPITEMDATA lpidParent; + DWORD type; + LPSTR str; + DWORD rval; + DWORD level; + LPSTR ref; + LPSTR p; + POINT pt; + DWORD childnum; + DWORD i; + HPEN hpen; + HPEN oldhpen; + + + switch (message) { + case WM_CREATE: + hli = (LPHLISTINFO) malloc( sizeof(HLISTINFO) ); + ZeroMemory( hli, sizeof(HLISTINFO) ); + GetClientRect( hwnd, &cRect ); + hli->hwndList = CreateWindow( + "LISTBOX", + NULL, + DEFAULT_STYLE, + cRect.left, + cRect.top, + cRect.right - cRect.left, + cRect.bottom - cRect.top, + hwnd, + NULL, + GetModuleHandle(NULL), + NULL ); + hFont = GetStockObject( SYSTEM_FIXED_FONT ); + SendMessage( hli->hwndList, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE ); + SetFocus( hli->hwndList ); + SetWindowLong( hwnd, 0, (DWORD)hli ); + break; + + case WM_SIZE: + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + GetClientRect( hwnd, &cRect ); + MoveWindow( + hli->hwndList, + cRect.left, + cRect.top, + cRect.right - cRect.left, + cRect.bottom - cRect.top, + TRUE ); + break; + + case WM_DESTROY: + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + hlt = hli->typeList; + while (hlt) { + hltNext = hlt->next; + free( hlt ); + hlt = hltNext; + } + DestroyWindow( hli->hwndList ); + hli->hwndList = NULL; + free( hli ); + SetWindowLong( hwnd, 0, 0 ); + break; + + case WM_COMMAND: + if (HIWORD(wParam) == LBN_DBLCLK) { + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + if (hli->lpCallback) { + nItem = SendMessage( hli->hwndList, LB_GETCURSEL, 0, 0 ); + + lpidParent = (LPITEMDATA) SendMessage( hli->hwndList, LB_GETITEMDATA, nItem, 0 ); + + y = 0; + lpid = lpidParent; + while (lpid) { + y += (strlen(lpid->str) + 1); + lpid = lpid->parent; + } + y += 16; + p = ref = malloc( y ); + lpid = lpidParent; + while (lpid) { + strcpy( p, lpid->str ); + p += (strlen(p) + 1); + lpid = lpid->parent; + } + *p = '\0'; + + level = lpidParent->level + 1; + type = lpidParent->type; + str = lpidParent->str; + rval = (hli->lpCallback)( &type, &str, ref, level, lpidParent->nchild ); + + if (rval == HLB_COLLAPSE) { + CollapseNode( hli->hwndList, lpidParent, nItem+1 ); + break; + } + + childnum = 1; + while (rval != HLB_END) { + if (rval == HLB_EXPAND) { + hlt = hli->typeList; + while (hlt && hlt->type != type) { + hlt = hlt->next; + } + if (!hlt) { + break; + } + lpidParent->nchild++; + lpid = (LPITEMDATA) malloc( sizeof(ITEMDATA) ); + lpid->type = type; + lpid->nchild = 0; + lpid->level = level; + lpid->bitmap = hlt->bitmap; + lpid->str = _strdup( (LPSTR)str ); + lpid->parent = lpidParent; + lpid->childnum = childnum++; + nItem = SendMessage( hli->hwndList, LB_INSERTSTRING, nItem+1, (LPARAM)lpid->str ); + SendMessage( hli->hwndList, LB_SETITEMDATA, nItem, (LPARAM) lpid ); + } + rval = (hli->lpCallback)( &type, &str, ref, level, 0 ); + } + free( ref ); + } + } + break; + + case HLB_REGISTER_CALLBACK: + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + hli->lpCallback = (HLISTCALLBACK) lParam; + return 1; + + case HLB_REGISTER_TYPE: + // + // wParam = type token + // lParam = the bitmap + // + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + if (!hli->typeList) { + hli->typeList = (LPHLISTTYPE) malloc( sizeof(HLISTTYPE) ); + hlt = hli->typeList; + } else { + hlt = hli->typeList; + while (hlt->next) { + hlt = hlt->next; + } + hlt->next = (LPHLISTTYPE) malloc( sizeof(HLISTTYPE) ); + hlt = hlt->next; + } + hlt->type = (WPARAM) wParam; + hlt->bitmap = (HBITMAP) lParam; + hlt->next = NULL; + return 1; + + case HLB_ADDSTRING: + // + // wParam = type + // lParam = string + // + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + hlt = hli->typeList; + while (hlt && hlt->type != wParam) { + hlt = hlt->next; + } + if (!hlt) { + return 0; + } + lpid = (LPITEMDATA) malloc( sizeof(ITEMDATA) ); + lpid->type = hlt->type; + lpid->level = 0; + lpid->nchild = 0; + lpid->bitmap = hlt->bitmap; + lpid->str = _strdup( (LPSTR)lParam ); + lpid->parent = NULL; + lpid->childnum = 0; + nItem = SendMessage( hli->hwndList, LB_ADDSTRING, 0, (LPARAM)lpid->str ); + SendMessage( hli->hwndList, LB_SETITEMDATA, nItem, (LPARAM) lpid ); + return 1; + + case WM_MEASUREITEM: + lpmis = (LPMEASUREITEMSTRUCT) lParam; + lpmis->itemHeight = YBITMAP; + return 1; + + case WM_DELETEITEM: + lplis = (LPDELETEITEMSTRUCT) lParam; + lpid = (LPITEMDATA) lplis->itemData; + free( lpid->str ); + free( lpid ); + return 1; + + case WM_DRAWITEM: + lpdis = (LPDRAWITEMSTRUCT) lParam; + + if (lpdis->itemID == -1) { + break; + } + + switch (lpdis->itemAction) { + case ODA_SELECT: + case ODA_DRAWENTIRE: + lpid = (LPITEMDATA) SendMessage( lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, 0 ); + hbmp = lpid->bitmap; + + hdc = CreateCompatibleDC( lpdis->hDC ); + hbmpOld = SelectObject( hdc, hbmp ); + + lpdis->rcItem.left += (lpid->level * INDENT); + + BitBlt( + lpdis->hDC, + lpdis->rcItem.left, + lpdis->rcItem.top, + lpdis->rcItem.right - lpdis->rcItem.left, + lpdis->rcItem.bottom - lpdis->rcItem.top, + hdc, + 0, + 0, + SRCCOPY ); + + GetTextMetrics( lpdis->hDC, &tm ); + + y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2; + + TextOut( lpdis->hDC, XBITMAP + MARGIN + (lpid->level * INDENT), y, lpid->str, strlen(lpid->str) ); + + SelectObject( hdc, hbmpOld ); + + // + // now draw lines + // + if (lpid->level) { + + hpen = CreatePen( PS_SOLID, 1, LINE_COLOR ); + oldhpen = SelectObject( lpdis->hDC, hpen ); + + y = lpdis->rcItem.top + ((lpdis->rcItem.bottom - lpdis->rcItem.top) / 2); + MoveToEx( + lpdis->hDC, + lpdis->rcItem.left - 1, + y, + &pt ); + + LineTo( + lpdis->hDC, + lpdis->rcItem.left - MIDDLE, + y ); + + MoveToEx( + lpdis->hDC, + lpdis->rcItem.left - MIDDLE, + lpdis->rcItem.top, + &pt ); + + if (lpid->childnum < lpid->parent->nchild) { + y = lpdis->rcItem.bottom; + } else { + y++; + } + + LineTo( + lpdis->hDC, + lpdis->rcItem.left - MIDDLE, + y ); + + if (lpid->level > 1) { + x = lpdis->rcItem.left - MIDDLE; + y = lpdis->rcItem.top; + for (i=1; i<lpid->level; i++) { + MoveToEx( + lpdis->hDC, + x - (i * INDENT), + y, + &pt ); + LineTo( + lpdis->hDC, + x - (i * INDENT), + lpdis->rcItem.bottom ); + } + } + + SelectObject( lpdis->hDC, oldhpen ); + DeleteObject( hpen ); + } + + DeleteDC( hdc ); + + if (lpdis->itemState & ODS_SELECTED) { + rcBitmap.left = lpdis->rcItem.left; + rcBitmap.top = lpdis->rcItem.top; + rcBitmap.right = lpdis->rcItem.left + XBITMAP + (tm.tmMaxCharWidth * strlen(lpid->str)) + MARGIN + 2; + rcBitmap.bottom = lpdis->rcItem.top + YBITMAP; + DrawFocusRect( lpdis->hDC, &rcBitmap ); + } + + break; + + case ODA_FOCUS: + break; + } + return 1; + + case LB_ADDSTRING: + return SendMessage( hwnd, HLB_ADDSTRING, 1, lParam ); + + case LB_INSERTSTRING: + case LB_DELETESTRING: + case LB_SELITEMRANGEEX: + case LB_RESETCONTENT: + case LB_SETSEL: + case LB_SETCURSEL: + case LB_GETSEL: + case LB_GETCURSEL: + case LB_GETTEXT: + case LB_GETTEXTLEN: + case LB_GETCOUNT: + case LB_SELECTSTRING: + case LB_DIR: + case LB_ADDFILE: + case LB_GETTOPINDEX: + case LB_FINDSTRING: + case LB_GETSELCOUNT: + case LB_GETSELITEMS: + case LB_SETTABSTOPS: + case LB_GETHORIZONTALEXTENT: + case LB_SETHORIZONTALEXTENT: + case LB_SETCOLUMNWIDTH: + case LB_SETTOPINDEX: + case LB_GETITEMRECT: + case LB_GETITEMDATA: + case LB_SETITEMDATA: + case LB_SELITEMRANGE: + case LB_SETANCHORINDEX: + case LB_GETANCHORINDEX: + case LB_SETCARETINDEX: + case LB_GETCARETINDEX: + case LB_SETITEMHEIGHT: + case LB_GETITEMHEIGHT: + case LB_FINDSTRINGEXACT: + case LB_SETLOCALE: + case LB_GETLOCALE: + case LB_SETCOUNT: + hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); + return SendMessage( hli->hwndList, message, wParam, lParam ); + } + + return DefWindowProc( hwnd, message, wParam, lParam ); +} diff --git a/private/sdktools/instaler/hlist.h b/private/sdktools/instaler/hlist.h new file mode 100644 index 000000000..61a63a98f --- /dev/null +++ b/private/sdktools/instaler/hlist.h @@ -0,0 +1,13 @@ + +// +// hlist defines +// +#define HLB_ADDSTRING WM_USER+100 +#define HLB_INSERTSTRING WM_USER+101 +#define HLB_REGISTER_TYPE WM_USER+102 +#define HLB_REGISTER_CALLBACK WM_USER+103 + +#define HLB_IGNORE 0 +#define HLB_EXPAND 1 +#define HLB_COLLAPSE 2 +#define HLB_END 3 diff --git a/private/sdktools/instaler/i386/machine.c b/private/sdktools/instaler/i386/machine.c new file mode 100644 index 000000000..9f5b120d5 --- /dev/null +++ b/private/sdktools/instaler/i386/machine.c @@ -0,0 +1,332 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + machine.c + +Abstract: + + This file contains machine specific code to support the INSTALER + program. Specifically, routines to fetch parameters from the + registers/stack of a target process, routines to set a breakpoint + and step over an instruction at a breakpoint. + +Author: + + Steve Wood (stevewo) 10-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +#define BREAKPOINT_OPCODE 0xCC +#define INT_OPCODE 0xCD + +UCHAR InstructionBuffer = BREAKPOINT_OPCODE; +PVOID BreakpointInstruction = (PVOID)&InstructionBuffer; +ULONG SizeofBreakpointInstruction = sizeof( InstructionBuffer ); + +BOOLEAN +SkipOverHardcodedBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PVOID BreakpointAddress + ) +{ + UCHAR InstructionByte; + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + if (!ReadMemory( Process, + BreakpointAddress, + &InstructionByte, + sizeof( InstructionByte ), + "hard coded breakpoint" + ) + ) { + return FALSE; + } + + if (InstructionByte == BREAKPOINT_OPCODE) { + Context.Eip = (ULONG)((PCHAR)BreakpointAddress + 1); + } + else + if (InstructionByte == INT_OPCODE) { + Context.Eip = (ULONG)((PCHAR)BreakpointAddress + 2); + } + else { + return FALSE; + } + + if (!SetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + else { + return TRUE; + } +} + + +BOOLEAN +ExtractProcedureParameters( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PULONG ReturnAddress, + ULONG SizeOfParameters, + PULONG Parameters + ) +{ + UINT i; + ULONG NumberOfParameters; + CONTEXT Context; + ULONG StackBuffer[ 1+31 ]; + + NumberOfParameters = SizeOfParameters / sizeof( ULONG ); + if ((NumberOfParameters * sizeof( ULONG )) != SizeOfParameters || + NumberOfParameters > 31 + ) { + DbgEvent( INTERNALERROR, ( "Invalid parameter size %x\n", SizeOfParameters ) ); + return FALSE; + } + + Context.ContextFlags = CONTEXT_CONTROL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + if (!ReadMemory( Process, + (PVOID)Context.Esp, + StackBuffer, + SizeOfParameters + sizeof( ULONG ), + "parameters" + ) + ) { + return FALSE; + } + + *ReturnAddress = StackBuffer[ 0 ]; + for (i=0; i<NumberOfParameters; i++) { + Parameters[ i ] = StackBuffer[ 1+i ]; + } + + return TRUE; +} + + +BOOLEAN +ExtractProcedureReturnValue( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PVOID ReturnValue, + ULONG SizeOfReturnValue + ) +{ + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + switch (SizeOfReturnValue) { + case sizeof( UCHAR ): + *(PUCHAR)ReturnValue = (UCHAR)Context.Eax; + break; + case sizeof( USHORT ): + *(PUSHORT)ReturnValue = (USHORT)Context.Eax; + break; + case sizeof( ULONG ): + *(PULONG)ReturnValue = (ULONG)Context.Eax; + break; + case sizeof( ULONGLONG ): + *(PULONGLONG)ReturnValue = (ULONGLONG)Context.Edx << 32 | Context.Eax; + break; + default: + DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) ); + return FALSE; + } + + return TRUE; +} + +BOOLEAN +SetProcedureReturnValue( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PVOID ReturnValue, + ULONG SizeOfReturnValue + ) +{ + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + switch (SizeOfReturnValue) { + case sizeof( UCHAR ): + (UCHAR)Context.Eax = *(PUCHAR)ReturnValue; + break; + case sizeof( USHORT ): + (USHORT)Context.Eax = *(PUSHORT)ReturnValue; + break; + case sizeof( ULONG ): + (ULONG)Context.Eax = *(PULONG)ReturnValue; + break; + case sizeof( ULONGLONG ): + (ULONG)Context.Eax = *(PULONG)ReturnValue; + (ULONG)Context.Edx = *((PULONG)ReturnValue + 1); + break; + default: + DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) ); + return FALSE; + } + + if (!SetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + else { + return TRUE; + } +} + +BOOLEAN +ForceReturnToCaller( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + ULONG SizeOfParameters, + PVOID ReturnAddress, + PVOID ReturnValue, + ULONG SizeOfReturnValue + ) +{ + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + switch (SizeOfReturnValue) { + case sizeof( UCHAR ): + (UCHAR)Context.Eax = *(PUCHAR)ReturnValue; + break; + case sizeof( USHORT ): + (USHORT)Context.Eax = *(PUSHORT)ReturnValue; + break; + case sizeof( ULONG ): + (ULONG)Context.Eax = *(PULONG)ReturnValue; + break; + case sizeof( ULONGLONG ): + (ULONG)Context.Eax = *(PULONG)ReturnValue; + (ULONG)Context.Edx = *((PULONG)ReturnValue + 1); + break; + default: + DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) ); + return FALSE; + } + + Context.Eip = (ULONG)ReturnAddress; + Context.Esp = Context.Esp + sizeof( ReturnAddress ) + SizeOfParameters; + + if (!SetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + else { + return TRUE; + } +} + + + +BOOLEAN +UndoReturnAddressBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ) +{ + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + Context.Eip -= 1; // Back up to where breakpoint instruction was + if (!SetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + else { + return TRUE; + } +} + + +BOOLEAN +BeginSingleStepBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ) +{ + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + Context.Eip -= 1; // Back up to where breakpoint instruction was + Context.EFlags |= V86FLAGS_TRACE; + if (!SetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + else { + return TRUE; + } +} + + +BOOLEAN +EndSingleStepBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ) +{ + CONTEXT Context; + + Context.ContextFlags = CONTEXT_FULL; + if (!GetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + + Context.EFlags &= ~V86FLAGS_TRACE; + if (!SetThreadContext( Thread->Handle, &Context )) { + DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) ); + return FALSE; + } + else { + return TRUE; + } +} diff --git a/private/sdktools/instaler/i386/sources b/private/sdktools/instaler/i386/sources new file mode 100644 index 000000000..96beda740 --- /dev/null +++ b/private/sdktools/instaler/i386/sources @@ -0,0 +1,32 @@ +i386_SOURCES=..\instaler.rc \ + ..\instutil.c \ + ..\iml.c \ + ..\init.c \ + ..\handler.c \ + ..\debug.c \ + ..\process.c \ + ..\handledb.c \ + ..\namedb.c \ + ..\file.c \ + ..\key.c \ + ..\ini.c \ + ..\error.c \ + ..\event.c \ + i386\machine.c + +UMTYPE=console +UMAPPL=instaler*showinst*undoinst*compinst +UMTEST=testins1*testins2 +UMLIBS=\nt\public\sdk\lib\*\setargv.obj \ + obj\*\instaler.lib \ + \nt\public\sdk\lib\*\ntdll.lib \ + \nt\public\sdk\lib\*\user32.lib +UMRES=$(@R).res + +NTTARGETFILE0=errormsg.h \ + obj\*\instaler.res \ + obj\*\testins1.res \ + obj\*\testins2.res \ + obj\*\showinst.res \ + obj\*\undoinst.res \ + obj\*\compinst.res diff --git a/private/sdktools/instaler/iml.c b/private/sdktools/instaler/iml.c new file mode 100644 index 000000000..5e8dbb7f1 --- /dev/null +++ b/private/sdktools/instaler/iml.c @@ -0,0 +1,481 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + iml.c + +Abstract: + + This module contains routines for creating and accessing Installation + Modification Log files (.IML) + +Author: + + Steve Wood (stevewo) 15-Jan-1996 + +Revision History: + +--*/ + +#include "instutil.h" +#include "iml.h" + +PWSTR +FormatImlPath( + PWSTR DirectoryPath, + PWSTR InstallationName + ) +{ + PWSTR ImlPath; + ULONG n; + + n = wcslen( DirectoryPath ) + wcslen( InstallationName ) + 8; + ImlPath = HeapAlloc( GetProcessHeap(), 0, (n * sizeof( WCHAR )) ); + if (ImlPath != NULL) { + _snwprintf( ImlPath, n, L"%s%s.IML", DirectoryPath, InstallationName ); + } + + return ImlPath; +} + + +PINSTALLATION_MODIFICATION_LOGFILE +CreateIml( + PWSTR ImlPath, + BOOLEAN IncludeCreateFileContents + ) +{ + HANDLE FileHandle; + PINSTALLATION_MODIFICATION_LOGFILE pIml; + + pIml = NULL; + FileHandle = CreateFile( ImlPath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + 0, + NULL + ); + if (FileHandle != INVALID_HANDLE_VALUE) { + pIml = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *pIml ) ); + if (pIml != NULL) { + pIml->Signature = IML_SIGNATURE; + pIml->FileHandle = FileHandle; + pIml->FileOffset = ROUND_UP( sizeof( *pIml ), 8 ); + if (IncludeCreateFileContents) { + pIml->Flags = IML_FLAG_CONTAINS_NEWFILECONTENTS; + } + + SetFilePointer( pIml->FileHandle, pIml->FileOffset, NULL, FILE_BEGIN ); + } + } + + return pIml; +} + + +PINSTALLATION_MODIFICATION_LOGFILE +LoadIml( + PWSTR ImlPath + ) +{ + HANDLE FileHandle, MappingHandle; + PINSTALLATION_MODIFICATION_LOGFILE pIml; + + pIml = NULL; + FileHandle = CreateFile( ImlPath, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (FileHandle != INVALID_HANDLE_VALUE) { + MappingHandle = CreateFileMapping( FileHandle, + NULL, + PAGE_READONLY, + 0, + 0, + NULL + ); + CloseHandle( FileHandle ); + if (MappingHandle != NULL) { + pIml = MapViewOfFile( MappingHandle, + FILE_MAP_READ, + 0, + 0, + 0 + ); + CloseHandle( MappingHandle ); + if (pIml != NULL) { + if (pIml->Signature != IML_SIGNATURE) { + UnmapViewOfFile( pIml ); + pIml = NULL; + SetLastError( ERROR_BAD_FORMAT ); + } + + } + } + } + + return pIml; +} + + +BOOLEAN +CloseIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml + ) +{ + HANDLE FileHandle; + BOOLEAN Result; + ULONG BytesWritten; + + if (pIml->FileHandle == NULL) { + if (!UnmapViewOfFile( pIml )) { + return FALSE; + } + else { + Result = TRUE; + } + } + else { + FileHandle = pIml->FileHandle; + pIml->FileHandle = NULL; + if (!SetEndOfFile( FileHandle ) || + SetFilePointer( FileHandle, 0, NULL, FILE_BEGIN ) != 0 || + !WriteFile( FileHandle, + pIml, + sizeof( *pIml ), + &BytesWritten, + NULL + ) || + BytesWritten != sizeof( *pIml ) + ) { + Result = FALSE; + } + else { + Result = TRUE; + } + CloseHandle( FileHandle ); + } + + return Result; +} + + +POFFSET +ImlWrite( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PVOID p, + ULONG Size + ) +{ + POFFSET Result; + ULONG BytesWritten; + + if (!WriteFile( pIml->FileHandle, + p, + Size, + &BytesWritten, + NULL + ) || + BytesWritten != Size + ) { + return 0; + } + + Result = pIml->FileOffset; + pIml->FileOffset += ROUND_UP( Size, 8 ); + SetFilePointer( pIml->FileHandle, + pIml->FileOffset, + NULL, + FILE_BEGIN + ); + return Result; +} + +POFFSET +ImlWriteString( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PWSTR Name + ) +{ + if (Name == NULL) { + return 0; + } + else { + return ImlWrite( pIml, Name, (wcslen( Name ) + 1) * sizeof( WCHAR ) ); + } +} + + +POFFSET +ImlWriteFileContents( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + PWSTR FileName + ) +{ + HANDLE hFindFirst, hFile, hMapping; + WIN32_FIND_DATA FindFileData; + PVOID p; + IML_FILE_RECORD_CONTENTS ImlFileContentsRecord; + + hFindFirst = FindFirstFile( FileName, &FindFileData ); + if (hFindFirst == INVALID_HANDLE_VALUE) { + return 0; + } + FindClose( hFindFirst ); + + ImlFileContentsRecord.LastWriteTime = FindFileData.ftLastWriteTime; + ImlFileContentsRecord.FileAttributes = FindFileData.dwFileAttributes; + if (!(ImlFileContentsRecord.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + ImlFileContentsRecord.FileSize = FindFileData.nFileSizeLow; + hFile = CreateFile( FileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (hFile == INVALID_HANDLE_VALUE) { + printf( "*** CreateFile( '%ws' ) failed (%u)\n", FileName, GetLastError() ); + return 0; + } + + if (ImlFileContentsRecord.FileSize != 0) { + hMapping = CreateFileMapping( hFile, + NULL, + PAGE_READONLY, + 0, + 0, + NULL + ); + CloseHandle( hFile ); + hFile = NULL; + if (hMapping == NULL) { + printf( "*** CreateFileMapping( '%ws' ) failed (%u)\n", FileName, GetLastError() ); + return 0; + } + + p = MapViewOfFile( hMapping, + FILE_MAP_READ, + 0, + 0, + 0 + ); + CloseHandle( hMapping ); + if (p == NULL) { + printf( "*** MapViewOfFile( '%ws' ) failed (%u)\n", FileName, GetLastError() ); + return 0; + } + } + else { + CloseHandle( hFile ); + p = NULL; + } + } + else { + ImlFileContentsRecord.FileSize = 0; + p = NULL; + } + + ImlFileContentsRecord.Contents = ImlWrite( pIml, p, ImlFileContentsRecord.FileSize ); + if (p != NULL) { + UnmapViewOfFile( p ); + } + + return ImlWrite( pIml, + &ImlFileContentsRecord, + sizeof( ImlFileContentsRecord ) + ); +} + +BOOLEAN +ImlAddFileRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_FILE_ACTION Action, + PWSTR Name, + PWSTR BackupFileName, + PFILETIME BackupLastWriteTime, + DWORD BackupFileAttributes + ) +{ + IML_FILE_RECORD ImlFileRecord; + IML_FILE_RECORD_CONTENTS ImlFileContentsRecord; + + memset( &ImlFileRecord, 0, sizeof( ImlFileRecord ) ); + ImlFileRecord.Action = Action; + ImlFileRecord.Name = ImlWriteString( pIml, Name ); + if (Action == CreateNewFile) { + if ((pIml->Flags & IML_FLAG_CONTAINS_NEWFILECONTENTS) != 0) { + ImlFileRecord.NewFile = ImlWriteFileContents( pIml, Name ); + } + } + else + if (Action == ModifyOldFile || + Action == DeleteOldFile + ) { + if (BackupFileName != NULL) { + ImlFileRecord.OldFile = ImlWriteFileContents( pIml, BackupFileName ); + } + + if (Action == ModifyOldFile && + (pIml->Flags & IML_FLAG_CONTAINS_NEWFILECONTENTS) != 0 + ) { + ImlFileRecord.NewFile = ImlWriteFileContents( pIml, Name ); + } + } + else { + ImlFileContentsRecord.LastWriteTime = *BackupLastWriteTime; + ImlFileContentsRecord.FileAttributes = BackupFileAttributes; + ImlFileContentsRecord.FileSize = 0; + ImlFileContentsRecord.Contents = 0; + ImlFileRecord.OldFile = ImlWrite( pIml, + &ImlFileContentsRecord, + sizeof( ImlFileContentsRecord ) + ); + } + + ImlFileRecord.Next = pIml->FileRecords; + pIml->FileRecords = ImlWrite( pIml, &ImlFileRecord, sizeof( ImlFileRecord ) ); + pIml->NumberOfFileRecords += 1; + return TRUE; +} + + +BOOLEAN +ImlAddValueRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_VALUE_ACTION Action, + PWSTR Name, + DWORD ValueType, + ULONG ValueLength, + PVOID ValueData, + DWORD BackupValueType, + ULONG BackupValueLength, + PVOID BackupValueData, + POFFSET *Values + ) +{ + IML_VALUE_RECORD ImlValueRecord; + IML_VALUE_RECORD_CONTENTS ImlValueContentsRecord; + + memset( &ImlValueRecord, 0, sizeof( ImlValueRecord ) ); + ImlValueRecord.Action = Action; + ImlValueRecord.Name = ImlWriteString( pIml, Name ); + if (Action != DeleteOldValue) { + ImlValueContentsRecord.Type = ValueType; + ImlValueContentsRecord.Length = ValueLength; + ImlValueContentsRecord.Data = ImlWrite( pIml, ValueData, ValueLength ); + ImlValueRecord.NewValue = ImlWrite( pIml, + &ImlValueContentsRecord, + sizeof( ImlValueContentsRecord ) + ); + } + if (Action != CreateNewValue) { + ImlValueContentsRecord.Type = BackupValueType; + ImlValueContentsRecord.Length = BackupValueLength; + ImlValueContentsRecord.Data = ImlWrite( pIml, BackupValueData, BackupValueLength ); + ImlValueRecord.OldValue = ImlWrite( pIml, + &ImlValueContentsRecord, + sizeof( ImlValueContentsRecord ) + ); + } + + ImlValueRecord.Next = *Values; + *Values = ImlWrite( pIml, &ImlValueRecord, sizeof( ImlValueRecord ) ); + return TRUE; +} + + +BOOLEAN +ImlAddKeyRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_KEY_ACTION Action, + PWSTR Name, + POFFSET Values + ) +{ + IML_KEY_RECORD ImlKeyRecord; + + memset( &ImlKeyRecord, 0, sizeof( ImlKeyRecord ) ); + ImlKeyRecord.Action = Action; + ImlKeyRecord.Name = ImlWriteString( pIml, Name ); + ImlKeyRecord.Values = Values; + ImlKeyRecord.Next = pIml->KeyRecords; + pIml->KeyRecords = ImlWrite( pIml, &ImlKeyRecord, sizeof( ImlKeyRecord ) ); + pIml->NumberOfKeyRecords += 1; + return TRUE; +} + + + +BOOLEAN +ImlAddIniVariableRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_INIVARIABLE_ACTION Action, + PWSTR Name, + PWSTR OldValue, + PWSTR NewValue, + POFFSET *Variables + ) +{ + IML_INIVARIABLE_RECORD ImlIniVariableRecord; + + memset( &ImlIniVariableRecord, 0, sizeof( ImlIniVariableRecord ) ); + ImlIniVariableRecord.Action = Action; + ImlIniVariableRecord.Name = ImlWriteString( pIml, Name ); + ImlIniVariableRecord.OldValue = ImlWriteString( pIml, OldValue ); + ImlIniVariableRecord.NewValue = ImlWriteString( pIml, NewValue ); + ImlIniVariableRecord.Next = *Variables; + *Variables = ImlWrite( pIml, &ImlIniVariableRecord, sizeof( ImlIniVariableRecord ) ); + return TRUE; +} + +BOOLEAN +ImlAddIniSectionRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_INISECTION_ACTION Action, + PWSTR Name, + POFFSET Variables, + POFFSET *Sections + ) +{ + IML_INISECTION_RECORD ImlIniSectionRecord; + + memset( &ImlIniSectionRecord, 0, sizeof( ImlIniSectionRecord ) ); + ImlIniSectionRecord.Action = Action; + ImlIniSectionRecord.Name = ImlWriteString( pIml, Name ); + ImlIniSectionRecord.Variables = Variables; + ImlIniSectionRecord.Next = *Sections; + *Sections = ImlWrite( pIml, &ImlIniSectionRecord, sizeof( ImlIniSectionRecord ) ); + return TRUE; +} + +BOOLEAN +ImlAddIniRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_INI_ACTION Action, + PWSTR Name, + PFILETIME BackupLastWriteTime, + POFFSET Sections + ) +{ + IML_INI_RECORD ImlIniRecord; + + memset( &ImlIniRecord, 0, sizeof( ImlIniRecord ) ); + ImlIniRecord.Action = Action; + ImlIniRecord.Name = ImlWriteString( pIml, Name ); + ImlIniRecord.LastWriteTime = *BackupLastWriteTime; + ImlIniRecord.Sections = Sections; + ImlIniRecord.Next = pIml->IniRecords; + pIml->IniRecords = ImlWrite( pIml, &ImlIniRecord, sizeof( ImlIniRecord ) ); + pIml->NumberOfIniRecords += 1; + return TRUE; +} diff --git a/private/sdktools/instaler/iml.h b/private/sdktools/instaler/iml.h new file mode 100644 index 000000000..dea3eadb7 --- /dev/null +++ b/private/sdktools/instaler/iml.h @@ -0,0 +1,221 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + iml.h + +Abstract: + + Header for for creating, accessing and manipulating Installation Modification + Log files (.IML extension) created by INSTALER.EXE + +Author: + + Steve Wood (stevewo) 23-Jan-1996 + +--*/ + +typedef ULONG POFFSET; + +#define MP(t,b,o) ((t)((o) ? (PVOID)((ULONG)(b) + (o)) : NULL)) + +typedef struct _INSTALLATION_MODIFICATION_LOGFILE { + ULONG Signature; + USHORT HeaderSize; + USHORT Flags; + HANDLE FileHandle; + ULONG FileOffset; + ULONG NumberOfFileRecords; + POFFSET FileRecords; // IML_FILE_RECORD + ULONG NumberOfKeyRecords; + POFFSET KeyRecords; // IML_KEY_RECORD + ULONG NumberOfIniRecords; + POFFSET IniRecords; // IML_INI_RECORD +} INSTALLATION_MODIFICATION_LOGFILE, *PINSTALLATION_MODIFICATION_LOGFILE; + +#define IML_SIGNATURE 0xFF0AA0FF + +#define IML_FLAG_CONTAINS_NEWFILECONTENTS 0x0001 +#define IML_FLAG_ACTIONS_UNDONE 0x0002 + +PWSTR +FormatImlPath( + PWSTR DirectoryPath, + PWSTR InstallationName + ); + +PINSTALLATION_MODIFICATION_LOGFILE +CreateIml( + PWSTR ImlPath, + BOOLEAN IncludeCreateFileContents + ); + +PINSTALLATION_MODIFICATION_LOGFILE +LoadIml( + PWSTR ImlPath + ); + +BOOLEAN +CloseIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml + ); + +typedef enum _IML_FILE_ACTION { + CreateNewFile, + ModifyOldFile, + DeleteOldFile, + ModifyFileDateTime, + ModifyFileAttributes +} IML_FILE_ACTION; + +typedef struct _IML_FILE_RECORD_CONTENTS { + FILETIME LastWriteTime; + DWORD FileAttributes; + DWORD FileSize; + POFFSET Contents; // VOID +} IML_FILE_RECORD_CONTENTS, *PIML_FILE_RECORD_CONTENTS; + + +typedef struct _IML_FILE_RECORD { + POFFSET Next; // IML_FILE_RECORD + IML_FILE_ACTION Action; + POFFSET Name; // WCHAR + POFFSET OldFile; // IML_FILE_RECORD_CONTENTS + POFFSET NewFile; // IML_FILE_RECORD_CONTENTS +} IML_FILE_RECORD, *PIML_FILE_RECORD; + +BOOLEAN +ImlAddFileRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_FILE_ACTION Action, + PWSTR Name, + PWSTR BackupFileName, + PFILETIME BackupLastWriteTime, + DWORD BackupFileAttributes + ); + +typedef enum _IML_VALUE_ACTION { + CreateNewValue, + DeleteOldValue, + ModifyOldValue +} IML_VALUE_ACTION; + +typedef struct _IML_VALUE_RECORD_CONTENTS { + DWORD Type; + DWORD Length; + POFFSET Data; // VOID +} IML_VALUE_RECORD_CONTENTS, *PIML_VALUE_RECORD_CONTENTS; + +typedef struct _IML_VALUE_RECORD { + POFFSET Next; // IML_VALUE_RECORD + IML_VALUE_ACTION Action; + POFFSET Name; // WCHAR + POFFSET OldValue; // IML_VALUE_RECORD_CONTENTS + POFFSET NewValue; // IML_VALUE_RECORD_CONTENTS +} IML_VALUE_RECORD, *PIML_VALUE_RECORD; + +BOOLEAN +ImlAddValueRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_VALUE_ACTION Action, + PWSTR Name, + DWORD ValueType, + ULONG ValueLength, + PVOID ValueData, + DWORD BackupValueType, + ULONG BackupValueLength, + PVOID BackupValueData, + POFFSET *Values // IML_VALUE_RECORD + ); + +typedef enum _IML_KEY_ACTION { + CreateNewKey, + DeleteOldKey, + ModifyKeyValues +} IML_KEY_ACTION; + +typedef struct _IML_KEY_RECORD { + POFFSET Next; // IML_KEY_RECORD + IML_KEY_ACTION Action; + POFFSET Name; // WCHAR + POFFSET Values; // IML_VALUE_RECORD +} IML_KEY_RECORD, *PIML_KEY_RECORD; + +BOOLEAN +ImlAddKeyRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_KEY_ACTION Action, + PWSTR Name, + POFFSET Values // IML_VALUE_RECORD + ); + +typedef enum _IML_INIVARIABLE_ACTION { + CreateNewVariable, + DeleteOldVariable, + ModifyOldVariable +} IML_INIVARIABLE_ACTION; + +typedef struct _IML_INIVARIABLE_RECORD { + POFFSET Next; // IML_INIVARIABLE_RECORD + IML_INIVARIABLE_ACTION Action; + POFFSET Name; // WCHAR + POFFSET OldValue; // WCHAR + POFFSET NewValue; // WCHAR +} IML_INIVARIABLE_RECORD, *PIML_INIVARIABLE_RECORD; + +BOOLEAN +ImlAddIniVariableRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_INIVARIABLE_ACTION Action, + PWSTR Name, + PWSTR OldValue, + PWSTR NewValue, + POFFSET *Variables // IML_INIVARIABLE_RECORD + ); + +typedef enum _IML_INISECTION_ACTION { + CreateNewSection, + DeleteOldSection, + ModifySectionVariables +} IML_INISECTION_ACTION; + +typedef struct _IML_INISECTION_RECORD { + POFFSET Next; // IML_INISECTION_RECORD + IML_INISECTION_ACTION Action; + POFFSET Name; // WCHAR + POFFSET Variables; // IML_INIVARIABLE_RECORD +} IML_INISECTION_RECORD, *PIML_INISECTION_RECORD; + +BOOLEAN +ImlAddIniSectionRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_INISECTION_ACTION Action, + PWSTR Name, + POFFSET Variables, // IML_INIVARIABLE_RECORD + POFFSET *Sections // IML_INISECTION_RECORD + ); + +typedef enum _IML_INI_ACTION { + CreateNewIniFile, + ModifyOldIniFile +} IML_INI_ACTION; + +typedef struct _IML_INI_RECORD { + POFFSET Next; // IML_INI_RECORD + IML_INI_ACTION Action; + POFFSET Name; // WCHAR + POFFSET Sections; // IML_INISECTION_RECORD + FILETIME LastWriteTime; +} IML_INI_RECORD, *PIML_INI_RECORD; + + +BOOLEAN +ImlAddIniRecord( + PINSTALLATION_MODIFICATION_LOGFILE pIml, + IML_INI_ACTION Action, + PWSTR Name, + PFILETIME BackupLastWriteTime, + POFFSET Sections // IML_INISECTION_RECORD + ); diff --git a/private/sdktools/instaler/ini.c b/private/sdktools/instaler/ini.c new file mode 100644 index 000000000..f50a177c7 --- /dev/null +++ b/private/sdktools/instaler/ini.c @@ -0,0 +1,382 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ini.c + +Abstract: + + This module implements the functions to save references to .INI file + sections and values for the INSTALER program. Part of each reference is + a a backup copy of sections and values for an .INI file. + +Author: + + Steve Wood (stevewo) 22-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + + +BOOLEAN +CreateIniFileReference( + PWSTR Name, + PINI_FILE_REFERENCE *ReturnedReference + ) +{ + PINI_FILE_REFERENCE p; + PINI_SECTION_REFERENCE p1; + PINI_VARIABLE_REFERENCE p2; + PWSTR SectionName; + PWSTR VariableName; + PWSTR VariableValue; + UNICODE_STRING UnicodeString; + PLIST_ENTRY Head, Next; + ULONG n, n1; + BOOLEAN Result; + HANDLE FindHandle; + WIN32_FIND_DATA FindFileData; + + p = FindIniFileReference( Name ); + if (p != NULL) { + *ReturnedReference = p; + return TRUE; + } + + p = AllocMem( sizeof( *p ) ); + if (p == NULL) { + return FALSE; + } + + p->Name = Name; + InitializeListHead( &p->SectionReferencesListHead ); + InsertTailList( &IniReferenceListHead, &p->Entry ); + FindHandle = FindFirstFile( Name, &FindFileData ); + if (FindHandle == INVALID_HANDLE_VALUE) { + p->Created = TRUE; + *ReturnedReference = p; + return TRUE; + } + FindClose( FindHandle ); + p->BackupLastWriteTime = FindFileData.ftLastWriteTime; + + GrowTemporaryBuffer( n = 0xF000 ); + SectionName = TemporaryBuffer; + + Result = TRUE; + n1 = GetPrivateProfileStringW( NULL, + NULL, + L"", + SectionName, + n, + Name + ); + if (n1 == 0 || n1 == n-2) { + Result = FALSE; + } + else { + while (*SectionName != UNICODE_NULL) { + p1 = AllocMem( sizeof( *p1 ) ); + if (p1 == NULL) { + Result = FALSE; + break; + } + + RtlInitUnicodeString( &UnicodeString, SectionName ); + p1->Name = AddName( &UnicodeString ); + if (FindIniSectionReference( p, p1->Name, FALSE )) { + FreeMem( &p1 ); + } + else { + InitializeListHead( &p1->VariableReferencesListHead ); + InsertTailList( &p->SectionReferencesListHead, &p1->Entry ); + } + while (*SectionName++ != UNICODE_NULL) { + } + } + } + + VariableName = TemporaryBuffer; + Head = &p->SectionReferencesListHead; + Next = Head->Flink; + while (Result && (Head != Next)) { + p1 = CONTAINING_RECORD( Next, INI_SECTION_REFERENCE, Entry ); + n1 = GetPrivateProfileSectionW( p1->Name, + VariableName, + n, + Name + ); + if (n1 == n-2) { + Result = FALSE; + break; + } + + while (*VariableName != UNICODE_NULL) { + VariableValue = VariableName; + while (*VariableValue != UNICODE_NULL && *VariableValue != L'=') { + VariableValue += 1; + } + + if (*VariableValue != L'=') { + Result = FALSE; + break; + } + *VariableValue++ = UNICODE_NULL; + + p2 = AllocMem( sizeof( *p2 ) + ((wcslen( VariableValue ) + 1) * sizeof( WCHAR )) ); + if (p2 == NULL) { + Result = FALSE; + break; + } + RtlInitUnicodeString( &UnicodeString, VariableName ); + p2->Name = AddName( &UnicodeString ); + p2->OriginalValue = (PWSTR)(p2+1); + wcscpy( p2->OriginalValue, VariableValue ); + InsertTailList( &p1->VariableReferencesListHead, &p2->Entry ); + + VariableName = VariableValue; + while (*VariableName++ != UNICODE_NULL) { + } + } + + Next = Next->Flink; + } + + + if (Result) { + *ReturnedReference = p; + } + else { + DestroyIniFileReference( p ); + } + + return Result; +} + + +BOOLEAN +DestroyIniFileReference( + PINI_FILE_REFERENCE p + ) +{ + PLIST_ENTRY Next, Head; + PINI_SECTION_REFERENCE p1; + + Head = &p->SectionReferencesListHead; + Next = Head->Flink; + while (Head != Next) { + p1 = CONTAINING_RECORD( Next, INI_SECTION_REFERENCE, Entry ); + Next = Next->Flink; + DestroyIniSectionReference( p1 ); + } + + RemoveEntryList( &p->Entry ); + FreeMem( &p ); + return TRUE; +} + + +BOOLEAN +DestroyIniSectionReference( + PINI_SECTION_REFERENCE p1 + ) +{ + PLIST_ENTRY Next, Head; + PINI_VARIABLE_REFERENCE p2; + + Head = &p1->VariableReferencesListHead; + Next = Head->Flink; + while (Head != Next) { + p2 = CONTAINING_RECORD( Next, INI_VARIABLE_REFERENCE, Entry ); + Next = Next->Flink; + DestroyIniVariableReference( p2 ); + } + + RemoveEntryList( &p1->Entry ); + FreeMem( &p1 ); + return TRUE; +} + + +BOOLEAN +DestroyIniVariableReference( + PINI_VARIABLE_REFERENCE p2 + ) +{ + RemoveEntryList( &p2->Entry ); + FreeMem( &p2 ); + return TRUE; +} + + +PINI_FILE_REFERENCE +FindIniFileReference( + PWSTR Name + ) +{ + PINI_FILE_REFERENCE p; + PLIST_ENTRY Next, Head; + + Head = &IniReferenceListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, INI_FILE_REFERENCE, Entry ); + if (p->Name == Name) { + return p; + } + + Next = Next->Flink; + } + + return NULL; +} + +PINI_SECTION_REFERENCE +FindIniSectionReference( + PINI_FILE_REFERENCE p, + PWSTR Name, + BOOLEAN CreateOkay + ) +{ + PLIST_ENTRY Next, Head; + PINI_SECTION_REFERENCE p1; + + Head = &p->SectionReferencesListHead; + Next = Head->Flink; + while (Head != Next) { + p1 = CONTAINING_RECORD( Next, INI_SECTION_REFERENCE, Entry ); + if (p1->Name == Name) { + return p1; + } + + Next = Next->Flink; + } + + if (CreateOkay) { + p1 = AllocMem( sizeof( *p1 ) ); + if (p1 != NULL) { + p1->Created = TRUE; + p1->Name = Name; + InitializeListHead( &p1->VariableReferencesListHead ); + InsertTailList( &p->SectionReferencesListHead, &p1->Entry ); + } + } + else { + p1 = NULL; + } + + return p1; +} + + +PINI_VARIABLE_REFERENCE +FindIniVariableReference( + PINI_SECTION_REFERENCE p1, + PWSTR Name, + BOOLEAN CreateOkay + ) +{ + PLIST_ENTRY Next, Head; + PINI_VARIABLE_REFERENCE p2; + + Head = &p1->VariableReferencesListHead; + Next = Head->Flink; + while (Head != Next) { + p2 = CONTAINING_RECORD( Next, INI_VARIABLE_REFERENCE, Entry ); + if (p2->Name == Name) { + return p2; + } + + Next = Next->Flink; + } + + if (CreateOkay) { + p2 = AllocMem( sizeof( *p2 ) ); + if (p2 != NULL) { + p2->Created = TRUE; + p2->Name = Name; + InsertTailList( &p1->VariableReferencesListHead, &p2->Entry ); + } + } + else { + p2 = NULL; + } + + return p2; +} + + +VOID +DumpIniFileReferenceList( + FILE *LogFile + ) +{ + PINI_FILE_REFERENCE p; + PINI_SECTION_REFERENCE p1; + PINI_VARIABLE_REFERENCE p2; + PLIST_ENTRY Head, Next; + PLIST_ENTRY Head1, Next1; + PLIST_ENTRY Head2, Next2; + POFFSET Variables; + POFFSET Sections; + + + Head = &IniReferenceListHead; + Next = Head->Blink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, INI_FILE_REFERENCE, Entry ); + Sections = 0; + Head1 = &p->SectionReferencesListHead; + Next1 = Head1->Blink; + while (Head1 != Next1) { + p1 = CONTAINING_RECORD( Next1, INI_SECTION_REFERENCE, Entry ); + Variables = 0; + Head2 = &p1->VariableReferencesListHead; + Next2 = Head2->Blink; + while (Head2 != Next2) { + p2 = CONTAINING_RECORD( Next2, INI_VARIABLE_REFERENCE, Entry ); + if (p2->Created || p2->Deleted || p2->Modified) { + ImlAddIniVariableRecord( pImlNew, + p2->Created ? CreateNewVariable : + p2->Deleted ? DeleteOldVariable : ModifyOldVariable, + p2->Name, + p2->OriginalValue, + p2->Value, + &Variables + ); + } + Next2 = Next2->Blink; + } + + if (Variables != 0) { + ImlAddIniSectionRecord( pImlNew, + p1->Created ? CreateNewSection : + p1->Deleted ? DeleteOldSection : ModifySectionVariables, + p1->Name, + Variables, + &Sections + ); + } + + Next1 = Next1->Blink; + } + + if (Sections != 0) { + ImlAddIniRecord( pImlNew, + p->Created ? CreateNewIniFile : ModifyOldIniFile, + p->Name, + &p->BackupLastWriteTime, + Sections + ); + } + + Next = Next->Blink; + } + + return; +} diff --git a/private/sdktools/instaler/init.c b/private/sdktools/instaler/init.c new file mode 100644 index 000000000..5a9a5c170 --- /dev/null +++ b/private/sdktools/instaler/init.c @@ -0,0 +1,770 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + This is the initialization module for the INSTALER program. + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +#if TRACE_ENABLED +ULONG EnabledTraceEvents = DBG_MASK_INTERNALERROR | + DBG_MASK_MEMORYERROR; +#endif + +MODULE_INFO ModuleInfo[ MAXIMUM_MODULE_INDEX ] = { + {L"NTDLL", NULL}, + {L"KERNEL32", NULL}, + {L"ADVAPI32", NULL} +}; + + + +API_INFO ApiInfo[ MAXIMUM_API_INDEX ] = { + {NTDLL_MODULE_INDEX, "NtCreateFile", NULL, NtCreateFileHandler , sizeof( CREATEFILE_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtOpenFile", NULL, NtOpenFileHandler , sizeof( OPENFILE_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtDeleteFile", NULL, NtDeleteFileHandler , sizeof( DELETEFILE_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtSetInformationFile", NULL, NtSetInformationFileHandler , sizeof( SETINFORMATIONFILE_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtQueryAttributesFile", NULL, NtQueryAttributesFileHandler , sizeof( QUERYATTRIBUTESFILE_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtQueryDirectoryFile", NULL, NtQueryDirectoryFileHandler , sizeof( QUERYDIRECTORYFILE_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtCreateKey", NULL, NtCreateKeyHandler , sizeof( CREATEKEY_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtOpenKey", NULL, NtOpenKeyHandler , sizeof( OPENKEY_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtDeleteKey", NULL, NtDeleteKeyHandler , sizeof( DELETEKEY_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtSetValueKey", NULL, NtSetValueKeyHandler , sizeof( SETVALUEKEY_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtDeleteValueKey", NULL, NtDeleteValueKeyHandler , sizeof( DELETEVALUEKEY_PARAMETERS ) , sizeof( NTSTATUS )}, + {NTDLL_MODULE_INDEX, "NtClose", NULL, NtCloseHandleHandler , sizeof( CLOSEHANDLE_PARAMETERS ) , sizeof( NTSTATUS )}, + {KERNEL32_MODULE_INDEX, "GetVersion", NULL, GetVersionHandler , 0 , sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "GetVersionExW", NULL, GetVersionExWHandler , sizeof( GETVERSIONEXW_PARAMETERS ) , sizeof( BOOL )}, + {KERNEL32_MODULE_INDEX, "SetCurrentDirectoryA", NULL, SetCurrentDirectoryAHandler , sizeof( SETCURRENTDIRECTORYA_PARAMETERS ) , sizeof( BOOL )}, + {KERNEL32_MODULE_INDEX, "SetCurrentDirectoryW", NULL, SetCurrentDirectoryWHandler , sizeof( SETCURRENTDIRECTORYW_PARAMETERS ) , sizeof( BOOL )}, + {KERNEL32_MODULE_INDEX, "WritePrivateProfileStringA", NULL, WritePrivateProfileStringAHandler , sizeof( WRITEPRIVATEPROFILESTRINGA_PARAMETERS ) , sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "WritePrivateProfileStringW", NULL, WritePrivateProfileStringWHandler , sizeof( WRITEPRIVATEPROFILESTRINGW_PARAMETERS ) , sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "WritePrivateProfileSectionA", NULL, WritePrivateProfileSectionAHandler, sizeof( WRITEPRIVATEPROFILESECTIONA_PARAMETERS ) , sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "WritePrivateProfileSectionW", NULL, WritePrivateProfileSectionWHandler, sizeof( WRITEPRIVATEPROFILESECTIONW_PARAMETERS ) , sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "GetPrivateProfileStringW", NULL, NULL, 0, sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "GetPrivateProfileStringA", NULL, NULL, 0, sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "GetPrivateProfileSectionW", NULL, NULL, 0, sizeof( DWORD )}, + {KERNEL32_MODULE_INDEX, "GetPrivateProfileSectionA", NULL, NULL, 0, sizeof( DWORD )}, + {ADVAPI32_MODULE_INDEX, "RegConnectRegistryW", NULL, RegConnectRegistryWHandler , sizeof( REGCONNECTREGISTRYW_PARAMETERS ) , sizeof( DWORD )} +}; + +BOOLEAN +LoadApplicationForDebug( + PWSTR CommandLine + ); + +BOOLEAN +LoadDriveLetterDefinitions( VOID ); + +WCHAR WindowsDirectoryBuffer[ MAX_PATH ]; +UNICODE_STRING WindowsDirectory; + +BOOLEAN +InitializeInstaler( + int argc, + char *argv[] + ) +{ + UINT ModuleIndex, ApiIndex; + PWSTR CommandLine; + UINT i; + LPSTR s; + UCHAR c; + SYSTEM_INFO SystemInfo; + BOOLEAN ProcessingDebugSwitch; + + InitCommonCode( "INSTALER", + "[-9] [-r] [-dAE] CommandLine...", + "-9 specifies that GetVersion should lie and tell application\n" + " that it is running on Windows 95\n" + "-r specifies that attempts to do a wildcard scan of the root\n" + " directory of a drive should fail.\n" + "-d specifies one or more debugging message options\n" + " A - shows all errors\n" + " E - shows all debug events\n" + " C - shows all create API calls\n" + ); + + AppHeap = GetProcessHeap(); + InstalerModuleHandle = GetModuleHandle( NULL ); + + GetWindowsDirectoryW( WindowsDirectoryBuffer, MAX_PATH ); + RtlInitUnicodeString( &WindowsDirectory, WindowsDirectoryBuffer ); + + GetSystemInfo( &SystemInfo ); + + TemporaryBufferLengthGrowth = SystemInfo.dwPageSize; + TemporaryBufferMaximumLength = ((128 * 1024) + SystemInfo.dwAllocationGranularity - 1) & + ~SystemInfo.dwAllocationGranularity; + TemporaryBuffer = VirtualAlloc( NULL, + TemporaryBufferMaximumLength, + MEM_RESERVE, + PAGE_READWRITE + ); + if (TemporaryBuffer == NULL) { + return FALSE; + } + + InitializeListHead( &ProcessListHead ); + InitializeListHead( &FileReferenceListHead ); + InitializeListHead( &KeyReferenceListHead ); + InitializeListHead( &IniReferenceListHead ); + InitializeCriticalSection( &BreakTable ); + + // + // Loop over the table of modules and make sure each is loaded in our + // address space so we can access their export tables. + // + for (ModuleIndex=0; ModuleIndex<MAXIMUM_MODULE_INDEX; ModuleIndex++) { + ModuleInfo[ ModuleIndex ].ModuleHandle = + GetModuleHandle( ModuleInfo[ ModuleIndex ].ModuleName ); + + if (ModuleInfo[ ModuleIndex ].ModuleHandle == NULL) { + // + // Bail if any are missing. + // + DeclareError( INSTALER_MISSING_MODULE, + GetLastError(), + ModuleInfo[ ModuleIndex ].ModuleName + ); + return FALSE; + } + } + + // + // Now loop over the table of entry points that we care about and + // get the address of each entry point from the + + for (ApiIndex=0; ApiIndex<MAXIMUM_API_INDEX; ApiIndex++) { + ModuleIndex = ApiInfo[ ApiIndex ].ModuleIndex; + + ApiInfo[ ApiIndex ].EntryPointAddress = + LookupEntryPointInIAT( ModuleInfo[ ModuleIndex ].ModuleHandle, + ApiInfo[ ApiIndex ].EntryPointName + ); + + if (ApiInfo[ ApiIndex ].EntryPointAddress == NULL) { + // + // Bail if we are unable to get the address of any of them + // + DeclareError( INSTALER_MISSING_ENTRYPOINT, + GetLastError(), + ApiInfo[ ApiIndex ].EntryPointName, + ModuleInfo[ ModuleIndex ].ModuleName + ); + return FALSE; + } + } + + CommandLine = NULL; + ProcessingDebugSwitch = FALSE; + AskUserOnce = FALSE; + while (--argc) { + s = *++argv; + if (*s == '-' || *s == '/') { + while (*++s) { + switch( tolower( *s ) ) { + case '9': + DefaultGetVersionToWin95 = TRUE; + break; + + case 'r': + FailAllScansOfRootDirectories = TRUE; + break; +#if TRACE_ENABLED + case 'd': + ProcessingDebugSwitch = TRUE; + break; + + case 'a': + if (ProcessingDebugSwitch) { + EnabledTraceEvents = 0xFFFFFFFF; + break; + } + case 'e': + if (ProcessingDebugSwitch) { + EnabledTraceEvents |= DBG_MASK_DBGEVENT; + break; + } + case 'c': + if (ProcessingDebugSwitch) { + EnabledTraceEvents |= DBG_MASK_CREATEEVENT; + break; + } +#endif + default: + if (!ProcessingDebugSwitch) { + CommonSwitchProcessing( &argc, &argv, *s ); + } + else { + Usage( "Invalid debug switch (-%c)", (ULONG)*s ); + } + break; + } + } + + ProcessingDebugSwitch = FALSE; + } + else + if (!CommonArgProcessing( &argc, &argv )) { + CommandLine = GetCommandLine(); + while (*CommandLine && *CommandLine <= L' ') { + CommandLine += 1; + } + + while (*CommandLine && *CommandLine > L' ') { + CommandLine += 1; + } + + CommandLine = wcsstr( CommandLine, GetArgAsUnicode( s ) ); + break; + } + } + + if (ImlPath == NULL) { + Usage( "Must specify an installation name as first argument", 0 ); + } + + if (CommandLine == NULL) { + Usage( "Command line missing", 0 ); + } + + pImlNew = CreateIml( ImlPath, FALSE ); + if (pImlNew == NULL) { + FatalError( "Unable to create %ws (%u)\n", + (ULONG)ImlPath, + GetLastError() + ); + } + + // + // Ready to roll. Cache the drive letter information and then load + // the application with the DEBUG option so we can watch what it does + // + if (!LoadDriveLetterDefinitions() || + !LoadApplicationForDebug( CommandLine ) + ) { + return FALSE; + } + + return TRUE; +} + +BOOLEAN +LoadApplicationForDebug( + PWSTR CommandLine + ) +{ + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInformation; + PWSTR ImageFilePath; + PWSTR ImageFileName; + PWSTR CurrentDirectory; + PWSTR TemporaryNull; + WCHAR TemporaryChar; + ULONG Length; + WCHAR PathBuffer[ MAX_PATH ]; + + TemporaryNull = CommandLine; + while(TemporaryChar = *TemporaryNull) { + if (TemporaryChar == L' ' || TemporaryChar == L'\t') { + *TemporaryNull = UNICODE_NULL; + break; + } + + TemporaryNull += 1; + } + + ImageFilePath = AllocMem( MAX_PATH * sizeof( WCHAR ) ); + Length = SearchPath( NULL, + CommandLine, + L".exe", + MAX_PATH, + ImageFilePath, + &ImageFileName + ); + *TemporaryNull = TemporaryChar; + if (!Length || Length >= MAX_PATH) { + DeclareError( INSTALER_CANT_DEBUG_PROGRAM, + GetLastError(), + CommandLine + ); + return FALSE; + } + + if (ImageFileName != NULL && + ImageFileName > ImageFilePath && + ImageFileName[ -1 ] == L'\\' + ) { + ImageFileName[ -1 ] = UNICODE_NULL; + CurrentDirectory = wcscpy( PathBuffer, ImageFilePath ); + ImageFileName[ -1 ] = L'\\'; + SetCurrentDirectory( CurrentDirectory ); + } + else { + CurrentDirectory = NULL; + } + + memset( &StartupInfo, 0, sizeof( StartupInfo ) ); + StartupInfo.cb = sizeof(StartupInfo); + + // + // Create the process with DEBUG option, as a separate WOW so we only see our + // application's damage. + // + if (!CreateProcess( ImageFilePath, + CommandLine, + NULL, + NULL, + FALSE, // No handles to inherit + DEBUG_PROCESS | + CREATE_SEPARATE_WOW_VDM, // Ignored for 32 bit apps + NULL, + CurrentDirectory, + &StartupInfo, + &ProcessInformation + ) + ) { + DeclareError( INSTALER_CANT_DEBUG_PROGRAM, + GetLastError(), + CommandLine + ); + return FALSE; + } + else { + sprintf( (LPSTR)PathBuffer, "%ws%ws.log", InstalerDirectory, InstallationName ); + InstalerLogFile = fopen( (LPSTR)PathBuffer, "w" ); + + // + // Will pick up the process and thread handles with the + // CREATE_PROCESS_DEBUG_EVENT and CREATE_PROCESS_THREAD_EVENT + // + return TRUE; + } +} + + +PVOID +LookupEntryPointInIAT( + HMODULE ModuleHandle, + PCHAR EntryPointName + ) +{ + PIMAGE_EXPORT_DIRECTORY Exports; + PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries; + DWORD NumberOfFunctionTableEntries; + ULONG ExportSize, FunctionTableSize; + PCHAR *EntryPointNames; + PULONG EntryPointAddresses; + PUSHORT EntryPointOrdinals; + PVOID EntryPointAddress; + ULONG i; + + Exports = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( ModuleHandle, + TRUE, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &ExportSize + ); + if (Exports == NULL) { + return NULL; + } + + FunctionTableEntries = (PIMAGE_RUNTIME_FUNCTION_ENTRY) + RtlImageDirectoryEntryToData( ModuleHandle, + TRUE, + IMAGE_DIRECTORY_ENTRY_EXCEPTION, + &FunctionTableSize + ); + if (FunctionTableEntries != NULL) { + NumberOfFunctionTableEntries = FunctionTableSize / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); + } + else { + NumberOfFunctionTableEntries = 0; + } + + EntryPointNames = (PCHAR *)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNames); + EntryPointOrdinals = (PUSHORT)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNameOrdinals); + EntryPointAddresses = (PULONG)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfFunctions); + for (i=0; i<Exports->NumberOfNames; i++) { + EntryPointAddress = (PVOID)((PCHAR)ModuleHandle + + EntryPointAddresses[ EntryPointOrdinals[ i ] ] + ); + if ((ULONG)EntryPointAddress > (ULONG)Exports && + (ULONG)EntryPointAddress < ((ULONG)Exports + ExportSize) + ) { + // + // Skip this... It's a forwarded reference + } + else + if (!_stricmp( EntryPointName, (PCHAR)ModuleHandle + (ULONG)EntryPointNames[ i ] )) { + return GetAddressForEntryPointBreakpoint( EntryPointAddress, + NumberOfFunctionTableEntries, + FunctionTableEntries + ); + } + } + + DbgEvent( INTERNALERROR, ( "Unable to find entry point '%s' in module at %x\n", EntryPointName, ModuleHandle ) ); + return NULL; +} + + +PVOID +GetAddressForEntryPointBreakpoint( + PVOID EntryPointAddress, + DWORD NumberOfFunctionTableEntries OPTIONAL, + PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries OPTIONAL + ) +{ + PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry; + PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable; + LONG High; + LONG Low; + LONG Middle; + + // + // If no function table, then okay to set breakpoint at exported + // address. + // + if (NumberOfFunctionTableEntries == 0) { + return EntryPointAddress; + } + + // + // Initialize search indicies. + // + Low = 0; + High = NumberOfFunctionTableEntries - 1; + FunctionTable = FunctionTableEntries; + + // + // Perform binary search on the function table for a function table + // entry that subsumes the specified PC. + // + while (High >= Low) { + // + // Compute next probe index and test entry. If the specified PC + // is greater than of equal to the beginning address and less + // than the ending address of the function table entry, then + // return the address of the function table entry. Otherwise, + // continue the search. + // + Middle = (Low + High) >> 1; + FunctionEntry = &FunctionTable[Middle]; + if ((ULONG)EntryPointAddress < FunctionEntry->BeginAddress) { + High = Middle - 1; + } + else + if ((ULONG)EntryPointAddress >= FunctionEntry->EndAddress) { + Low = Middle + 1; + } + else { + if (((ULONG)EntryPointAddress >= FunctionEntry->BeginAddress) && + ((ULONG)EntryPointAddress < FunctionEntry->PrologEndAddress)) { + return (PVOID)FunctionEntry->PrologEndAddress; + } + else { + break; + } + } + } + + // + // A function table entry for the specified PC was not found. Just use + // the exported address and hope for the best. + // + return EntryPointAddress; +} + + +BOOLEAN +LoadDriveLetterDefinitions( VOID ) +{ + PVOID Buffer; + ULONG BufferSize; + ULONG cchDeviceName; + ULONG cch; + ULONG cchTargetPath; + PWSTR DeviceName; + PWSTR TargetPath; + ULONG DriveLetterIndex; + ULONG cb; + PDRIVE_LETTER_INFO p; + + RtlInitUnicodeString( &AltDriveLetterPrefix, L"\\DosDevices\\" ); + RtlInitUnicodeString( &DriveLetterPrefix, L"\\??\\" ); + RtlInitUnicodeString( &UNCPrefix, L"UNC\\" ); + + BufferSize = 0x1000; + Buffer = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE ); + if (Buffer == NULL) { + DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n", + BufferSize, + GetLastError() + ) + ); + + return FALSE; + } + + cchTargetPath = BufferSize / sizeof( WCHAR ); + cchDeviceName = QueryDosDeviceW( NULL, + Buffer, + cchTargetPath + ); + if (cchDeviceName == 0) { + DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( NULL ) failed (%u)\n", + GetLastError() + ) + ); + return FALSE; + } + + cchTargetPath -= (cchDeviceName + 2); + DeviceName = Buffer; + TargetPath = DeviceName + 2 + cchDeviceName; + while (*DeviceName) { + if (wcslen( DeviceName ) == 2 && + DeviceName[ 1 ] == L':' && + _wcsupr( DeviceName ) && + DeviceName[ 0 ] >= L'@' && + DeviceName[ 0 ] <= L'_' + ) { + cch = QueryDosDeviceW( DeviceName, TargetPath, cchTargetPath ); + if (cch == 0) { + DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( %ws ) failed (%u)\n", + DeviceName, + GetLastError() + ) + ); + return FALSE; + } + + DriveLetterIndex = DeviceName[ 0 ] - L'@'; + p = &DriveLetters[ DriveLetterIndex ]; + p->DriveLetter = (WCHAR)(L'@' + DriveLetterIndex); + cb = (cch+1) * sizeof( WCHAR ); + p->NtLinkTarget.Buffer = AllocMem( cb ); + if (p->NtLinkTarget.Buffer == NULL) { + return FALSE; + } + MoveMemory( p->NtLinkTarget.Buffer, TargetPath, cb ); + p->NtLinkTarget.Length = (USHORT)( cb - sizeof( WCHAR )); + p->NtLinkTarget.MaximumLength = (USHORT)cb; + p->DriveLetterValid = TRUE; + } + + while (*DeviceName++) + ; + } + + return TRUE; +} + + +BOOLEAN +IsDriveLetterPath( + PUNICODE_STRING Path + ) +{ + ULONG DriveLetterIndex; + PDRIVE_LETTER_INFO p; + PUNICODE_STRING Prefix; + + if (RtlPrefixUnicodeString( Prefix = &DriveLetterPrefix, Path, TRUE ) || + RtlPrefixUnicodeString( Prefix = &AltDriveLetterPrefix, Path, TRUE ) + ) { + Path->Length -= Prefix->Length; + RtlMoveMemory( Path->Buffer, + (PCHAR)(Path->Buffer) + Prefix->Length, + Path->Length + sizeof( UNICODE_NULL ) + ); + if (RtlPrefixUnicodeString( &UNCPrefix, Path, TRUE )) { + Path->Length -= UNCPrefix.Length; + Path->Buffer[0] = L'\\'; + Path->Buffer[1] = L'\\'; + RtlMoveMemory( &Path->Buffer[2], + (PCHAR)(Path->Buffer) + UNCPrefix.Length, + Path->Length + sizeof( UNICODE_NULL ) + ); + Path->Length += 2 * sizeof( WCHAR ); + } + + return TRUE; + } + + for (DriveLetterIndex=0, p = &DriveLetters[ DriveLetterIndex ]; + DriveLetterIndex<32; + DriveLetterIndex++, p++ + ) { + if (p->DriveLetterValid && + RtlPrefixUnicodeString( &p->NtLinkTarget, Path, TRUE ) + ) { + Path->Length -= p->NtLinkTarget.Length; + RtlMoveMemory( &Path->Buffer[ 2 ], + (PCHAR)(Path->Buffer) + p->NtLinkTarget.Length, + Path->Length + sizeof( UNICODE_NULL ) + ); + Path->Buffer[ 0 ] = p->DriveLetter; + Path->Buffer[ 1 ] = L':'; + Path->Length += 2; + return TRUE; + } + } + + return FALSE; +} + + + +VOID +TrimTemporaryBuffer( VOID ) +{ + PVOID CommitAddress; + + if (TemporaryBufferLength == 0) { + return; + } + + if (VirtualFree( (PCHAR)TemporaryBuffer, + TemporaryBufferLength, + MEM_DECOMMIT + ) + ) { + TemporaryBufferLength = 0; + } + + return; +} + +BOOLEAN +GrowTemporaryBuffer( + ULONG NeededSize + ) +{ + PVOID CommitAddress; + + if (NeededSize <= TemporaryBufferLength) { + return TRUE; + } + + if (TemporaryBufferLength == TemporaryBufferMaximumLength) { + return FALSE; + } + + CommitAddress = VirtualAlloc( (PCHAR)TemporaryBuffer + TemporaryBufferLength, + NeededSize - TemporaryBufferLength, + MEM_COMMIT, + PAGE_READWRITE + ); + if (CommitAddress == NULL) { + DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n", + NeededSize - TemporaryBufferLength, + GetLastError() + ) + ); + + return FALSE; + } + + TemporaryBufferLength += TemporaryBufferLengthGrowth; + return TRUE; +} + +ULONG +FillTemporaryBuffer( + PPROCESS_INFO Process, + PVOID Address, + BOOLEAN Unicode, + BOOLEAN DoubleNullTermination + ) +{ + ULONG BytesRead; + ULONG TotalBytesRead; + PVOID Source; + PVOID Destination; + LPSTR s1; + PWSTR s2; + BOOLEAN MoreToRead; + BOOLEAN SeenOneNull; + + TotalBytesRead = 0; + Destination = (PCHAR)TemporaryBuffer; + MoreToRead = TRUE; + SeenOneNull = FALSE; + while (MoreToRead) { + TotalBytesRead += TemporaryBufferLengthGrowth; + if (!GrowTemporaryBuffer( TotalBytesRead )) { + return 0; + } + + Source = Destination; + if (!ReadProcessMemory( Process->Handle, + Address, + Destination, + TemporaryBufferLengthGrowth, + &BytesRead + ) + ) { + if (BytesRead == 0) { + MoreToRead = FALSE; + } + else { + return 0; + } + } + + Destination = (PCHAR)Destination + TotalBytesRead; + if (Unicode) { + s2 = (PWSTR)Source; + while (s2 < (PWSTR)Destination) { + if (*s2 == UNICODE_NULL) { + if (SeenOneNull || !DoubleNullTermination) { + return (PCHAR)s2 - (PCHAR)TemporaryBuffer; + } + else { + SeenOneNull = TRUE; + } + } + else { + SeenOneNull = FALSE; + } + + s2++; + } + } + else { + s1 = (LPSTR)Source; + while (s1 < (LPSTR)Destination) { + if (*s1 == '\0') { + if (SeenOneNull || !DoubleNullTermination) { + return (PCHAR)s1 - (PCHAR)TemporaryBuffer; + } + else { + SeenOneNull = TRUE; + } + } + else { + SeenOneNull = FALSE; + } + + s1++; + } + } + } + + return 0; +} diff --git a/private/sdktools/instaler/instaler.c b/private/sdktools/instaler/instaler.c new file mode 100644 index 000000000..e3b73297c --- /dev/null +++ b/private/sdktools/instaler/instaler.c @@ -0,0 +1,159 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + instaler.c + +Abstract: + + USAGE: instaler "setup/install command line" + + Main source file for the INSTALER application. This application is + intended for use as a wrapper application around another + application's setup/install program. This program uses the Debugger + API calls to set breakpoints in the setup/install program and its + descendents at all calls to NT/Win32 API calls that modify the + current system. The API calls that are tracked include: + + NtCreateFile + NtDeleteFile + NtSetInformationFile (FileRenameInformation, FileDispositionInformation) + NtCreateKey + NtOpenKey + NtDeleteKey + NtSetValueKey + NtDeleteValueKey + GetVersion + GetVersionExW + WriteProfileStringA/W + WritePrivateProfileStringA/W + WriteProfileSectionA/W + WritePrivateProfileSectionA/W + RegConnectRegistryW + + This program sets breakpoints around each of the above API entry + points. At the breakpoint at the entry to an API call, the + parameters are inspected and if the call is going to overwrite some + state (e.g. create/open a file/key for write access, store a new + key value or profile string), then this program will save the old + state in a temporary directory before letting the API call proceed. + At the exit from the API call, it will determine if the operation + was successful. If not, the saved state will be discarded. If + successful, it will keep the saved state for when the application + setup/install program completes. Part of the Create/Open API + tracking is the maintenance of a handle database so that relative opens + can be handled correctly with the full path. + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +--*/ + +#include "instaler.h" + +BOOLEAN +SortReferenceList( + PLIST_ENTRY OldHead, + ULONG NumberOfEntriesInList + ); + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + if (!InitializeInstaler( argc, argv )) { + ExitProcess( 1 ); + } + else { + StartProcessTickCount = GetTickCount(); + DebugEventLoop(); + printf( "Creating %ws\n", ImlPath ); + SortReferenceList( &FileReferenceListHead, NumberOfFileReferences ); + SortReferenceList( &KeyReferenceListHead, NumberOfKeyReferences ); + SortReferenceList( &IniReferenceListHead, NumberOfIniReferences ); + DumpFileReferenceList( InstalerLogFile ); + DumpKeyReferenceList( InstalerLogFile ); + DumpIniFileReferenceList( InstalerLogFile ); + DumpNameDataBase( InstalerLogFile ); + CloseIml( pImlNew ); + fclose( InstalerLogFile ); + ExitProcess( 0 ); + } + + return 0; +} + + +typedef struct _GENERIC_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; +} GENERIC_REFERENCE, *PGENERIC_REFERENCE; + + +int +_CRTAPI1 +CompareReferences( + const void *Reference1, + const void *Reference2 + ) +{ + PGENERIC_REFERENCE p1 = *(PGENERIC_REFERENCE *)Reference1; + PGENERIC_REFERENCE p2 = *(PGENERIC_REFERENCE *)Reference2; + + return _wcsicmp( p1->Name, p2->Name ); +} + + +BOOLEAN +SortReferenceList( + PLIST_ENTRY Head, + ULONG NumberOfEntriesInList + ) +{ + PGENERIC_REFERENCE p, *SortedArray; + PLIST_ENTRY Next; + ULONG i; + + if (NumberOfEntriesInList == 0) { + return TRUE; + } + + SortedArray = AllocMem( NumberOfEntriesInList * sizeof( *SortedArray ) ); + if (SortedArray == NULL) { + return FALSE; + } + + Next = Head->Flink; + i = 0; + while (Head != Next) { + p = CONTAINING_RECORD( Next, GENERIC_REFERENCE, Entry ); + if (i >= NumberOfEntriesInList) { + break; + } + + SortedArray[ i++ ] = p; + Next = Next->Flink; + } + + qsort( (void *)SortedArray, + NumberOfEntriesInList, + sizeof( *SortedArray ), + CompareReferences + ); + + InitializeListHead( Head ); + for (i=0; i<NumberOfEntriesInList; i++) { + p = SortedArray[ i ]; + InsertTailList( Head, &p->Entry ); + } + + FreeMem( (PVOID *)&SortedArray ); + + return TRUE; +} diff --git a/private/sdktools/instaler/instaler.h b/private/sdktools/instaler/instaler.h new file mode 100644 index 000000000..5ae44b683 --- /dev/null +++ b/private/sdktools/instaler/instaler.h @@ -0,0 +1,1165 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + instaler.h + +Abstract: + + Main include file for the INSTALER application. + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +Revision History: + +--*/ + +#ifdef RC_INVOKED +#include <windows.h> + +#define FILEBMP 500 +#define DIRBMP 501 + +#else + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntdbg.h> +#include <windows.h> +#include <vdmdbg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "errormsg.h" + +// +// Data structures and entry points in ERROR.C +// + +#define TRACE_ENABLED 1 + +#if TRACE_ENABLED +extern ULONG EnabledTraceEvents; + +#define DBG_MASK_DBGEVENT 0x00000001 +#define DBG_MASK_INTERNALERROR 0x00000002 +#define DBG_MASK_MEMORYERROR 0x00000004 +#define DBG_MASK_CREATEEVENT 0x00000008 + +VOID +TraceDisplay( + const char *FormatString, + ... + ); + +#define DbgEvent( m, x ) if (EnabledTraceEvents & (DBG_MASK_##m)) TraceDisplay x +#define TestDbgEvent( m ) (EnabledTraceEvents & (DBG_MASK_##m)) +#else +#define DbgEvent( m, x ) +#define TestDbgEvent( m ) (FALSE) +#endif + + +VOID +CDECL +DeclareError( + UINT ErrorCode, + UINT SupplementalErrorCode, + ... + ); + +UINT +CDECL +AskUser( + UINT MessageBoxFlags, + UINT MessageId, + UINT NumberOfArguments, + ... + ); + + +// +// Data structures and entry points in EVENT.C +// + +VOID +CDECL +LogEvent( + UINT MessageId, + UINT NumberOfArguments, + ... + ); + +// +// Data structures and entry points in PROCESS.C +// + +#define HANDLE_TYPE_FILE 0 +#define HANDLE_TYPE_KEY 1 +#define HANDLE_TYPE_NONE 2 + +typedef struct _OPENHANDLE_INFO { + LIST_ENTRY Entry; + HANDLE Handle; + BOOLEAN Inherit; + BOOLEAN RootDirectory; + USHORT Type; + USHORT LengthOfName; + PWSTR Name; + + // + // Union for handlers that need to store state in a handle during + // use. + // + union { + PWSTR QueryName; + }; +} OPENHANDLE_INFO, *POPENHANDLE_INFO; + +typedef struct _PROCESS_INFO { + LIST_ENTRY Entry; + LIST_ENTRY ThreadListHead; + LIST_ENTRY BreakpointListHead; + LIST_ENTRY OpenHandleListHead; + DWORD Id; + HANDLE Handle; + PROCESS_BASIC_INFORMATION ProcessInformation; + WCHAR ImageFileName[ 32 ]; +} PROCESS_INFO, *PPROCESS_INFO; + +typedef struct _THREAD_INFO { + LIST_ENTRY Entry; + LIST_ENTRY BreakpointListHead; + DWORD Id; + HANDLE Handle; + PVOID StartAddress; + ULONG ModuleIndexCurrentlyIn; + BOOLEAN SingleStepExpected; + struct _BREAKPOINT_INFO *BreakpointToStepOver; +} THREAD_INFO, *PTHREAD_INFO; + +LIST_ENTRY ProcessListHead; + +BOOLEAN +AddProcess( + LPDEBUG_EVENT DebugEvent, + PPROCESS_INFO *ReturnedProcess + ); + +BOOLEAN +DeleteProcess( + PPROCESS_INFO Process + ); + +BOOLEAN +AddThread( + LPDEBUG_EVENT DebugEvent, + PPROCESS_INFO Process, + PTHREAD_INFO *ReturnedThread + ); + +BOOLEAN +DeleteThread( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ); + +PPROCESS_INFO +FindProcessById( + ULONG Id + ); + +BOOLEAN +FindProcessAndThreadForEvent( + LPDEBUG_EVENT DebugEvent, + PPROCESS_INFO *ReturnedProcess, + PTHREAD_INFO *ReturnedThread + ); + +BOOLEAN +HandleThreadsForSingleStep( + PPROCESS_INFO Process, + PTHREAD_INFO ThreadToSingleStep, + BOOLEAN SuspendThreads + ); + +BOOLEAN +ReadMemory( + PPROCESS_INFO Process, + PVOID Address, + PVOID DataRead, + ULONG BytesToRead, + PCHAR Reason + ); + +BOOLEAN +WriteMemory( + PPROCESS_INFO Process, + PVOID Address, + PVOID DataToWrite, + ULONG BytesToWrite, + PCHAR Reason + ); + +PVOID +AllocMem( + ULONG Size + ); + +VOID +FreeMem( + PVOID *p + ); + + +// +// Data structures and entry points in MACHINE.C +// + +PVOID BreakpointInstruction; +ULONG SizeofBreakpointInstruction; + +PVOID +GetAddressForEntryPointBreakpoint( + PVOID EntryPointAddress, + DWORD NumberOfFunctionTableEntries OPTIONAL, + PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries OPTIONAL + ); + +BOOLEAN +SkipOverHardcodedBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PVOID BreakpointAddress + ); + +BOOLEAN +ExtractProcedureParameters( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PULONG ReturnAddress, + ULONG SizeOfParameters, + PULONG Parameters + ); + +BOOLEAN +ExtractProcedureReturnValue( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PVOID ReturnValue, + ULONG SizeOfReturnValue + ); + +BOOLEAN +SetProcedureReturnValue( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PVOID ReturnValue, + ULONG SizeOfReturnValue + ); + +BOOLEAN +ForceReturnToCaller( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + ULONG SizeOfParameters, + PVOID ReturnAddress, + PVOID ReturnValue, + ULONG SizeOfReturnValue + ); + +BOOLEAN +UndoReturnAddressBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ); + +BOOLEAN +BeginSingleStepBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ); + +BOOLEAN +EndSingleStepBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ); + +typedef enum _API_ACTION { + QueryPath, + OpenPath, + RenamePath, + DeletePath, + SetValue, + DeleteValue, + WriteIniValue, + WriteIniSection +} API_ACTION; + +typedef struct _API_SAVED_CALL_STATE { + LIST_ENTRY Entry; + API_ACTION Action; + ULONG Type; + PWSTR FullName; + PVOID Reference; + union { + struct { + BOOLEAN InheritHandle; + BOOLEAN WriteAccessRequested; + PHANDLE ResultHandleAddress; + } PathOpen; + struct { + PWSTR NewName; + BOOLEAN ReplaceIfExists; + } PathRename; + struct { + PWSTR SectionName; + PWSTR VariableName; + PWSTR VariableValue; + } SetIniValue; + struct { + PWSTR SectionName; + PWSTR SectionValue; + } SetIniSection; + }; +} API_SAVED_CALL_STATE, *PAPI_SAVED_CALL_STATE; + +BOOLEAN +CreateSavedCallState( + PPROCESS_INFO Process, + PAPI_SAVED_CALL_STATE SavedCallState, + API_ACTION Action, + ULONG Type, + PWSTR FullName, + ... + ); + +VOID +FreeSavedCallState( + PAPI_SAVED_CALL_STATE CallState + ); + + + +// +// Data structures and entry points in HANDLER.C +// + +typedef struct _CREATEFILE_PARAMETERS { + PHANDLE FileHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + PIO_STATUS_BLOCK IoStatusBlock; + PLARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG ShareAccess; + ULONG CreateDisposition; + ULONG CreateOptions; +} CREATEFILE_PARAMETERS, *PCREATEFILE_PARAMETERS; + +typedef struct _OPENFILE_PARAMETERS { + PHANDLE FileHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + PIO_STATUS_BLOCK IoStatusBlock; + ULONG ShareAccess; + ULONG OpenOptions; +} OPENFILE_PARAMETERS, *POPENFILE_PARAMETERS; + +typedef struct _DELETEFILE_PARAMETERS { + POBJECT_ATTRIBUTES ObjectAttributes; +} DELETEFILE_PARAMETERS, *PDELETEFILE_PARAMETERS; + +typedef struct _SETINFORMATIONFILE_PARAMETERS { + HANDLE FileHandle; + PIO_STATUS_BLOCK IoStatusBlock; + PVOID FileInformation; + ULONG Length; + FILE_INFORMATION_CLASS FileInformationClass; +} SETINFORMATIONFILE_PARAMETERS, *PSETINFORMATIONFILE_PARAMETERS; + +typedef struct _QUERYATTRIBUTESFILE_PARAMETERS { + POBJECT_ATTRIBUTES ObjectAttributes; + PFILE_BASIC_INFORMATION FileInformation; +} QUERYATTRIBUTESFILE_PARAMETERS, *PQUERYATTRIBUTESFILE_PARAMETERS; + +typedef struct _QUERYDIRECTORYFILE_PARAMETERS { + HANDLE FileHandle; + HANDLE Event; + PIO_APC_ROUTINE ApcRoutine; + PVOID ApcContext; + PIO_STATUS_BLOCK IoStatusBlock; + PVOID FileInformation; + ULONG Length; + FILE_INFORMATION_CLASS FileInformationClass; + BOOLEAN ReturnSingleEntry; + PUNICODE_STRING FileName; + BOOLEAN RestartScan; +} QUERYDIRECTORYFILE_PARAMETERS, *PQUERYDIRECTORYFILE_PARAMETERS; + +typedef struct _CREATEKEY_PARAMETERS { + PHANDLE KeyHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + ULONG TitleIndex; + PUNICODE_STRING Class; + ULONG CreateOptions; + PULONG Disposition; +} CREATEKEY_PARAMETERS, *PCREATEKEY_PARAMETERS; + +typedef struct _OPENKEY_PARAMETERS { + PHANDLE KeyHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; +} OPENKEY_PARAMETERS, *POPENKEY_PARAMETERS; + +typedef struct _DELETEKEY_PARAMETERS { + HANDLE KeyHandle; +} DELETEKEY_PARAMETERS, *PDELETEKEY_PARAMETERS; + +typedef struct _SETVALUEKEY_PARAMETERS { + HANDLE KeyHandle; + PUNICODE_STRING ValueName; + ULONG TitleIndex; + ULONG Type; + PVOID Data; + ULONG DataLength; +} SETVALUEKEY_PARAMETERS, *PSETVALUEKEY_PARAMETERS; + +typedef struct _DELETEVALUEKEY_PARAMETERS { + HANDLE KeyHandle; + PUNICODE_STRING ValueName; +} DELETEVALUEKEY_PARAMETERS, *PDELETEVALUEKEY_PARAMETERS; + +typedef struct _CLOSEHANDLE_PARAMETERS { + HANDLE Handle; +} CLOSEHANDLE_PARAMETERS, *PCLOSEHANDLE_PARAMETERS; + +typedef struct _GETVERSIONEXW_PARAMETERS { + LPOSVERSIONINFOA lpVersionInformation; +} GETVERSIONEXW_PARAMETERS, *PGETVERSIONEXW_PARAMETERS; + +typedef struct _SETCURRENTDIRECTORYA_PARAMETERS { + LPSTR lpPathName; +} SETCURRENTDIRECTORYA_PARAMETERS, *PSETCURRENTDIRECTORYA_PARAMETERS; + +typedef struct _SETCURRENTDIRECTORYW_PARAMETERS { + PWSTR lpPathName; +} SETCURRENTDIRECTORYW_PARAMETERS, *PSETCURRENTDIRECTORYW_PARAMETERS; + +typedef struct _WRITEPRIVATEPROFILESTRINGA_PARAMETERS { + LPCSTR lpAppName; + LPCSTR lpKeyName; + LPCSTR lpString; + LPCSTR lpFileName; +} WRITEPRIVATEPROFILESTRINGA_PARAMETERS, *PWRITEPRIVATEPROFILESTRINGA_PARAMETERS; + +typedef struct _WRITEPRIVATEPROFILESTRINGW_PARAMETERS { + LPCWSTR lpAppName; + LPCWSTR lpKeyName; + LPCWSTR lpString; + LPCWSTR lpFileName; +} WRITEPRIVATEPROFILESTRINGW_PARAMETERS, *PWRITEPRIVATEPROFILESTRINGW_PARAMETERS; + +typedef struct _WRITEPRIVATEPROFILESECTIONA_PARAMETERS { + LPCSTR lpAppName; + LPCSTR lpString; + LPCSTR lpFileName; +} WRITEPRIVATEPROFILESECTIONA_PARAMETERS, *PWRITEPRIVATEPROFILESECTIONA_PARAMETERS; + +typedef struct _WRITEPRIVATEPROFILESECTIONW_PARAMETERS { + LPCWSTR lpAppName; + LPCWSTR lpString; + LPCWSTR lpFileName; +} WRITEPRIVATEPROFILESECTIONW_PARAMETERS, *PWRITEPRIVATEPROFILESECTIONW_PARAMETERS; + +typedef struct _REGCONNECTREGISTRYW_PARAMETERS { + LPWSTR lpMachineName; + HKEY hKey; + PHKEY phkResult; +} REGCONNECTREGISTRYW_PARAMETERS, *PREGCONNECTREGISTRYW_PARAMETERS; + +typedef struct _API_SAVED_PARAMETERS { + API_SAVED_CALL_STATE SavedCallState; + union { + CREATEFILE_PARAMETERS CreateFile; + OPENFILE_PARAMETERS OpenFile; + DELETEFILE_PARAMETERS DeleteFile; + SETINFORMATIONFILE_PARAMETERS SetInformationFile; + QUERYATTRIBUTESFILE_PARAMETERS QueryAttributesFile; + QUERYDIRECTORYFILE_PARAMETERS QueryDirectoryFile; + CREATEKEY_PARAMETERS CreateKey; + OPENKEY_PARAMETERS OpenKey; + DELETEKEY_PARAMETERS DeleteKey; + SETVALUEKEY_PARAMETERS SetValueKey; + DELETEVALUEKEY_PARAMETERS DeleteValueKey; + CLOSEHANDLE_PARAMETERS CloseHandle; + GETVERSIONEXW_PARAMETERS GetVersionExW; + SETCURRENTDIRECTORYA_PARAMETERS SetCurrentDirectoryA; + SETCURRENTDIRECTORYW_PARAMETERS SetCurrentDirectoryW; + WRITEPRIVATEPROFILESTRINGA_PARAMETERS WritePrivateProfileStringA; + WRITEPRIVATEPROFILESTRINGW_PARAMETERS WritePrivateProfileStringW; + WRITEPRIVATEPROFILESECTIONA_PARAMETERS WritePrivateProfileSectionA; + WRITEPRIVATEPROFILESECTIONW_PARAMETERS WritePrivateProfileSectionW; + REGCONNECTREGISTRYW_PARAMETERS RegConnectRegistryW; + } InputParameters; + PVOID ReturnAddress; + union { + UCHAR ReturnedByte; + USHORT ReturnedShort; + ULONG ReturnedLong; + ULONGLONG ReturnedQuad; + BOOL ReturnedBool; + } ReturnValue; + BOOLEAN ReturnValueValid; + + // + // Union for handlers that need to store state between entry and + // exit, without the overhead of allocating an API_SAVED_CALL_STATE + // + union { + BOOLEAN AbortCall; + PWSTR CurrentDirectory; + }; +} API_SAVED_PARAMETERS, *PAPI_SAVED_PARAMETERS; + +BOOLEAN +NtCreateFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtOpenFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtDeleteFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtSetInformationFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtQueryAttributesFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtQueryDirectoryFileHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtCreateKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtOpenKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtDeleteKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtSetValueKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +NtDeleteValueKeyHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + + +BOOLEAN +NtCloseHandleHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +GetVersionHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +GetVersionExWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +SetCurrentDirectoryAHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +SetCurrentDirectoryWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +WritePrivateProfileStringAHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +WritePrivateProfileStringWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +WritePrivateProfileSectionAHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +WritePrivateProfileSectionWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +BOOLEAN +RegConnectRegistryWHandler( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +// +// Data structures and entry points in DEBUG.C +// + +CRITICAL_SECTION BreakTable; + +typedef struct _BREAKPOINT_INFO { + LIST_ENTRY Entry; + PVOID Address; + UCHAR ApiIndex; + PWSTR ModuleName; + LPSTR ProcedureName; + BOOLEAN SavedInstructionValid; + BOOLEAN SavedParametersValid; + union { + UCHAR Byte; + USHORT Short; + ULONG Long; + ULONGLONG LongLong; + } SavedInstruction; + API_SAVED_PARAMETERS SavedParameters; +} BREAKPOINT_INFO, *PBREAKPOINT_INFO; + +VOID +DebugEventLoop( VOID ); + + +BOOLEAN +InstallBreakpoint( + PPROCESS_INFO Process, + PBREAKPOINT_INFO Breakpoint + ); + +BOOLEAN +RemoveBreakpoint( + PPROCESS_INFO Process, + PBREAKPOINT_INFO Breakpoint + ); + +BOOLEAN +HandleBreakpoint( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PBREAKPOINT_INFO Breakpoint + ); + + +BOOLEAN +CreateBreakpoint( + PVOID Address, + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + UCHAR ApiIndex, + PVOID SavedParameters, + PBREAKPOINT_INFO *Breakpoint + ); + +BOOLEAN +DestroyBreakpoint( + PVOID Address, + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ); + +PBREAKPOINT_INFO +FindBreakpoint( + PVOID Address, + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ); + +// +// Data structures and entry points in HANDLEDB.C +// + +POPENHANDLE_INFO +FindOpenHandle( + PPROCESS_INFO Process, + HANDLE Handle, + ULONG Type + ); + +BOOLEAN +AddOpenHandle( + PPROCESS_INFO Process, + HANDLE Handle, + ULONG Type, + PWSTR Name, + BOOLEAN InheritHandle + ); + +BOOLEAN +DeleteOpenHandle( + PPROCESS_INFO Process, + HANDLE Handle, + ULONG Type + ); + +VOID +InheritHandles( + PPROCESS_INFO Process + ); + + + +// +// Data structures and entry points in FILE.C +// + + +typedef struct _FILE_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; + ULONG PrefixLength; + BOOLEAN WriteAccess; + BOOLEAN Deleted; + BOOLEAN Created; + BOOLEAN AttributesModified; + BOOLEAN DateModified; + BOOLEAN ContentsModified; + BOOLEAN DirectoryFile; + USHORT BackupFileUniqueId; + DWORD BackupFileAttributes; + FILETIME BackupLastWriteTime; + ULARGE_INTEGER BackupFileSize; +} FILE_REFERENCE, *PFILE_REFERENCE; + + +BOOLEAN +CreateFileReference( + PWSTR Name, + BOOLEAN WriteAccess, + PFILE_REFERENCE *ReturnedReference + ); + +BOOLEAN +CompleteFileReference( + PFILE_REFERENCE p, + BOOLEAN CallSuccessful, + BOOLEAN Delete, + PFILE_REFERENCE RenameReference + ); + +BOOLEAN +DestroyFileReference( + PFILE_REFERENCE p + ); + +BOOLEAN +IsNewFileSameAsBackup( + PFILE_REFERENCE p + ); + +PFILE_REFERENCE +FindFileReference( + PWSTR Name + ); + +VOID +DumpFileReferenceList( + FILE *LogFile + ); + +// +// Data structures and entry points in KEY.C +// + +typedef struct _KEY_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; + ULONG PrefixLength; + BOOLEAN WriteAccess; + BOOLEAN Deleted; + BOOLEAN Created; + PKEY_FULL_INFORMATION BackupKeyInfo; + LIST_ENTRY ValueReferencesListHead; +} KEY_REFERENCE, *PKEY_REFERENCE; + +typedef struct _VALUE_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; + BOOLEAN Modified; + BOOLEAN Deleted; + BOOLEAN Created; + PKEY_VALUE_PARTIAL_INFORMATION Value; + KEY_VALUE_PARTIAL_INFORMATION OriginalValue; +} VALUE_REFERENCE, *PVALUE_REFERENCE; + +BOOLEAN +CreateKeyReference( + PWSTR Name, + BOOLEAN WriteAccess, + PKEY_REFERENCE *ReturnedReference + ); + +BOOLEAN +CompleteKeyReference( + PKEY_REFERENCE p, + BOOLEAN CallSuccessful, + BOOLEAN Delete + ); + +BOOLEAN +DestroyKeyReference( + PKEY_REFERENCE p + ); + +PKEY_REFERENCE +FindKeyReference( + PWSTR Name + ); + +VOID +MarkKeyDeleted( + PKEY_REFERENCE KeyReference + ); + +BOOLEAN +CreateValueReference( + PPROCESS_INFO Process, + PKEY_REFERENCE KeyReference, + PWSTR Name, + ULONG TitleIndex, + ULONG Type, + PVOID Data, + ULONG DataLength, + PVALUE_REFERENCE *ReturnedValueReference + ); + +PVALUE_REFERENCE +FindValueReference( + PKEY_REFERENCE KeyReference, + PWSTR Name + ); + +BOOLEAN +DestroyValueReference( + PVALUE_REFERENCE p + ); + +VOID +DumpKeyReferenceList( + FILE *LogFile + ); + +// +// Data structures and entry points in INI.C +// + +typedef struct _INI_FILE_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; + ULONG PrefixLength; + BOOLEAN Created; + FILETIME BackupLastWriteTime; + LIST_ENTRY SectionReferencesListHead; +} INI_FILE_REFERENCE, *PINI_FILE_REFERENCE; + +typedef struct _INI_SECTION_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; + BOOLEAN Deleted; + BOOLEAN Created; + LIST_ENTRY VariableReferencesListHead; +} INI_SECTION_REFERENCE, *PINI_SECTION_REFERENCE; + +typedef struct _INI_VARIABLE_REFERENCE { + LIST_ENTRY Entry; + PWSTR Name; + BOOLEAN Modified; + BOOLEAN Deleted; + BOOLEAN Created; + PWSTR OriginalValue; + PWSTR Value; +} INI_VARIABLE_REFERENCE, *PINI_VARIABLE_REFERENCE; + + +BOOLEAN +CreateIniFileReference( + PWSTR Name, + PINI_FILE_REFERENCE *ReturnedReference + ); + +BOOLEAN +DestroyIniFileReference( + PINI_FILE_REFERENCE p + ); + +BOOLEAN +DestroyIniSectionReference( + PINI_SECTION_REFERENCE p1 + ); + +BOOLEAN +DestroyIniVariableReference( + PINI_VARIABLE_REFERENCE p2 + ); + +PINI_FILE_REFERENCE +FindIniFileReference( + PWSTR Name + ); + +PINI_SECTION_REFERENCE +FindIniSectionReference( + PINI_FILE_REFERENCE p, + PWSTR Name, + BOOLEAN CreateOkay + ); + +PINI_VARIABLE_REFERENCE +FindIniVariableReference( + PINI_SECTION_REFERENCE p1, + PWSTR Name, + BOOLEAN CreateOkay + ); + +VOID +DumpIniFileReferenceList( + FILE *LogFile + ); + +// +// Data structures and entry points in NAMEDB.C +// + +PWSTR +AddName( + PUNICODE_STRING Name + ); + +VOID +DumpNameDataBase( + FILE *LogFile + ); + +BOOLEAN +IncrementOpenCount( + PWSTR Name, + BOOLEAN CallSuccessful + ); + +ULONG +QueryOpenCount( + PWSTR Name, + BOOLEAN CallSuccessful + ); + + + +// +// Data structures and entry points in INIT.C +// + +HMODULE InstalerModuleHandle; +HANDLE AppHeap; +UNICODE_STRING WindowsDirectory; +ULONG StartProcessTickCount; +FILE *InstalerLogFile; +BOOLEAN AskUserOnce; +BOOLEAN DefaultGetVersionToWin95; +BOOLEAN FailAllScansOfRootDirectories; + + + +LIST_ENTRY FileReferenceListHead; +ULONG NumberOfFileReferences; +LIST_ENTRY KeyReferenceListHead; +ULONG NumberOfKeyReferences; +LIST_ENTRY IniReferenceListHead; +ULONG NumberOfIniReferences; + +#define NTDLL_MODULE_INDEX 0 +#define KERNEL32_MODULE_INDEX 1 +#define ADVAPI32_MODULE_INDEX 2 +#define MAXIMUM_MODULE_INDEX 3 + +typedef struct _MODULE_INFO { + PWSTR ModuleName; + HMODULE ModuleHandle; +} MODULE_INFO, *PMODULE_INFO; + +MODULE_INFO ModuleInfo[ MAXIMUM_MODULE_INDEX ]; + +typedef BOOLEAN (*PAPI_HANDLER)( + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + PAPI_SAVED_PARAMETERS Parameters + ); + +typedef struct _API_INFO { + ULONG ModuleIndex; + LPSTR EntryPointName; // Exported names are ANSI only + PVOID EntryPointAddress; + PAPI_HANDLER EntryPointHandler; + ULONG SizeOfParameters; + ULONG SizeOfReturnValue; +} API_INFO, *PAPI_INFO; + +#define NTCREATEFILE_INDEX 0 +#define NTOPENFILE_INDEX 1 +#define NTDELETEFILE_INDEX 2 +#define NTSETINFORMATIONFILE_INDEX 3 +#define NTQUERYATTRIBUTESFILE_INDEX 4 +#define NTQUERYDIRECTORYFILE_INDEX 5 +#define NTCREATEKEY_INDEX 6 +#define NTOPENKEY_INDEX 7 +#define NTDELETEKEY_INDEX 8 +#define NTSETVALUEKEY_INDEX 9 +#define NTDELETEVALUEKEY_INDEX 10 +#define NTCLOSEHANDLE_INDEX 11 +#define GETVERSION_INDEX 12 +#define GETVERSIONEXW_INDEX 13 +#define SETCURRENTDIRECTORYA_INDEX 14 +#define SETCURRENTDIRECTORYW_INDEX 15 +#define WRITEPRIVATEPROFILESTRINGA_INDEX 16 +#define WRITEPRIVATEPROFILESTRINGW_INDEX 17 +#define WRITEPRIVATEPROFILESECTIONA_INDEX 18 +#define WRITEPRIVATEPROFILESECTIONW_INDEX 19 +#define GETPRIVATEPROFILESTRINGA_INDEX 20 +#define GETPRIVATEPROFILESTRINGW_INDEX 21 +#define GETPRIVATEPROFILESECTIONA_INDEX 22 +#define GETPRIVATEPROFILESECTIONW_INDEX 23 +#define REGCONNECTREGISTRYW_INDEX 24 +#define MAXIMUM_API_INDEX 25 + +API_INFO ApiInfo[ MAXIMUM_API_INDEX ]; + +typedef struct _DRIVE_LETTER_INFO { + WCHAR DriveLetter; + BOOLEAN DriveLetterValid; + UNICODE_STRING NtLinkTarget; +} DRIVE_LETTER_INFO, *PDRIVE_LETTER_INFO; + +UNICODE_STRING UNCPrefix; +UNICODE_STRING DriveLetterPrefix; +UNICODE_STRING AltDriveLetterPrefix; +DRIVE_LETTER_INFO DriveLetters[ 32 ]; + +BOOLEAN +InitializeInstaler( + int argc, + char *argv[] + ); + +PVOID +LookupEntryPointInIAT( + HMODULE ModuleHandle, + PCHAR EntryPointName + ); + +BOOLEAN +IsDriveLetterPath( + PUNICODE_STRING Path + ); + + +PVOID TemporaryBuffer; +ULONG TemporaryBufferLength; +ULONG TemporaryBufferLengthGrowth; +ULONG TemporaryBufferMaximumLength; + +VOID +TrimTemporaryBuffer( VOID ); + +BOOLEAN +GrowTemporaryBuffer( + ULONG NeededSize + ); + +ULONG +FillTemporaryBuffer( + PPROCESS_INFO Process, + PVOID Address, + BOOLEAN Unicode, + BOOLEAN DoubleNullTermination + ); + +#include "instutil.h" +#include "iml.h" + +PINSTALLATION_MODIFICATION_LOGFILE pImlNew; + + +#endif // defined( RC_INVOKED ) diff --git a/private/sdktools/instaler/instaler.rc b/private/sdktools/instaler/instaler.rc new file mode 100644 index 000000000..c608ba1aa --- /dev/null +++ b/private/sdktools/instaler/instaler.rc @@ -0,0 +1,12 @@ +#include "instaler.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Instaler Program" +#define VER_INTERNALNAME_STR "INSTALER\0" +#define VER_ORIGINALFILENAME_STR "INSTALER.EXE" + +#include "common.ver" + +RCINCLUDE errormsg.rc diff --git a/private/sdktools/instaler/instutil.c b/private/sdktools/instaler/instutil.c new file mode 100644 index 000000000..fb9b0c683 --- /dev/null +++ b/private/sdktools/instaler/instutil.c @@ -0,0 +1,365 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + instutil.c + +Abstract: + + Common code for INSTALER.EXE, DISPINST.EXE, COMPINST.EXE and UNDOINST.EXE + +Author: + + Steve Wood (stevewo) 14-Jan-1996 + +Revision History: + +--*/ + +#include "instutil.h" +#include "iml.h" + +LPSTR SavedModuleName; +LPSTR SavedModuleUsage1; +LPSTR SavedModuleUsage2; + +WCHAR AltTempFilePathBuffer[ MAX_PATH ]; +PWSTR AltTempFilePathFileName; +WCHAR TempFilePathBuffer[ MAX_PATH ]; +PWSTR TempFilePathFileName; +USHORT TempFileNextUniqueId; + +BOOL WINAPI +CtrlCHandler( + ULONG CtrlType + ) +{ + // + // Ignore control C interrupts. Let child process deal with them + // if it wants. If it doesn't then it will terminate and we will + // get control and terminate ourselves + // + + return TRUE; +} + +void +InitCommonCode( + LPSTR ModuleName, + LPSTR ModuleUsage1, + LPSTR ModuleUsage2 + ) +{ + SavedModuleName = ModuleName; + SavedModuleUsage1 = ModuleUsage1; + SavedModuleUsage2 = ModuleUsage2; + + GetTempPath( sizeof( TempFilePathBuffer ) / sizeof( WCHAR ), + TempFilePathBuffer + ); + TempFilePathFileName = TempFilePathBuffer + wcslen( TempFilePathBuffer ); + TempFileNextUniqueId = (USHORT)0x0001; + + InstalerDirectory[ 0 ] = UNICODE_NULL; + return; +} + +void +DisplayIndentedString( + ULONG IndentAmount, + PCHAR sBegin + ) +{ + PCHAR sEnd; + + while (sBegin != NULL) { + sEnd = sBegin; + while (*sEnd && *sEnd != '\n') { + sEnd += 1; + } + + fprintf( stderr, "%.*s%.*s\n", + IndentAmount, + " ", + sEnd - sBegin, sBegin + ); + + if (*sEnd == '\0') { + break; + } + else { + sBegin = ++sEnd; + } + } + return; +} + + +void +Usage( + LPSTR Message, + ULONG MessageParameter + ) +{ + ULONG n; + LPSTR sBegin, sEnd; + + n = fprintf( stderr, "usage: %s ", SavedModuleName ); + fprintf( stderr, "InstallationName\n" ); + DisplayIndentedString( n, SavedModuleUsage1 ); + fprintf( stderr, "\n" ); + + n = fprintf( stderr, "where: " ); + fprintf( stderr, "InstallationName specifies a name for the installation. This is a required parameter.\n" ); + DisplayIndentedString( n, + "-? Displays this message." + ); + fprintf( stderr, "\n" ); + DisplayIndentedString( n, SavedModuleUsage2 ); + + if (Message != NULL) { + fprintf( stderr, "\n" ); + } + + // + // No return from FatalError + // + FatalError( Message, MessageParameter, 0 ); +} + +void +FatalError( + LPSTR Message, + ULONG MessageParameter1, + ULONG MessageParameter2 + ) +{ + if (Message != NULL) { + fprintf( stderr, "%s: ", SavedModuleName ); + fprintf( stderr, Message, MessageParameter1, MessageParameter2 ); + fprintf( stderr, "\n" ); + } + + exit( 1 ); +} + + +PWSTR +GetArgAsUnicode( + LPSTR s + ) +{ + ULONG n; + PWSTR ps; + + n = strlen( s ); + ps = HeapAlloc( GetProcessHeap(), + 0, + (n + 1) * sizeof( WCHAR ) + ); + if (ps == NULL) { + FatalError( "Out of memory", 0, 0 ); + } + + if (MultiByteToWideChar( CP_ACP, + MB_PRECOMPOSED, + s, + n, + ps, + n + ) != (LONG)n + ) { + FatalError( "Unable to convert parameter '%s' to Unicode (%u)", (ULONG)s, GetLastError() ); + } + + ps[ n ] = UNICODE_NULL; + return ps; +} + + +void +CommonSwitchProcessing( + PULONG argc, + PCHAR **argv, + CHAR c + ) +{ + DWORD dwFileAttributes; + PWSTR s; + + switch( c = tolower( c ) ) { + case 'd': + DebugOutput = TRUE; + break; + + case '?': + Usage( NULL, 0 ); + break; + + default: + Usage( "Invalid switch (-%c)", (ULONG)c ); + break; + } + + return; +} + + +BOOLEAN +CommonArgProcessing( + PULONG argc, + PCHAR **argv + ) +{ + PWSTR s; + + if (InstallationName == NULL) { + GetCurrentDirectory( MAX_PATH, InstalerDirectory ); + s = wcschr( InstalerDirectory, UNICODE_NULL ); + if (s[-1] != L'\\') { + *s++ = L'\\'; + *s = UNICODE_NULL; + } + + InstallationName = GetArgAsUnicode( **argv ); + ImlPath = FormatImlPath( InstalerDirectory, InstallationName ); + return TRUE; + } + else { + return FALSE; + } +} + +PWSTR +FormatTempFileName( + PWSTR Directory, + PUSHORT TempFileUniqueId + ) +{ + if (*TempFileUniqueId == 0) { + *TempFileUniqueId = (USHORT)(TempFileNextUniqueId++); + if (TempFileNextUniqueId == 0) { + return NULL; + } + } + else + if (*TempFileUniqueId == 0xFFFF) { + return NULL; + } + + if (Directory != NULL) { + GetFullPathName( Directory, MAX_PATH, AltTempFilePathBuffer, &AltTempFilePathFileName ); + AltTempFilePathFileName = wcsrchr( AltTempFilePathBuffer, TEXT('\\') ); + AltTempFilePathFileName += 1; + swprintf( AltTempFilePathFileName, L"~INS%04x.TMP", *TempFileUniqueId ); + return AltTempFilePathBuffer; + } + else { + swprintf( TempFilePathFileName, L"~INS%04x.TMP", *TempFileUniqueId ); + return TempFilePathBuffer; + } +} + +PWSTR +CreateBackupFileName( + PUSHORT TempFileUniqueId + ) +{ + PWSTR BackupFileName; + + while (BackupFileName = FormatTempFileName( NULL, TempFileUniqueId )) { + if (GetFileAttributesW( BackupFileName ) == 0xFFFFFFFF) { + break; + } + else { + *TempFileUniqueId = 0; // Temp file name existed, try next unique id + } + } + + return BackupFileName; +} + + +UCHAR EnumTypeBuffer0[ 512 ]; +UCHAR EnumTypeBuffer1[ 512 ]; +UCHAR EnumTypeBuffer2[ 512 ]; +UCHAR EnumTypeBuffer3[ 512 ]; +LPSTR EnumTypeBuffers[ 4 ] = { + EnumTypeBuffer0, + EnumTypeBuffer1, + EnumTypeBuffer2, + EnumTypeBuffer3 +}; + +LPSTR +FormatEnumType( + ULONG BufferIndex, + PENUM_TYPE_NAMES Table, + ULONG Value, + BOOLEAN FlagFormat + ) +{ + LPSTR s, FlagsBuffer = EnumTypeBuffers[ BufferIndex ]; + + FlagsBuffer[ 0 ] = '\0'; + while (Table->Value != 0xFFFFFFFF) { + if (FlagFormat) { + if (Table->Value & Value) { + if (FlagsBuffer[ 0 ] != '\0') { + strcat( FlagsBuffer, " | " ); + } + + strcat( FlagsBuffer, Table->Name ); + Value &= ~Table->Value; + if (Value == 0) { + return FlagsBuffer; + } + } + } + else + if (Table->Value == Value) { + if (Value == 0) { + if (!strcmp( Table->Name, "STATUS_WAIT_0" )) { + return "STATUS_SUCCESS"; + } + else + if (!strcmp( Table->Name, "ERROR_SUCCESS" )) { + return "NO_ERROR"; + } + } + return Table->Name; + } + + Table += 1; + } + + s = FlagsBuffer; + if (FlagFormat) { + if (s[ 0 ] != '\0') { + strcat( s, " | " ); + s += strlen( s ); + } + } + + sprintf( s, Table->Name ? Table->Name : "%x", Value ); + return FlagsBuffer; +} + + + +ENUM_TYPE_NAMES ValueDataTypeNames[] = { + REG_NONE, "REG_NONE", + REG_SZ, "REG_SZ", + REG_EXPAND_SZ, "REG_EXPAND_SZ", + REG_BINARY, "REG_BINARY", + REG_DWORD, "REG_DWORD", + REG_DWORD_BIG_ENDIAN, "REG_DWORD_BIG_ENDIAN", + REG_LINK, "REG_LINK", + REG_MULTI_SZ, "REG_MULTI_SZ", + REG_RESOURCE_LIST, "REG_RESOURCE_LIST", + REG_FULL_RESOURCE_DESCRIPTOR, "REG_FULL_RESOURCE_DESCRIPTOR", + REG_RESOURCE_REQUIREMENTS_LIST,"REG_RESOURCE_REQUIREMENTS_LIST", + 0xFFFFFFFF, "%x" +}; diff --git a/private/sdktools/instaler/instutil.h b/private/sdktools/instaler/instutil.h new file mode 100644 index 000000000..1b98ddc51 --- /dev/null +++ b/private/sdktools/instaler/instutil.h @@ -0,0 +1,114 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + instutil.h + +Abstract: + + Header file for common definition for programs that manipulate the output of + the INSTALER.EXE program (e.g. DISPINST.EXE, COMPINST.EXE, UNDOINST.EXE) + +Author: + + Steve Wood (stevewo) 14-Jan-1996 + +Revision History: + +--*/ + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <tchar.h> + +WCHAR InstalerDirectory[ MAX_PATH ]; +PWSTR InstallationName; +PWSTR ImlPath; +BOOLEAN DebugOutput; + +// +// Useful rounding macros that the rounding amount is always a +// power of two. +// + +#define ROUND_DOWN( Size, Amount ) ((DWORD)(Size) & ~((Amount) - 1)) +#define ROUND_UP( Size, Amount ) (((DWORD)(Size) + ((Amount) - 1)) & ~((Amount) - 1)) + +void +InitCommonCode( + LPSTR ModuleName, + LPSTR ModuleUsage1, + LPSTR ModuleUsage2 + ); + +void +Usage( + LPSTR Message, + ULONG MessageParameter + ); + +void +FatalError( + LPSTR Message, + ULONG MessageParameter1, + ULONG MessageParameter2 + ); + +void +InputMessage( + PWSTR FileName, + ULONG LineNumber, + BOOLEAN Error, + LPSTR Message, + ULONG MessageParameter1, + ULONG MessageParameter2 + ); + +PWSTR +GetArgAsUnicode( + LPSTR s + ); + +void +CommonSwitchProcessing( + PULONG argc, + PCHAR **argv, + CHAR c + ); + +BOOLEAN +CommonArgProcessing( + PULONG argc, + PCHAR **argv + ); + +PWSTR +FormatTempFileName( + PWSTR Directory, + PUSHORT TempFileUniqueId + ); + + +PWSTR +CreateBackupFileName( + PUSHORT TempFileUniqueId + ); + + +typedef struct _ENUM_TYPE_NAMES { + ULONG Value; + LPSTR Name; +} ENUM_TYPE_NAMES, *PENUM_TYPE_NAMES; + +LPSTR +FormatEnumType( + ULONG BufferIndex, + PENUM_TYPE_NAMES Table, + ULONG Value, + BOOLEAN FlagFormat + ); + +ENUM_TYPE_NAMES ValueDataTypeNames[]; diff --git a/private/sdktools/instaler/key.c b/private/sdktools/instaler/key.c new file mode 100644 index 000000000..2b7096e4d --- /dev/null +++ b/private/sdktools/instaler/key.c @@ -0,0 +1,524 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + key.c + +Abstract: + + This module implements the functions to save references to registry + keys and values for the INSTALER program. Part of each reference is + a a backup copy of a key information and its values that have been + changed/deleted. + +Author: + + Steve Wood (stevewo) 22-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +#define DEFAULT_KEY_VALUE_BUFFER_SIZE 512 +PKEY_VALUE_FULL_INFORMATION KeyValueInformation; + +VOID +BackupKeyInfo( + PKEY_REFERENCE p + ) +{ + NTSTATUS Status; + UNICODE_STRING KeyName; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE KeyHandle; + KEY_FULL_INFORMATION KeyInformation; + ULONG ResultLength; + ULONG ValueIndex; + UNICODE_STRING ValueName; + PVALUE_REFERENCE ValueReference; + + RtlInitUnicodeString( &KeyName, p->Name ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + Status = NtOpenKey( &KeyHandle, + KEY_READ, + &ObjectAttributes + ); + if (!NT_SUCCESS( Status )) { + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { + p->Created = TRUE; + p->WriteAccess = TRUE; + } + + fprintf( InstalerLogFile, "*** Unable to open key %ws (%x)\n", p->Name, Status ); + return; + } + + if (!p->WriteAccess) { + NtClose( KeyHandle ); + return; + } + + fprintf( InstalerLogFile, "Saving values for %ws\n", p->Name ); + if (KeyValueInformation == NULL) { + KeyValueInformation = AllocMem( DEFAULT_KEY_VALUE_BUFFER_SIZE ); + if (KeyValueInformation == NULL) { + fprintf( InstalerLogFile, "*** No memory for key value information\n" ); + return; + } + } + + Status = NtQueryKey( KeyHandle, + KeyFullInformation, + &KeyInformation, + sizeof( KeyInformation ), + &ResultLength + ); + if (!NT_SUCCESS( Status ) && Status != STATUS_BUFFER_OVERFLOW) { + NtClose( KeyHandle ); + fprintf( InstalerLogFile, "*** Unable to query key (%x)\n", Status ); + return; + } + + p->BackupKeyInfo = AllocMem( ResultLength ); + if (p->BackupKeyInfo == NULL) { + NtClose( KeyHandle ); + fprintf( InstalerLogFile, "*** No memory for backup information\n" ); + return; + } + + if (!NT_SUCCESS( Status )) { + Status = NtQueryKey( KeyHandle, + KeyFullInformation, + p->BackupKeyInfo, + ResultLength, + &ResultLength + ); + if (!NT_SUCCESS( Status )) { + NtClose( KeyHandle ); + fprintf( InstalerLogFile, "*** Unable to query key (%x)\n", Status ); + return; + } + } + else { + memmove( p->BackupKeyInfo, &KeyInformation, ResultLength ); + } + + + for (ValueIndex = 0; TRUE; ValueIndex++) { + Status = NtEnumerateValueKey( KeyHandle, + ValueIndex, + KeyValueFullInformation, + KeyValueInformation, + DEFAULT_KEY_VALUE_BUFFER_SIZE, + &ResultLength + ); + if (!NT_SUCCESS( Status ) && Status != STATUS_BUFFER_OVERFLOW) { + break; + } + + ValueReference = AllocMem( FIELD_OFFSET( VALUE_REFERENCE, OriginalValue ) + + FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) + + KeyValueInformation->DataLength + ); + if (ValueReference == NULL) { + fprintf( InstalerLogFile, "*** No memory for value ref\n", Status ); + break; + } + + if (KeyValueInformation->NameLength != 0) { + ValueName.Length = (USHORT)KeyValueInformation->NameLength; + ValueName.MaximumLength = ValueName.Length; + ValueName.Buffer = KeyValueInformation->Name; + ValueReference->Name = AddName( &ValueName ); + fprintf( InstalerLogFile, " Saving data for '%ws'\n", ValueReference->Name ); + } + else { + fprintf( InstalerLogFile, " Saving data for empty value name\n" ); + } + + if (Status == STATUS_BUFFER_OVERFLOW) { + Status = NtEnumerateValueKey( KeyHandle, + ValueIndex, + KeyValuePartialInformation, + &ValueReference->OriginalValue, + FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) + + KeyValueInformation->DataLength, + &ResultLength + ); + if (!NT_SUCCESS( Status )) { + FreeMem( &ValueReference ); + break; + } + } + else { + ValueReference->OriginalValue.TitleIndex = KeyValueInformation->TitleIndex; + ValueReference->OriginalValue.Type = KeyValueInformation->Type; + ValueReference->OriginalValue.DataLength = KeyValueInformation->DataLength; + memmove( &ValueReference->OriginalValue.Data, + (PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset, + KeyValueInformation->DataLength + ); + } + + InsertTailList( &p->ValueReferencesListHead, &ValueReference->Entry ); + } + + NtClose( KeyHandle ); + return; +} + + + +BOOLEAN +CreateKeyReference( + PWSTR Name, + BOOLEAN WriteAccess, + PKEY_REFERENCE *ReturnedReference + ) +{ + PKEY_REFERENCE p; + + *ReturnedReference = NULL; + p = FindKeyReference( Name ); + if (p != NULL) { + if (p->WriteAccess) { + *ReturnedReference = p; + return TRUE; + } + } + else { + p = AllocMem( sizeof( *p ) ); + if (p == NULL) { + return FALSE; + } + + p->Name = Name; + InsertTailList( &KeyReferenceListHead, &p->Entry ); + NumberOfKeyReferences += 1; + } + + InitializeListHead( &p->ValueReferencesListHead ); + p->WriteAccess = WriteAccess; + BackupKeyInfo( p ); + + *ReturnedReference = p; + return TRUE; +} + + +BOOLEAN +CompleteKeyReference( + PKEY_REFERENCE p, + BOOLEAN CallSuccessful, + BOOLEAN Deleted + ) +{ + if (!CallSuccessful) { + DestroyKeyReference( p ); + return FALSE; + } + + if (Deleted && p->Created) { + LogEvent( INSTALER_EVENT_DELETE_TEMP_KEY, + 1, + p->Name + ); + DestroyKeyReference( p ); + return FALSE; + } + + if (Deleted) { + LogEvent( INSTALER_EVENT_DELETE_KEY, + 1, + p->Name + ); + } + else + if (p->WriteAccess) { + LogEvent( INSTALER_EVENT_WRITE_KEY, + 1, + p->Name + ); + } + else { + LogEvent( INSTALER_EVENT_READ_KEY, + 1, + p->Name + ); + } + + p->Deleted = Deleted; + return TRUE; +} + + +BOOLEAN +DestroyKeyReference( + PKEY_REFERENCE p + ) +{ + RemoveEntryList( &p->Entry ); + NumberOfKeyReferences -= 1; + FreeMem( &p ); + return TRUE; +} + +PKEY_REFERENCE +FindKeyReference( + PWSTR Name + ) +{ + PKEY_REFERENCE p; + PLIST_ENTRY Head, Next; + + Head = &KeyReferenceListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, KEY_REFERENCE, Entry ); + if (p->Name == Name) { + return p; + } + + Next = Next->Flink; + } + + return NULL; +} + +VOID +MarkKeyDeleted( + PKEY_REFERENCE KeyReference + ) +{ + PVALUE_REFERENCE p; + PLIST_ENTRY Head, Next; + + KeyReference->Deleted = TRUE; + Head = &KeyReference->ValueReferencesListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, VALUE_REFERENCE, Entry ); + Next = Next->Flink; + if (p->Created || KeyReference->Created) { + DestroyValueReference( p ); + } + else { + p->Deleted = TRUE; + } + } + + if (KeyReference->Created) { + DestroyKeyReference( KeyReference ); + } + + return; +} + +BOOLEAN +CreateValueReference( + PPROCESS_INFO Process, + PKEY_REFERENCE KeyReference, + PWSTR Name, + ULONG TitleIndex, + ULONG Type, + PVOID Data, + ULONG DataLength, + PVALUE_REFERENCE *ReturnedValueReference + ) +{ + PVALUE_REFERENCE p; + PKEY_VALUE_PARTIAL_INFORMATION OldValue, NewValue; + + *ReturnedValueReference = NULL; + + NewValue = AllocMem( FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) + + DataLength + ); + if (NewValue == NULL) { + return FALSE; + } + + NewValue->TitleIndex = TitleIndex; + NewValue->Type = Type; + NewValue->DataLength = DataLength; + if (!ReadMemory( Process, + Data, + &NewValue->Data[0], + DataLength, + "new value data" + ) + ) { + FreeMem( &NewValue ); + return FALSE; + } + + p = FindValueReference( KeyReference, Name ); + if (p != NULL) { + FreeMem( &p->Value ); + p->Value = NewValue; + OldValue = &p->OriginalValue; + if (OldValue->TitleIndex == NewValue->TitleIndex && + OldValue->Type == NewValue->Type && + OldValue->DataLength == NewValue->DataLength && + RtlCompareMemory( &OldValue->Data, &NewValue->Data, OldValue->DataLength ) + ) { + FreeMem( &p->Value ); + } + else { + p->Modified = TRUE; + } + + return TRUE; + } + + p = AllocMem( FIELD_OFFSET( VALUE_REFERENCE, OriginalValue ) ); + if (p == NULL) { + FreeMem( &NewValue ); + return FALSE; + } + + p->Name = Name; + p->Created = TRUE; + p->Value = NewValue; + InsertTailList( &KeyReference->ValueReferencesListHead, &p->Entry ); + + *ReturnedValueReference = p; + return TRUE; +} + + +PVALUE_REFERENCE +FindValueReference( + PKEY_REFERENCE KeyReference, + PWSTR Name + ) +{ + PVALUE_REFERENCE p; + PLIST_ENTRY Head, Next; + + Head = &KeyReference->ValueReferencesListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, VALUE_REFERENCE, Entry ); + if (p->Name == Name) { + return p; + } + + Next = Next->Flink; + } + + return NULL; +} + + +BOOLEAN +DestroyValueReference( + PVALUE_REFERENCE p + ) +{ + RemoveEntryList( &p->Entry ); + FreeMem( &p ); + return TRUE; +} + + +VOID +DumpKeyReferenceList( + FILE *LogFile + ) +{ + PKEY_REFERENCE p; + PLIST_ENTRY Head, Next; + PVALUE_REFERENCE p1; + PLIST_ENTRY Head1, Next1; + PKEY_VALUE_PARTIAL_INFORMATION OldValue, NewValue; + KEY_VALUE_PARTIAL_INFORMATION NullValue; + POFFSET Values; + + memset( &NullValue, 0, sizeof( NullValue ) ); + NullValue.Type = REG_SZ; + + Head = &KeyReferenceListHead; + Next = Head->Flink; + while (Head != Next) { + p = CONTAINING_RECORD( Next, KEY_REFERENCE, Entry ); + if (p->Created || p->WriteAccess) { + Values = 0; + Head1 = &p->ValueReferencesListHead; + Next1 = Head1->Flink; + while (Head1 != Next1) { + p1 = CONTAINING_RECORD( Next1, VALUE_REFERENCE, Entry ); + NewValue = p1->Value; + if (NewValue == NULL) { + NewValue = &NullValue; + } + + OldValue = &p1->OriginalValue; + if (!p1->Deleted) { + if (p1->Created) { + ImlAddValueRecord( pImlNew, + CreateNewValue, + p1->Name, + NewValue->Type, + NewValue->DataLength, + NewValue->Data, + 0, + 0, + NULL, + &Values + ); + } + else + if (p1->Modified) { + ImlAddValueRecord( pImlNew, + ModifyOldValue, + p1->Name, + NewValue->Type, + NewValue->DataLength, + NewValue->Data, + OldValue->Type, + OldValue->DataLength, + OldValue->Data, + &Values + ); + } + } + else { + ImlAddValueRecord( pImlNew, + DeleteOldValue, + p1->Name, + 0, + 0, + NULL, + OldValue->Type, + OldValue->DataLength, + OldValue->Data, + &Values + ); + } + + Next1 = Next1->Flink; + } + + ImlAddKeyRecord( pImlNew, + p->Created ? CreateNewKey : + p->Deleted ? DeleteOldKey : ModifyKeyValues, + p->Name, + Values + ); + } + + Next = Next->Flink; + } + + return; +} diff --git a/private/sdktools/instaler/makefile b/private/sdktools/instaler/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/sdktools/instaler/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/sdktools/instaler/makefile.inc b/private/sdktools/instaler/makefile.inc new file mode 100644 index 000000000..5c217612d --- /dev/null +++ b/private/sdktools/instaler/makefile.inc @@ -0,0 +1,10 @@ +instaler.rc: errormsg.rc + +showinst.rc: errormsg.rc + +undoinst.rc: errormsg.rc + +compinst.rc: errormsg.rc + +errormsg.h errormsg.rc msg00001.bin: errormsg.mc + mc -v errormsg.mc diff --git a/private/sdktools/instaler/namedb.c b/private/sdktools/instaler/namedb.c new file mode 100644 index 000000000..3d9c2274d --- /dev/null +++ b/private/sdktools/instaler/namedb.c @@ -0,0 +1,173 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + namedb.c + +Abstract: + + This module maintains a database of path names detected by the INSTALER program + +Author: + + Steve Wood (stevewo) 20-Aug-1994 + +Revision History: + +--*/ + + +#include "instaler.h" + +typedef struct _NAME_TABLE_ENTRY { + struct _NAME_TABLE_ENTRY *HashLink; + UNICODE_STRING Name; + ULONG OpenCount; + ULONG FailedOpenCount; +} NAME_TABLE_ENTRY, *PNAME_TABLE_ENTRY; + +#define NUMBER_OF_HASH_BUCKETS 37 +PNAME_TABLE_ENTRY NameTableBuckets[ NUMBER_OF_HASH_BUCKETS ]; + +BOOLEAN +IncrementOpenCount( + PWSTR Name, + BOOLEAN CallSuccessful + ) +{ + PNAME_TABLE_ENTRY p; + + p = (PNAME_TABLE_ENTRY)Name - 1; + if (p->Name.Buffer == Name) { + if (CallSuccessful) { + p->OpenCount += 1; + } + else { + p->FailedOpenCount += 1; + } + return TRUE; + } + else { + return FALSE; + } +} + +ULONG +QueryOpenCount( + PWSTR Name, + BOOLEAN CallSuccessful + ) +{ + PNAME_TABLE_ENTRY p; + + p = (PNAME_TABLE_ENTRY)Name - 1; + if (p->Name.Buffer == Name) { + if (CallSuccessful) { + return p->OpenCount; + } + else { + return p->FailedOpenCount; + } + + } + else { + return 0; + } +} + +PWSTR +AddName( + PUNICODE_STRING Name + ) +{ + ULONG n, Hash; + WCHAR c; + PWCH s; + PNAME_TABLE_ENTRY *pp, p; + + n = Name->Length / sizeof( c ); + s = Name->Buffer; + Hash = 0; + while (n--) { + c = RtlUpcaseUnicodeChar( *s++ ); + Hash = Hash + (c << 1) + (c >> 1) + c; + } + + pp = &NameTableBuckets[ Hash % NUMBER_OF_HASH_BUCKETS ]; + while (p = *pp) { + if (RtlEqualUnicodeString( &p->Name, Name, TRUE )) { + return p->Name.Buffer; + } + else { + pp = &p->HashLink; + } + } + + p = AllocMem( sizeof( *p ) + Name->Length + sizeof( UNICODE_NULL ) ); + *pp = p; + p->HashLink = NULL; + p->Name.Buffer = (PWSTR)(p + 1); + p->Name.Length = Name->Length; + p->Name.MaximumLength = (USHORT)(Name->Length + sizeof( UNICODE_NULL )); + RtlMoveMemory( p->Name.Buffer, Name->Buffer, Name->Length ); + p->Name.Buffer[ Name->Length / sizeof( WCHAR ) ] = UNICODE_NULL; + return p->Name.Buffer; +} + + +VOID +DumpNameDataBase( + FILE *LogFile + ) +{ + ULONG i; + PNAME_TABLE_ENTRY p; + +#if 0 + fprintf( LogFile, "Name Data Base entries:\n" ); + for (i=0; i<NUMBER_OF_HASH_BUCKETS; i++) { + p = NameTableBuckets[ i ]; + if (p != NULL) { + fprintf( LogFile, "Bucket[ %02u ]:\n", i ); + while (p) { + fprintf( LogFile, " %ws\n", p->Name.Buffer ); + p = p->HashLink; + } + } + } + fprintf( LogFile, "\n" ); +#endif + + fprintf( LogFile, "List of paths with non-zero successful open counts\n" ); + for (i=0; i<NUMBER_OF_HASH_BUCKETS; i++) { + p = NameTableBuckets[ i ]; + if (p != NULL) { + while (p) { + if (p->OpenCount != 0) { + fprintf( LogFile, " %4u %ws\n", p->OpenCount, p->Name.Buffer ); + } + + p = p->HashLink; + } + } + } + fprintf( LogFile, "\n" ); + fprintf( LogFile, "List of paths with non-zero failed open counts\n" ); + for (i=0; i<NUMBER_OF_HASH_BUCKETS; i++) { + p = NameTableBuckets[ i ]; + if (p != NULL) { + while (p) { + if (p->FailedOpenCount != 0) { + fprintf( LogFile, " %4u %ws\n", p->FailedOpenCount, p->Name.Buffer ); + } + + p = p->HashLink; + } + } + } + fprintf( LogFile, "\n" ); + + return; +} diff --git a/private/sdktools/instaler/process.c b/private/sdktools/instaler/process.c new file mode 100644 index 000000000..c3a57627f --- /dev/null +++ b/private/sdktools/instaler/process.c @@ -0,0 +1,560 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + process.c + +Abstract: + + This module maintains state about each process/thread created by the application + setup/install program. + +Author: + + Steve Wood (stevewo) 09-Aug-1994 + +Revision History: + +--*/ + +#include "instaler.h" + +BOOLEAN +AddProcess( + LPDEBUG_EVENT DebugEvent, + PPROCESS_INFO *ReturnedProcess + ) +{ + NTSTATUS Status; + PPROCESS_INFO Process; + RTL_USER_PROCESS_PARAMETERS ProcessParameters; + PEB Peb; + PWSTR FreeBuffer, s; + + Process = AllocMem( sizeof( *Process ) ); + if (Process == NULL) { + return FALSE; + } + + Process->Id = DebugEvent->dwProcessId; + Process->Handle = DebugEvent->u.CreateProcessInfo.hProcess; + InitializeListHead( &Process->ThreadListHead ); + InitializeListHead( &Process->BreakpointListHead ); + InitializeListHead( &Process->OpenHandleListHead ); + InsertTailList( &ProcessListHead, &Process->Entry ); + *ReturnedProcess = Process; + + Status = NtQueryInformationProcess( Process->Handle, + ProcessBasicInformation, + &Process->ProcessInformation, + sizeof( Process->ProcessInformation ), + NULL + ); + FreeBuffer = NULL; + if (ReadMemory( Process, + Process->ProcessInformation.PebBaseAddress, + &Peb, + sizeof( Peb ), + "PEB" + ) && + Peb.ProcessParameters != NULL && + ReadMemory( Process, + Peb.ProcessParameters, + &ProcessParameters, + sizeof( ProcessParameters ), + "ProcessParameters" + ) && + ProcessParameters.ImagePathName.Length != 0 && + (FreeBuffer = AllocMem( ProcessParameters.ImagePathName.Length + sizeof( UNICODE_NULL ) )) != NULL && + ReadMemory( Process, + ProcessParameters.Flags & RTL_USER_PROC_PARAMS_NORMALIZED ? + ProcessParameters.ImagePathName.Buffer : + (PWSTR)((ULONG)(ProcessParameters.ImagePathName.Buffer) + (PCHAR)(Peb.ProcessParameters)), + FreeBuffer, + ProcessParameters.ImagePathName.Length, + "Image File Name" + ) + ) { + s = (PWSTR)((PCHAR)FreeBuffer + ProcessParameters.ImagePathName.Length); + while (s > FreeBuffer && s[ -1 ] != OBJ_NAME_PATH_SEPARATOR) { + s--; + } + + wcsncpy( Process->ImageFileName, + s, + (sizeof( Process->ImageFileName ) - sizeof( UNICODE_NULL )) / sizeof( WCHAR ) + ); + } + FreeMem( &FreeBuffer ); + return TRUE; +} + +BOOLEAN +DeleteProcess( + PPROCESS_INFO Process + ) +{ + PLIST_ENTRY Next, Head; + PTHREAD_INFO Thread; + PBREAKPOINT_INFO Breakpoint; + POPENHANDLE_INFO p; + + RemoveEntryList( &Process->Entry ); + + Head = &Process->ThreadListHead; + Next = Head->Flink; + while (Next != Head) { + Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry ); + Next = Next->Flink; + DeleteThread( Process, Thread ); + } + + Head = &Process->BreakpointListHead; + Next = Head->Flink; + while (Next != Head) { + Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry ); + Next = Next->Flink; + DestroyBreakpoint( Breakpoint->Address, Process, NULL ); + } + + + Head = &Process->OpenHandleListHead; + Next = Head->Flink; + while (Next != Head) { + p = CONTAINING_RECORD( Next, OPENHANDLE_INFO, Entry ); + Next = Next->Flink; + DeleteOpenHandle( Process, p->Handle, p->Type ); + } + + FreeMem( &Process ); + return TRUE; +} + + +BOOLEAN +AddThread( + LPDEBUG_EVENT DebugEvent, + PPROCESS_INFO Process, + PTHREAD_INFO *ReturnedThread + ) +{ + PTHREAD_INFO Thread; + + Thread = AllocMem( sizeof( *Thread ) ); + if (Thread == NULL) { + return FALSE; + } + + Thread->Id = DebugEvent->dwThreadId; + if (DebugEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { + Thread->Handle = DebugEvent->u.CreateProcessInfo.hThread; + Thread->StartAddress = DebugEvent->u.CreateProcessInfo.lpStartAddress; + } + else { + Thread->Handle = DebugEvent->u.CreateThread.hThread; + Thread->StartAddress = DebugEvent->u.CreateThread.lpStartAddress; + } + Thread->SingleStepExpected = FALSE; + InitializeListHead( &Thread->BreakpointListHead ); + InsertTailList( &Process->ThreadListHead, &Thread->Entry ); + *ReturnedThread = Thread; + return TRUE; +} + +BOOLEAN +DeleteThread( + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ) +{ + PLIST_ENTRY Next, Head; + PBREAKPOINT_INFO Breakpoint; + + RemoveEntryList( &Thread->Entry ); + + Head = &Thread->BreakpointListHead; + Next = Head->Flink; + while (Next != Head) { + Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry ); + Next = Next->Flink; + DestroyBreakpoint( Breakpoint->Address, Process, Thread ); + } + + FreeMem( &Thread ); + return TRUE; +} + + +PPROCESS_INFO +FindProcessById( + ULONG Id + ) +{ + PLIST_ENTRY Next, Head; + PPROCESS_INFO Process; + + Head = &ProcessListHead; + Next = Head->Flink; + while (Next != Head) { + Process = CONTAINING_RECORD( Next, PROCESS_INFO, Entry ); + if (Process->Id == Id) { + return Process; + } + + Next = Next->Flink; + } + + return NULL; +} + +BOOLEAN +FindProcessAndThreadForEvent( + LPDEBUG_EVENT DebugEvent, + PPROCESS_INFO *ReturnedProcess, + PTHREAD_INFO *ReturnedThread + ) +{ + PLIST_ENTRY Next, Head; + PPROCESS_INFO Process; + PTHREAD_INFO Thread; + + Head = &ProcessListHead; + Next = Head->Flink; + Process = NULL; + Thread = NULL; + while (Next != Head) { + Process = CONTAINING_RECORD( Next, PROCESS_INFO, Entry ); + if (Process->Id == DebugEvent->dwProcessId) { + Head = &Process->ThreadListHead; + Next = Head->Flink; + while (Next != Head) { + Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry ); + if (Thread->Id == DebugEvent->dwThreadId) { + break; + } + + Thread = NULL; + Next = Next->Flink; + } + + break; + } + + Process = NULL; + Next = Next->Flink; + } + + *ReturnedProcess = Process; + *ReturnedThread = Thread; + + if (DebugEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { + if (Process != NULL) { + DeclareError( INSTALER_DUPLICATE_PROCESS_ID, 0, DebugEvent->dwProcessId ); + return FALSE; + } + } + else + if (DebugEvent->dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) { + if (Thread != NULL) { + DeclareError( INSTALER_DUPLICATE_THREAD_ID, 0, DebugEvent->dwThreadId, DebugEvent->dwProcessId ); + return FALSE; + } + if (Process == NULL) { + DeclareError( INSTALER_MISSING_PROCESS_ID, 0, DebugEvent->dwProcessId ); + return FALSE; + } + } + else + if (Process == NULL) { + DeclareError( INSTALER_MISSING_PROCESS_ID, 0, DebugEvent->dwProcessId ); + return FALSE; + } + else + if (Thread == NULL) { + DeclareError( INSTALER_MISSING_THREAD_ID, 0, DebugEvent->dwThreadId, DebugEvent->dwProcessId ); + return FALSE; + } + + return TRUE; +} + + +PBREAKPOINT_INFO +FindBreakpoint( + LPVOID Address, + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ) +{ + PBREAKPOINT_INFO Breakpoint; + PLIST_ENTRY Next, Head; + + if (Thread != NULL) { + Head = &Thread->BreakpointListHead; + Next = Head->Flink; + while (Next != Head) { + Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry ); + if (Breakpoint->Address == Address) { + return Breakpoint; + } + + Next = Next->Flink; + } + } + + Head = &Process->BreakpointListHead; + Next = Head->Flink; + while (Next != Head) { + Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry ); + if (Breakpoint->Address == Address) { + return Breakpoint; + } + + Next = Next->Flink; + } + + return NULL; +} + +BOOLEAN +CreateBreakpoint( + LPVOID Address, + PPROCESS_INFO Process, + PTHREAD_INFO Thread, + UCHAR ApiIndex, + PAPI_SAVED_PARAMETERS SavedParameters, + PBREAKPOINT_INFO *ReturnedBreakpoint + ) +{ + PBREAKPOINT_INFO Breakpoint; + + Breakpoint = FindBreakpoint( Address, Process, Thread ); + + if (ARGUMENT_PRESENT( ReturnedBreakpoint )) { + *ReturnedBreakpoint = Breakpoint; + } + + if (Breakpoint != NULL) { + return (Breakpoint->ApiIndex == ApiIndex); + } + + Breakpoint = AllocMem( sizeof( *Breakpoint ) ); + if (Breakpoint == NULL) { + return FALSE; + } + + Breakpoint->Address = Address; + Breakpoint->ApiIndex = ApiIndex; + if (ARGUMENT_PRESENT( SavedParameters )) { + Breakpoint->SavedParameters = *SavedParameters; + Breakpoint->SavedParametersValid = TRUE; + } + else { + Breakpoint->SavedParametersValid = FALSE; + } + + if (Thread != NULL) { + InsertTailList( &Thread->BreakpointListHead, &Breakpoint->Entry ); + } + else { + InsertTailList( &Process->BreakpointListHead, &Breakpoint->Entry ); + } + + InstallBreakpoint( Process, Breakpoint ); + + if (ARGUMENT_PRESENT( ReturnedBreakpoint )) { + *ReturnedBreakpoint = Breakpoint; + } + + return TRUE; +} + + +BOOLEAN +DestroyBreakpoint( + LPVOID Address, + PPROCESS_INFO Process, + PTHREAD_INFO Thread + ) +{ + PBREAKPOINT_INFO Breakpoint; + + Breakpoint = FindBreakpoint( Address, Process, Thread ); + if (Breakpoint == NULL) { + return FALSE; + } + + RemoveBreakpoint( Process, Breakpoint ); + + RemoveEntryList( &Breakpoint->Entry ); + + FreeMem( &Breakpoint ); + return TRUE; +} + + +BOOLEAN +HandleThreadsForSingleStep( + PPROCESS_INFO Process, + PTHREAD_INFO ThreadToSingleStep, + BOOLEAN SuspendThreads + ) +{ + PLIST_ENTRY Next, Head; + PTHREAD_INFO Thread; + + Head = &Process->ThreadListHead; + Next = Head->Flink; + while (Next != Head) { + Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry ); + if (Thread != ThreadToSingleStep) { + if (SuspendThreads) { + if (Thread->BreakpointToStepOver == NULL) { + SuspendThread( Thread->Handle ); + } + } + else { + ResumeThread( Thread->Handle ); + } + + break; + } + + Next = Next->Flink; + } + + return TRUE; +} + + +BOOLEAN +ReadMemory( + PPROCESS_INFO Process, + PVOID Address, + PVOID DataRead, + ULONG BytesToRead, + PCHAR Reason + ) +{ + ULONG BytesRead; + + if (!ReadProcessMemory( Process->Handle, + Address, + DataRead, + BytesToRead, + &BytesRead + ) || + BytesRead != BytesToRead + ) { + DbgEvent( MEMORYERROR, ( "Read memory from %x for %x bytes failed (%u) - '%s'\n", + Address, + BytesToRead, + GetLastError(), + Reason + ) + ); + return FALSE; + } + else { + return TRUE; + } +} + + +BOOLEAN +WriteMemory( + PPROCESS_INFO Process, + PVOID Address, + PVOID DataToWrite, + ULONG BytesToWrite, + PCHAR Reason + ) +{ + ULONG BytesWritten; + ULONG OldProtection; + BOOLEAN Result; + + if (WriteProcessMemory( Process->Handle, + Address, + DataToWrite, + BytesToWrite, + &BytesWritten + ) && + BytesWritten == BytesToWrite + ) { + return TRUE; + } + + Result = FALSE; + if (GetLastError() == ERROR_NOACCESS && + VirtualProtectEx( Process->Handle, + Address, + BytesToWrite, + PAGE_READWRITE, + &OldProtection + ) + ) { + if (WriteProcessMemory( Process->Handle, + Address, + DataToWrite, + BytesToWrite, + &BytesWritten + ) && + BytesWritten == BytesToWrite + ) { + Result = TRUE; + } + VirtualProtectEx( Process->Handle, + Address, + BytesToWrite, + OldProtection, + &OldProtection + ); + if (Result) { + return TRUE; + } + } + + DbgEvent( MEMORYERROR, ( "Write memory to %x for %x bytes failed (%u) - '%s'\n", + Address, + BytesToWrite, + GetLastError(), + Reason + ) + ); + return FALSE; +} + + +PVOID +AllocMem( + ULONG Size + ) +{ + PVOID p; + + p = HeapAlloc( AppHeap, HEAP_ZERO_MEMORY, Size ); + if (p == NULL) { + DbgEvent( INTERNALERROR, ( "HeapAlloc( %0x8 ) failed\n", Size ) ); + } + + + + return p; +} + + +VOID +FreeMem( + PVOID *p + ) +{ + if (*p != NULL) { + HeapFree( AppHeap, 0, *p ); + *p = NULL; + } + + return; +} diff --git a/private/sdktools/instaler/res.h b/private/sdktools/instaler/res.h new file mode 100644 index 000000000..c1a489bf4 --- /dev/null +++ b/private/sdktools/instaler/res.h @@ -0,0 +1,2 @@ +#define FILEBMP 500 +#define DIRBMP 501 diff --git a/private/sdktools/instaler/showinst.c b/private/sdktools/instaler/showinst.c new file mode 100644 index 000000000..9cba9b2b3 --- /dev/null +++ b/private/sdktools/instaler/showinst.c @@ -0,0 +1,295 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + showinst.c + +Abstract: + + This program displays the contents of an Installation Modification Log file + created by the INSTALER program + +Author: + + Steve Wood (stevewo) 15-Jan-1996 + +Revision History: + +--*/ + +#include "instutil.h" +#include "iml.h" + +BOOLEAN DisplayContentsOfTextFiles; + +int +ProcessShowIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml + ); + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + int Result; + char *s; + PWSTR pw; + PINSTALLATION_MODIFICATION_LOGFILE pIml; + + InitCommonCode( "SHOWINST", + "[-c]", + "-c specifies to display the contents of text files\n" + ); + DisplayContentsOfTextFiles = FALSE; + while (--argc) { + s = *++argv; + if (*s == '-' || *s == '/') { + while (*++s) { + switch( tolower( *s ) ) { + case 'c': + DisplayContentsOfTextFiles = TRUE; + break; + default: + CommonSwitchProcessing( &argc, &argv, *s ); + break; + } + } + } + else + if (!CommonArgProcessing( &argc, &argv )) { + Usage( "Arguments not supported - '%s'", (ULONG)s ); + } + } + + if (ImlPath == NULL) { + Usage( "Must specify an installation name as first argument", 0 ); + } + + if (!SetCurrentDirectory( InstalerDirectory )) { + FatalError( "Unable to change to '%ws' directory (%u)", + (ULONG)InstalerDirectory, + GetLastError() + ); + } + + pIml = LoadIml( ImlPath ); + if (pIml == NULL) { + FatalError( "Unable to open '%ws' (%u)", + (ULONG)ImlPath, + GetLastError() + ); + } + Result = ProcessShowIml( pIml ); + + CloseIml( pIml ); + exit( Result ); + return Result; +} + +int +ProcessShowIml( + PINSTALLATION_MODIFICATION_LOGFILE pIml + ) +{ + PIML_FILE_RECORD pFile; + PIML_FILE_RECORD_CONTENTS pOldFile; + PIML_FILE_RECORD_CONTENTS pNewFile; + PIML_KEY_RECORD pKey; + PIML_VALUE_RECORD pValue; + PIML_VALUE_RECORD_CONTENTS pOldValue; + PIML_VALUE_RECORD_CONTENTS pNewValue; + PIML_INI_RECORD pIni; + PIML_INISECTION_RECORD pSection; + PIML_INIVARIABLE_RECORD pVariable; + BOOLEAN FileNameShown; + BOOLEAN SectionNameShown; + + if (pIml->NumberOfFileRecords > 0) { + printf( "File Modifications:\n" ); + pFile = MP( PIML_FILE_RECORD, pIml, pIml->FileRecords ); + while (pFile != NULL) { + pOldFile = MP( PIML_FILE_RECORD_CONTENTS, pIml, pFile->OldFile ); + pNewFile = MP( PIML_FILE_RECORD_CONTENTS, pIml, pFile->NewFile ); + printf( " %ws - ", MP( PWSTR, pIml, pFile->Name ) ); + switch( pFile->Action ) { + case CreateNewFile: + printf( "created\n" ); + break; + + case ModifyOldFile: + printf( "overwritten\n" ); + if (pOldFile != NULL) { + printf( " Old size is %u bytes\n", pOldFile->FileSize ); + } + break; + + case DeleteOldFile: + printf( "deleted\n" ); + if (pOldFile != NULL) { + printf( " Old size is %u bytes\n", pOldFile->FileSize ); + } + break; + + case ModifyFileDateTime: + printf( "date/time modified\n" ); + break; + + case ModifyFileAttributes: + printf( "attributes modified\n" ); + break; + } + + pFile = MP( PIML_FILE_RECORD, pIml, pFile->Next ); + } + + printf( "\n" ); + } + + if (pIml->NumberOfKeyRecords > 0) { + printf( "Registry Modifications:\n" ); + pKey = MP( PIML_KEY_RECORD, pIml, pIml->KeyRecords ); + while (pKey != NULL) { + printf( " %ws - ", MP( PWSTR, pIml, pKey->Name ) ); + switch( pKey->Action ) { + case CreateNewKey: + printf( "created\n" ); + break; + + case DeleteOldKey: + printf( "deleted\n" ); + break; + + + case ModifyKeyValues: + printf( "modified\n" ); + break; + + } + + pValue = MP( PIML_VALUE_RECORD, pIml, pKey->Values ); + while (pValue != NULL) { + pOldValue = MP( PIML_VALUE_RECORD_CONTENTS, pIml, pValue->OldValue ); + pNewValue = MP( PIML_VALUE_RECORD_CONTENTS, pIml, pValue->NewValue ); + printf( " %ws - ", MP( PWSTR, pIml, pValue->Name ) ); + if (pValue->Action != DeleteOldValue) { + printf( "%s [%x]", + FormatEnumType( 0, ValueDataTypeNames, pNewValue->Type, FALSE ), + pNewValue->Length + ); + if (pNewValue->Type == REG_SZ || + pNewValue->Type == REG_EXPAND_SZ + ) { + printf( " '%ws'", MP( PWSTR, pIml, pNewValue->Data ) ); + } + else + if (pNewValue->Type == REG_DWORD) { + printf( " 0x%x", *MP( PULONG, pIml, pNewValue->Data ) ); + } + } + + if (pValue->Action == CreateNewValue) { + printf( " (created)\n" ); + } + else { + if (pValue->Action == DeleteOldValue) { + printf( " (deleted" ); + } + else { + printf( " (modified" ); + } + + printf( " - was %s [%x]", + FormatEnumType( 0, ValueDataTypeNames, pOldValue->Type, FALSE ), + pOldValue->Length + ); + if (pOldValue->Type == REG_SZ || + pOldValue->Type == REG_EXPAND_SZ + ) { + printf( " '%ws'", MP( PWSTR, pIml, pOldValue->Data ) ); + } + else + if (pOldValue->Type == REG_DWORD) { + printf( " 0x%x", *MP( PULONG, pIml, pOldValue->Data ) ); + } + + printf( " )\n" ); + } + + pValue = MP( PIML_VALUE_RECORD, pIml, pValue->Next ); + } + + pKey = MP( PIML_KEY_RECORD, pIml, pKey->Next ); + } + + printf( "\n" ); + } + + if (pIml->NumberOfIniRecords > 0) { + printf( ".INI File modifications:\n" ); + pIni = MP( PIML_INI_RECORD, pIml, pIml->IniRecords ); + while (pIni != NULL) { + FileNameShown = FALSE; + pSection = MP( PIML_INISECTION_RECORD, pIml, pIni->Sections ); + while (pSection != NULL) { + SectionNameShown = FALSE; + pVariable = MP( PIML_INIVARIABLE_RECORD, pIml, pSection->Variables ); + while (pVariable != NULL) { + if (!FileNameShown) { + printf( "%ws", MP( PWSTR, pIml, pIni->Name ) ); + if (pIni->Action == CreateNewIniFile) { + printf( " (created)" ); + } + printf( "\n" ); + FileNameShown = TRUE; + } + + if (!SectionNameShown) { + printf( " [%ws]", MP( PWSTR, pIml, pSection->Name ) ); + if (pSection->Action == CreateNewSection) { + printf( " (created)" ); + } + else + if (pSection->Action == DeleteOldSection) { + printf( " (deleted)" ); + } + printf( "\n" ); + + SectionNameShown = TRUE; + } + + printf( " %ws = ", MP( PWSTR, pIml, pVariable->Name ) ); + if (pVariable->Action == CreateNewVariable) { + printf( "'%ws' (created)\n", MP( PWSTR, pIml, pVariable->NewValue ) ); + } + else + if (pVariable->Action == DeleteOldVariable) { + printf( " (deleted - was '%ws')\n", MP( PWSTR, pIml, pVariable->OldValue ) ); + } + else { + printf( "'%ws' (modified - was '%ws')\n", + MP( PWSTR, pIml, pVariable->NewValue ), + MP( PWSTR, pIml, pVariable->OldValue ) + ); + } + + pVariable = MP( PIML_INIVARIABLE_RECORD, pIml, pVariable->Next ); + } + + pSection = MP( PIML_INISECTION_RECORD, pIml, pSection->Next ); + } + + if (FileNameShown) { + printf( "\n" ); + } + + pIni = MP( PIML_INI_RECORD, pIml, pIni->Next ); + } + } + + return 0; +} diff --git a/private/sdktools/instaler/showinst.rc b/private/sdktools/instaler/showinst.rc new file mode 100644 index 000000000..399061b50 --- /dev/null +++ b/private/sdktools/instaler/showinst.rc @@ -0,0 +1,12 @@ +#include "instaler.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Instaler Display Program" +#define VER_INTERNALNAME_STR "SHOWINST\0" +#define VER_ORIGINALFILENAME_STR "SHOWINST.EXE" + +#include "common.ver" + +RCINCLUDE errormsg.rc diff --git a/private/sdktools/instaler/sources b/private/sdktools/instaler/sources new file mode 100644 index 000000000..c77ff7f6b --- /dev/null +++ b/private/sdktools/instaler/sources @@ -0,0 +1,36 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=sdktools +MINORCOMP=instaler + +TARGETNAME=instaler +TARGETPATH=obj +TARGETTYPE=LIBRARY + +MSC_WARNING_LEVEL=/W3 /WX + +C_DEFINES=-DUNICODE -D_UNICODE + +SOURCES= diff --git a/private/sdktools/instaler/test.c b/private/sdktools/instaler/test.c new file mode 100644 index 000000000..8579fbcaf --- /dev/null +++ b/private/sdktools/instaler/test.c @@ -0,0 +1,389 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + test.c + +Abstract: + + This is a test program that issues various Kernel 32 file/registry/INI file + API calls so that we can see if the INSTALER program figures out correctly + what is being done. + + This program assumes that the following conditions exist: + + TEST subdirectory + + +Author: + + Steve Wood (stevewo) 13-Aug-1994 + +--*/ + + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntdbg.h> +#include <windows.h> +#include <stdio.h> +#include <string.h> + +UCHAR AnsiBuffer[ MAX_PATH ]; +WCHAR UnicodeBuffer[ MAX_PATH ]; + + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + FILE *File0; + FILE *File1; + FILE *File2; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; + BOOLEAN TranslationStatus; + UNICODE_STRING FileName; + RTL_RELATIVE_NAME RelativeName; + PVOID FreeBuffer; + UNICODE_STRING KeyName; + UNICODE_STRING SubKeyName; + UNICODE_STRING ValueName; + HANDLE FileHandle, FindHandle, KeyHandle, SubKeyHandle; + ULONG ValueDWord = 0x12345678; + WIN32_FIND_DATAW FindFileData; + LPSTR s1; + PWSTR s2; + UCHAR AnsiBuffer[ MAX_PATH ]; + WCHAR UnicodeBuffer[ MAX_PATH ]; + DWORD dwVersion; + OSVERSIONINFO VersionInfo; + HKEY hKey; + + // + // File operations we want to test: + // + // Creating a new file. + // Deleting that file using DeleteFile (which does NtOpenFile and NtSetInformationFile + // with Delete Dispostion). (INSTALER should use this to forget about create). + // Creating a new file with the same name. + // Deleting that file using NtDeleteFile. (again INSTALER should not care). + // + // Open the TEST1 file for read access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // + // + + // printf( "TEST: GetFileAttributes( .\\test1 )\n" ); + GetFileAttributesA( ".\\test1" ); +#if 0 + dwVersion = GetVersion(); + if ((dwVersion >> 30) ^ 0x2 == VER_PLATFORM_WIN32_WINDOWS) { + printf( "GetVersion returns Windows 95\n" ); + } + else + if ((dwVersion >> 30) ^ 0x2 == VER_PLATFORM_WIN32_NT) { + printf( "GetVersion returns Windows NT\n" ); + } + else { + printf( "GetVersion returns %x\n", dwVersion ); + } + fflush(stdout); + + VersionInfo.dwOSVersionInfoSize = sizeof( VersionInfo ); + GetVersionEx( &VersionInfo ); + if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + printf( "GetVersionEx returns Windows 95\n" ); + } + else + if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + printf( "GetVersionEx returns Windows NT\n" ); + } + else { + printf( "GetVersionEx returns %x\n", VersionInfo.dwPlatformId ); + } + fflush(stdout); + + if (RegConnectRegistryA( "\\\\stevewo_dbgr", HKEY_USERS, &hKey )) { + printf( "RegConnectRegistryA( \\stevewo_dbgr ) failed (hKey == %x).\n", hKey ); + } + else { + printf( "RegConnectRegistryA( \\stevewo_dbgr ) succeeded (hKey == %x).\n", hKey ); + RegCloseKey( hKey ); + } + + if (RegConnectRegistryW( L"\\\\stevewo_dbgr", HKEY_USERS, &hKey )) { + printf( "RegConnectRegistryW( \\stevewo_dbgr ) failed (hKey == %x).\n", hKey ); + } + else { + printf( "RegConnectRegistryW( \\stevewo_dbgr ) succeeded (hKey == %x).\n", hKey ); + RegCloseKey( hKey ); + } +#endif + + RtlInitUnicodeString( &FileName, L"\\DosDevices\\A:" ); + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // printf( "TEST: NtOpenFile( %wZ ) should succeed without touching floppy.\n", &FileName ); + Status = NtOpenFile( &FileHandle, + SYNCHRONIZE | FILE_READ_ATTRIBUTES, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + if (!NT_SUCCESS( Status )) { + printf( "TEST: Failed - Status == %x\n", Status ); + } + else { + NtClose( FileHandle ); + } + + // printf( "TEST: FindFirstFileW( C:\\*.* should fail.\n" ); + FindHandle = FindFirstFileW( L"C:\\*.*", &FindFileData ); + if (FindHandle != INVALID_HANDLE_VALUE) { + printf( "TEST: *** oops, it worked.\n" ); + FindClose( FindHandle ); + } + // printf( "TEST: FindFirstFileW( \\TMP\\*.* should work.\n" ); + FindHandle = FindFirstFileW( L"\\TMP\\*.*", &FindFileData ); + if (FindHandle == INVALID_HANDLE_VALUE) { + printf( "TEST: *** oops, it failed.\n" ); + } + else { + FindClose( FindHandle ); + } + + // printf( "TEST: opening .\\test0 for write access.\n" ); + if (File0 = fopen( "test0.", "w" )) { + fprintf( File0, "This is test file 0\n" ); + // printf( "TEST: closing .\\test0\n" ); + fclose( File0 ); + // printf( "TEST: deleting .\\test0 using DeleteFile (open, set, close)\n" ); + DeleteFile( L"test0" ); + } + + // printf( "TEST: opening .\\test0 for write access.\n" ); + if (File0 = fopen( "test0.", "w" )) { + fprintf( File0, "This is test file 0\n" ); + // printf( "TEST: closing .\\test0\n" ); + fclose( File0 ); + + TranslationStatus = RtlDosPathNameToNtPathName_U( + L"test0", + &FileName, + NULL, + &RelativeName + ); + + if (TranslationStatus ) { + FreeBuffer = FileName.Buffer; + if ( RelativeName.RelativeName.Length ) { + FileName = *(PUNICODE_STRING)&RelativeName.RelativeName; + } + else { + RelativeName.ContainingDirectory = NULL; + } + + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + RelativeName.ContainingDirectory, + NULL + ); + // printf( "TEST: deleting .\\test0 using NtDeleteFile\n" ); + Status = NtDeleteFile( &ObjectAttributes ); + RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer ); + } + } + + // printf( "TEST: opening .\\test1 for write access.\n" ); + if (File1 = fopen( "test1.", "w" )) { + fprintf( File1, "This is test file 1\n" ); + // printf( "TEST: closing .\\test1\n" ); + fclose( File1 ); + } + + // printf( "TEST: opening .\\test2 for write access (Instaler should noticed contents different)\n" ); + if (File2 = fopen( "test2.", "w" )) { + fprintf( File2, "This is test file 2\n" ); + // printf( "TEST: closing .\\test2\n" ); + fclose( File2 ); + } + + // printf( "TEST: opening .\\test0.tmp for write access.\n" ); + if (File0 = fopen( "test0.tmp", "w" )) { + fprintf( File0, "This is test file tmp files\n" ); + // printf( "TEST: closing .\\test0.tmp\n" ); + fclose( File0 ); + // printf( "TEST: deleting .\\test0 using DeleteFile (open, set, close)\n" ); + rename("test0.tmp", "test0.fin"); + } + + RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\Software\\Test" ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // printf( "TEST: opening %wZ for write access\n", &KeyName ); + Status = NtOpenKey( &KeyHandle, + KEY_WRITE, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test0" ); + // printf( "TEST: setting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + REG_SZ, + "0", + 2 * sizeof( WCHAR ) + ); + + RtlInitUnicodeString( &ValueName, L"Test1" ); + // printf( "TEST: deleting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtDeleteValueKey( KeyHandle, + &ValueName + ); + + RtlInitUnicodeString( &ValueName, L"Test2" ); + // printf( "TEST: setting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + RtlInitUnicodeString( &SubKeyName, L"Test3" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: opening %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtOpenKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + // printf( "TEST: deleting %wZ\\%wZ key and values\n", &KeyName, &SubKeyName ); + Status = NtDeleteKey( SubKeyHandle ); + NtClose( SubKeyHandle ); + } + + RtlInitUnicodeString( &SubKeyName, L"Test4" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: creating %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtCreateKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test4" ); + // printf( "TEST: creating %wZ\\%wZ %wZ value\n", &KeyName, &SubKeyName, &ValueName ); + Status = NtSetValueKey( SubKeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + NtClose( SubKeyHandle ); + } + + RtlInitUnicodeString( &SubKeyName, L"Test5" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: creating %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtCreateKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test5" ); + // printf( "TEST: creating %wZ\\%wZ %wZ value\n", &KeyName, &SubKeyName, &ValueName ); + Status = NtSetValueKey( SubKeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + // printf( "TEST: deleting %wZ\\%wZ key and values\n", &KeyName, &SubKeyName ); + Status = NtDeleteKey( SubKeyHandle ); + NtClose( SubKeyHandle ); + } + + NtClose( KeyHandle ); + } + + GetPrivateProfileStringA( "test", NULL, "", + AnsiBuffer, + sizeof( AnsiBuffer ), + ".\\test.ini" + ); + + GetPrivateProfileStringW( L"test", NULL, L"", + UnicodeBuffer, + sizeof( UnicodeBuffer ), + L".\\test.ini" + ); + + + if (!SetCurrentDirectoryA( ".." )) { + printf( "TEST: SetCurrentDirectory to '..' failed (%u)\n", GetLastError() ); + } + + WriteProfileString( L"fonts", L"FooBar", L"1" ); + + WriteProfileString( L"fonts", L"Rockwell Italic (TrueType)", L"ROCKI.FOT" ); + + if (!SetCurrentDirectoryW( L"test" )) { + printf( "TEST: SetCurrentDirectory to 'test' failed (%u)\n", GetLastError() ); + } + + WritePrivateProfileStringA( "test", "test1", "-1", ".\\test.ini" ); + + WritePrivateProfileStringW( L"test", L"test1", L"-2", L".\\test.ini" ); + + WritePrivateProfileSectionA( "test1", "test0=0\0test1=1\0test2=2\0", ".\\test.ini" ); + + WritePrivateProfileSectionW( L"test2", L"test0=0\0test1=1\0test2=2\0", L".\\test.ini" ); + + return 0; +} diff --git a/private/sdktools/instaler/testins1.c b/private/sdktools/instaler/testins1.c new file mode 100644 index 000000000..4d2c0a0f1 --- /dev/null +++ b/private/sdktools/instaler/testins1.c @@ -0,0 +1,384 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + testins1.c + +Abstract: + + This is a test program that issues various Kernel 32 file/registry/INI file + API calls so that we can see if the INSTALER program figures out correctly + what is being done. + +Author: + + Steve Wood (stevewo) 13-Aug-1994 + +--*/ + + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntdbg.h> +#include <windows.h> +#include <stdio.h> +#include <string.h> + +UCHAR AnsiBuffer[ MAX_PATH ]; +WCHAR UnicodeBuffer[ MAX_PATH ]; + + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + FILE *File0; + FILE *File1; + FILE *File2; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; + BOOLEAN TranslationStatus; + UNICODE_STRING FileName; + RTL_RELATIVE_NAME RelativeName; + PVOID FreeBuffer; + UNICODE_STRING KeyName; + UNICODE_STRING SubKeyName; + UNICODE_STRING ValueName; + HANDLE FileHandle, FindHandle, KeyHandle, SubKeyHandle; + ULONG ValueDWord = 0x12345678; + WIN32_FIND_DATAW FindFileData; + LPSTR s1; + PWSTR s2; + UCHAR AnsiBuffer[ MAX_PATH ]; + WCHAR UnicodeBuffer[ MAX_PATH ]; + DWORD dwVersion; + OSVERSIONINFO VersionInfo; + HKEY hKey; + + // + // File operations we want to test: + // + // Creating a new file. + // Deleting that file using DeleteFile (which does NtOpenFile and NtSetInformationFile + // with Delete Dispostion). (INSTALER should use this to forget about create). + // Creating a new file with the same name. + // Deleting that file using NtDeleteFile. (again INSTALER should not care). + // + // Open the TEST1 file for read access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // + // + + // printf( "TEST: GetFileAttributes( .\\test1 )\n" ); + GetFileAttributesA( ".\\test1" ); +#if 0 + dwVersion = GetVersion(); + if ((dwVersion >> 30) ^ 0x2 == VER_PLATFORM_WIN32_WINDOWS) { + printf( "GetVersion returns Windows 95\n" ); + } + else + if ((dwVersion >> 30) ^ 0x2 == VER_PLATFORM_WIN32_NT) { + printf( "GetVersion returns Windows NT\n" ); + } + else { + printf( "GetVersion returns %x\n", dwVersion ); + } + fflush(stdout); + + VersionInfo.dwOSVersionInfoSize = sizeof( VersionInfo ); + GetVersionEx( &VersionInfo ); + if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + printf( "GetVersionEx returns Windows 95\n" ); + } + else + if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + printf( "GetVersionEx returns Windows NT\n" ); + } + else { + printf( "GetVersionEx returns %x\n", VersionInfo.dwPlatformId ); + } + fflush(stdout); + + if (RegConnectRegistryA( "\\\\stevewo_dbgr", HKEY_USERS, &hKey )) { + printf( "RegConnectRegistryA( \\stevewo_dbgr ) failed (hKey == %x).\n", hKey ); + } + else { + printf( "RegConnectRegistryA( \\stevewo_dbgr ) succeeded (hKey == %x).\n", hKey ); + RegCloseKey( hKey ); + } + + if (RegConnectRegistryW( L"\\\\stevewo_dbgr", HKEY_USERS, &hKey )) { + printf( "RegConnectRegistryW( \\stevewo_dbgr ) failed (hKey == %x).\n", hKey ); + } + else { + printf( "RegConnectRegistryW( \\stevewo_dbgr ) succeeded (hKey == %x).\n", hKey ); + RegCloseKey( hKey ); + } +#endif + + RtlInitUnicodeString( &FileName, L"\\DosDevices\\A:" ); + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // printf( "TEST: NtOpenFile( %wZ ) should succeed without touching floppy.\n", &FileName ); + Status = NtOpenFile( &FileHandle, + SYNCHRONIZE | FILE_READ_ATTRIBUTES, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + if (!NT_SUCCESS( Status )) { + printf( "TEST: Failed - Status == %x\n", Status ); + } + else { + NtClose( FileHandle ); + } + + // printf( "TEST: FindFirstFileW( C:\\*.* should fail.\n" ); + FindHandle = FindFirstFileW( L"C:\\*.*", &FindFileData ); + if (FindHandle != INVALID_HANDLE_VALUE) { + printf( "TEST: *** oops, it worked.\n" ); + FindClose( FindHandle ); + } + // printf( "TEST: FindFirstFileW( \\TMP\\*.* should work.\n" ); + FindHandle = FindFirstFileW( L"\\TMP\\*.*", &FindFileData ); + if (FindHandle == INVALID_HANDLE_VALUE) { + printf( "TEST: *** oops, it failed.\n" ); + } + else { + FindClose( FindHandle ); + } + + // printf( "TEST: opening .\\test0 for write access.\n" ); + if (File0 = fopen( "test0.", "w" )) { + fprintf( File0, "This is test file 0\n" ); + // printf( "TEST: closing .\\test0\n" ); + fclose( File0 ); + // printf( "TEST: deleting .\\test0 using DeleteFile (open, set, close)\n" ); + DeleteFile( L"test0" ); + } + + // printf( "TEST: opening .\\test0 for write access.\n" ); + if (File0 = fopen( "test0.", "w" )) { + fprintf( File0, "This is test file 0\n" ); + // printf( "TEST: closing .\\test0\n" ); + fclose( File0 ); + + TranslationStatus = RtlDosPathNameToNtPathName_U( + L"test0", + &FileName, + NULL, + &RelativeName + ); + + if (TranslationStatus ) { + FreeBuffer = FileName.Buffer; + if ( RelativeName.RelativeName.Length ) { + FileName = *(PUNICODE_STRING)&RelativeName.RelativeName; + } + else { + RelativeName.ContainingDirectory = NULL; + } + + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + RelativeName.ContainingDirectory, + NULL + ); + // printf( "TEST: deleting .\\test0 using NtDeleteFile\n" ); + Status = NtDeleteFile( &ObjectAttributes ); + RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer ); + } + } + + // printf( "TEST: opening .\\test1 for write access.\n" ); + if (File1 = fopen( "test1.", "w" )) { + fprintf( File1, "This is test file 1\n" ); + // printf( "TEST: closing .\\test1\n" ); + fclose( File1 ); + } + + // printf( "TEST: opening .\\test2 for write access (Instaler should noticed contents different)\n" ); + if (File2 = fopen( "test2.", "w" )) { + fprintf( File2, "This is test file 2\n" ); + // printf( "TEST: closing .\\test2\n" ); + fclose( File2 ); + } + + // printf( "TEST: opening .\\test0.tmp for write access.\n" ); + if (File0 = fopen( "test0.tmp", "w" )) { + fprintf( File0, "This is test file tmp files\n" ); + // printf( "TEST: closing .\\test0.tmp\n" ); + fclose( File0 ); + // printf( "TEST: deleting .\\test0 using DeleteFile (open, set, close)\n" ); + rename("test0.tmp", "test0.fin"); + } + + RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\Software\\Test" ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // printf( "TEST: opening %wZ for write access\n", &KeyName ); + Status = NtOpenKey( &KeyHandle, + KEY_WRITE, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test0" ); + // printf( "TEST: setting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + REG_SZ, + "0", + 2 * sizeof( WCHAR ) + ); + + RtlInitUnicodeString( &ValueName, L"Test1" ); + // printf( "TEST: deleting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtDeleteValueKey( KeyHandle, + &ValueName + ); + + RtlInitUnicodeString( &ValueName, L"Test2" ); + // printf( "TEST: setting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + RtlInitUnicodeString( &SubKeyName, L"Test3" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: opening %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtOpenKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + // printf( "TEST: deleting %wZ\\%wZ key and values\n", &KeyName, &SubKeyName ); + Status = NtDeleteKey( SubKeyHandle ); + NtClose( SubKeyHandle ); + } + + RtlInitUnicodeString( &SubKeyName, L"Test4" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: creating %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtCreateKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test4" ); + // printf( "TEST: creating %wZ\\%wZ %wZ value\n", &KeyName, &SubKeyName, &ValueName ); + Status = NtSetValueKey( SubKeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + NtClose( SubKeyHandle ); + } + + RtlInitUnicodeString( &SubKeyName, L"Test5" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: creating %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtCreateKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test5" ); + // printf( "TEST: creating %wZ\\%wZ %wZ value\n", &KeyName, &SubKeyName, &ValueName ); + Status = NtSetValueKey( SubKeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + // printf( "TEST: deleting %wZ\\%wZ key and values\n", &KeyName, &SubKeyName ); + Status = NtDeleteKey( SubKeyHandle ); + NtClose( SubKeyHandle ); + } + + NtClose( KeyHandle ); + } + + GetPrivateProfileStringA( "test", NULL, "", + AnsiBuffer, + sizeof( AnsiBuffer ), + ".\\test.ini" + ); + + GetPrivateProfileStringW( L"test", NULL, L"", + UnicodeBuffer, + sizeof( UnicodeBuffer ), + L".\\test.ini" + ); + + + if (!SetCurrentDirectoryA( ".." )) { + printf( "TEST: SetCurrentDirectory to '..' failed (%u)\n", GetLastError() ); + } + + WriteProfileString( L"fonts", L"FooBar", L"1" ); + + WriteProfileString( L"fonts", L"Rockwell Italic (TrueType)", L"ROCKI.FOT" ); + + if (!SetCurrentDirectoryW( L"test" )) { + printf( "TEST: SetCurrentDirectory to 'test' failed (%u)\n", GetLastError() ); + } + + WritePrivateProfileStringA( "test", "test1", "-1", ".\\test.ini" ); + + WritePrivateProfileStringW( L"test", L"test1", L"-2", L".\\test.ini" ); + + WritePrivateProfileSectionA( "test1", "test0=0\0test1=1\0test2=2\0", ".\\test.ini" ); + + WritePrivateProfileSectionW( L"test2", L"test0=0\0test1=1\0test2=2\0", L".\\test.ini" ); + + return 0; +} diff --git a/private/sdktools/instaler/testins1.rc b/private/sdktools/instaler/testins1.rc new file mode 100644 index 000000000..75c36422f --- /dev/null +++ b/private/sdktools/instaler/testins1.rc @@ -0,0 +1,12 @@ +#include "instaler.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Instaler Test Program" +#define VER_INTERNALNAME_STR "TESTINST\0" +#define VER_ORIGINALFILENAME_STR "TESTINST.EXE" + +#include "common.ver" + +RCINCLUDE errormsg.rc diff --git a/private/sdktools/instaler/testins2.c b/private/sdktools/instaler/testins2.c new file mode 100644 index 000000000..23513d751 --- /dev/null +++ b/private/sdktools/instaler/testins2.c @@ -0,0 +1,387 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + testins2.c + +Abstract: + + This is a test program that issues various Kernel 32 file/registry/INI file + API calls so that we can see if the INSTALER program figures out correctly + what is being done. + +Author: + + Steve Wood (stevewo) 13-Aug-1994 + +--*/ + + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntdbg.h> +#include <windows.h> +#include <stdio.h> +#include <string.h> + +UCHAR AnsiBuffer[ MAX_PATH ]; +WCHAR UnicodeBuffer[ MAX_PATH ]; + + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + FILE *File0; + FILE *File1; + FILE *File2; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; + BOOLEAN TranslationStatus; + UNICODE_STRING FileName; + RTL_RELATIVE_NAME RelativeName; + PVOID FreeBuffer; + UNICODE_STRING KeyName; + UNICODE_STRING SubKeyName; + UNICODE_STRING ValueName; + HANDLE FileHandle, FindHandle, KeyHandle, SubKeyHandle; + ULONG ValueDWord = 0x12345679; + WIN32_FIND_DATAW FindFileData; + LPSTR s1; + PWSTR s2; + UCHAR AnsiBuffer[ MAX_PATH ]; + WCHAR UnicodeBuffer[ MAX_PATH ]; + DWORD dwVersion; + OSVERSIONINFO VersionInfo; + HKEY hKey; + + // + // File operations we want to test: + // + // Creating a new file. + // Deleting that file using DeleteFile (which does NtOpenFile and NtSetInformationFile + // with Delete Dispostion). (INSTALER should use this to forget about create). + // Creating a new file with the same name. + // Deleting that file using NtDeleteFile. (again INSTALER should not care). + // + // Open the TEST1 file for read access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // Open the TEST2 file for write access (INSTALER should not care). + // + // + + // printf( "TEST: GetFileAttributes( .\\test1 )\n" ); + GetFileAttributesA( ".\\test1" ); +#if 0 + dwVersion = GetVersion(); + if ((dwVersion >> 30) ^ 0x2 == VER_PLATFORM_WIN32_WINDOWS) { + printf( "GetVersion returns Windows 95\n" ); + } + else + if ((dwVersion >> 30) ^ 0x2 == VER_PLATFORM_WIN32_NT) { + printf( "GetVersion returns Windows NT\n" ); + } + else { + printf( "GetVersion returns %x\n", dwVersion ); + } + fflush(stdout); + + VersionInfo.dwOSVersionInfoSize = sizeof( VersionInfo ); + GetVersionEx( &VersionInfo ); + if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + printf( "GetVersionEx returns Windows 95\n" ); + } + else + if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + printf( "GetVersionEx returns Windows NT\n" ); + } + else { + printf( "GetVersionEx returns %x\n", VersionInfo.dwPlatformId ); + } + fflush(stdout); + + if (RegConnectRegistryA( "\\\\stevewo_dbgr", HKEY_USERS, &hKey )) { + printf( "RegConnectRegistryA( \\stevewo_dbgr ) failed (hKey == %x).\n", hKey ); + } + else { + printf( "RegConnectRegistryA( \\stevewo_dbgr ) succeeded (hKey == %x).\n", hKey ); + RegCloseKey( hKey ); + } + + if (RegConnectRegistryW( L"\\\\stevewo_dbgr", HKEY_USERS, &hKey )) { + printf( "RegConnectRegistryW( \\stevewo_dbgr ) failed (hKey == %x).\n", hKey ); + } + else { + printf( "RegConnectRegistryW( \\stevewo_dbgr ) succeeded (hKey == %x).\n", hKey ); + RegCloseKey( hKey ); + } +#endif + + RtlInitUnicodeString( &FileName, L"\\DosDevices\\A:" ); + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // printf( "TEST: NtOpenFile( %wZ ) should succeed without touching floppy.\n", &FileName ); + Status = NtOpenFile( &FileHandle, + SYNCHRONIZE | FILE_READ_ATTRIBUTES, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + if (!NT_SUCCESS( Status )) { + printf( "TEST: Failed - Status == %x\n", Status ); + } + else { + NtClose( FileHandle ); + } + + // printf( "TEST: FindFirstFileW( C:\\*.* should fail.\n" ); + FindHandle = FindFirstFileW( L"C:\\*.*", &FindFileData ); + if (FindHandle != INVALID_HANDLE_VALUE) { + printf( "TEST: *** oops, it worked.\n" ); + FindClose( FindHandle ); + } + // printf( "TEST: FindFirstFileW( \\TMP\\*.* should work.\n" ); + FindHandle = FindFirstFileW( L"\\TMP\\*.*", &FindFileData ); + if (FindHandle == INVALID_HANDLE_VALUE) { + printf( "TEST: *** oops, it failed.\n" ); + } + else { + FindClose( FindHandle ); + } + + // printf( "TEST: opening .\\test0 for write access.\n" ); + if (File0 = fopen( "test0.", "w" )) { + fprintf( File0, "This is test file 0\n" ); + // printf( "TEST: closing .\\test0\n" ); + fclose( File0 ); + // printf( "TEST: deleting .\\test0 using DeleteFile (open, set, close)\n" ); + DeleteFile( L"test0" ); + } + + // printf( "TEST: opening .\\test0 for write access.\n" ); + if (File0 = fopen( "test0.", "w" )) { + fprintf( File0, "This is test file 0\n" ); + // printf( "TEST: closing .\\test0\n" ); + fclose( File0 ); +#if 0 + TranslationStatus = RtlDosPathNameToNtPathName_U( + L"test0", + &FileName, + NULL, + &RelativeName + ); + + if (TranslationStatus ) { + FreeBuffer = FileName.Buffer; + if ( RelativeName.RelativeName.Length ) { + FileName = *(PUNICODE_STRING)&RelativeName.RelativeName; + } + else { + RelativeName.ContainingDirectory = NULL; + } + + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + RelativeName.ContainingDirectory, + NULL + ); + // printf( "TEST: deleting .\\test0 using NtDeleteFile\n" ); + Status = NtDeleteFile( &ObjectAttributes ); + RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer ); + } +#endif + } + + // printf( "TEST: opening .\\test1 for write access.\n" ); + if (File1 = fopen( "test1.", "w" )) { + fprintf( File1, "This is test file 1a\n" ); + // printf( "TEST: closing .\\test1\n" ); + fclose( File1 ); + } + + // printf( "TEST: opening .\\test2 for write access (Instaler should noticed contents different)\n" ); + if (File2 = fopen( "test2.", "w" )) { + fprintf( File2, "This is test file 2\n" ); + // printf( "TEST: closing .\\test2\n" ); + fclose( File2 ); + } + + // printf( "TEST: opening .\\test0.tmp for write access.\n" ); + if (File0 = fopen( "test0.tmp", "w" )) { + fprintf( File0, "This is test file tmp files\n" ); + // printf( "TEST: closing .\\test0.tmp\n" ); + fclose( File0 ); + // printf( "TEST: deleting .\\test0 using DeleteFile (open, set, close)\n" ); + rename("test0.tmp", "test0.fin"); + } + rename("test1.", "test2.fin"); + rename("test3.", "test3.fin"); + + RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\Software\\Test" ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + // printf( "TEST: opening %wZ for write access\n", &KeyName ); + Status = NtOpenKey( &KeyHandle, + KEY_WRITE, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test0" ); + // printf( "TEST: setting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + REG_SZ, + "1", + 2 * sizeof( WCHAR ) + ); + + RtlInitUnicodeString( &ValueName, L"Test1" ); + // printf( "TEST: deleting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtDeleteValueKey( KeyHandle, + &ValueName + ); + + RtlInitUnicodeString( &ValueName, L"Test2" ); + // printf( "TEST: setting %wZ . %wZ value\n", &KeyName, &ValueName ); + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + RtlInitUnicodeString( &SubKeyName, L"Test3" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: opening %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtOpenKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + // printf( "TEST: deleting %wZ\\%wZ key and values\n", &KeyName, &SubKeyName ); + Status = NtDeleteKey( SubKeyHandle ); + NtClose( SubKeyHandle ); + } + + RtlInitUnicodeString( &SubKeyName, L"Test4" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: creating %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtCreateKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test4" ); + // printf( "TEST: creating %wZ\\%wZ %wZ value\n", &KeyName, &SubKeyName, &ValueName ); + Status = NtSetValueKey( SubKeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + NtClose( SubKeyHandle ); + } + + RtlInitUnicodeString( &SubKeyName, L"Test5" ); + InitializeObjectAttributes( &ObjectAttributes, + &SubKeyName, + OBJ_CASE_INSENSITIVE, + KeyHandle, + NULL + ); + // printf( "TEST: creating %wZ\\%wZ for write access\n", &KeyName, &SubKeyName ); + Status = NtCreateKey( &SubKeyHandle, + DELETE | KEY_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + if (NT_SUCCESS( Status )) { + RtlInitUnicodeString( &ValueName, L"Test5" ); + // printf( "TEST: creating %wZ\\%wZ %wZ value\n", &KeyName, &SubKeyName, &ValueName ); + Status = NtSetValueKey( SubKeyHandle, + &ValueName, + 0, + REG_DWORD, + &ValueDWord, + sizeof( ValueDWord ) + ); + // printf( "TEST: deleting %wZ\\%wZ key and values\n", &KeyName, &SubKeyName ); + Status = NtDeleteKey( SubKeyHandle ); + NtClose( SubKeyHandle ); + } + + NtClose( KeyHandle ); + } + + GetPrivateProfileStringA( "test", NULL, "", + AnsiBuffer, + sizeof( AnsiBuffer ), + ".\\test.ini" + ); + + GetPrivateProfileStringW( L"test", NULL, L"", + UnicodeBuffer, + sizeof( UnicodeBuffer ), + L".\\test.ini" + ); + + + if (!SetCurrentDirectoryA( ".." )) { + printf( "TEST: SetCurrentDirectory to '..' failed (%u)\n", GetLastError() ); + } + + WriteProfileString( L"fonts", L"FooBar", L"2" ); + + WriteProfileString( L"fonts", L"Rockwell Italic (TrueType)", L"ROCKI.FOT" ); + + if (!SetCurrentDirectoryW( L"test" )) { + printf( "TEST: SetCurrentDirectory to 'test' failed (%u)\n", GetLastError() ); + } + + WritePrivateProfileStringA( "test", "test1", "-1", ".\\test.ini" ); + + WritePrivateProfileStringW( L"test", L"test1", L"-3", L".\\test.ini" ); + + WritePrivateProfileSectionA( "test1", "test0=0\0test1=1\0test2=2\0", ".\\test.ini" ); + + WritePrivateProfileSectionW( L"test2", L"test0=0\0test1=2\0test2=2\0", L".\\test.ini" ); + + return 0; +} diff --git a/private/sdktools/instaler/testins2.rc b/private/sdktools/instaler/testins2.rc new file mode 100644 index 000000000..75c36422f --- /dev/null +++ b/private/sdktools/instaler/testins2.rc @@ -0,0 +1,12 @@ +#include "instaler.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Instaler Test Program" +#define VER_INTERNALNAME_STR "TESTINST\0" +#define VER_ORIGINALFILENAME_STR "TESTINST.EXE" + +#include "common.ver" + +RCINCLUDE errormsg.rc diff --git a/private/sdktools/instaler/undoinst.c b/private/sdktools/instaler/undoinst.c new file mode 100644 index 000000000..30e8ace5a --- /dev/null +++ b/private/sdktools/instaler/undoinst.c @@ -0,0 +1,831 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + undoinst.c + +Abstract: + + This program undoes the actions described by an Installation Modification Log file + created by the INSTALER program + +Author: + + Steve Wood (stevewo) 15-Jan-1996 + +Revision History: + +--*/ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> + +#include "instutil.h" +#include "iml.h" + +BOOLEAN RedoScript; +BOOLEAN VerboseOutput; + +int +ProcessUndoIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PINSTALLATION_MODIFICATION_LOGFILE pImlRedo + ); + +int +_CRTAPI1 +main( + int argc, + char *argv[] + ) +{ + int Result; + char *s; + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo; + PINSTALLATION_MODIFICATION_LOGFILE pImlRedo; + USHORT RedoScriptId; + + InitCommonCode( "UNDOINST", + "[-r] [-v]", + "-r replace contents of input .IML file with redo script to undo the undo\n" + "-v verbose output\n" + ); + RedoScript = FALSE; + VerboseOutput = FALSE; + while (--argc) { + s = *++argv; + if (*s == '-' || *s == '/') { + while (*++s) { + switch( tolower( *s ) ) { + case 'r': + RedoScript = TRUE; + break; + case 'v': + VerboseOutput = TRUE; + break; + default: + CommonSwitchProcessing( &argc, &argv, *s ); + break; + } + } + } + else + if (!CommonArgProcessing( &argc, &argv )) { + Usage( "Arguments not supported - '%s'", (ULONG)s ); + } + } + + if (ImlPath == NULL) { + Usage( "Must specify an installation name as first argument", 0 ); + } + + if (!SetCurrentDirectory( InstalerDirectory )) { + FatalError( "Unable to change to '%ws' directory (%u)", + (ULONG)InstalerDirectory, + GetLastError() + ); + } + + pImlUndo = LoadIml( ImlPath ); + if (pImlUndo == NULL) { + FatalError( "Unable to open '%ws' (%u)", + (ULONG)ImlPath, + GetLastError() + ); + } + if (RedoScript) { + RedoScriptId = 0; + if (CreateBackupFileName( &RedoScriptId ) == NULL) { + FatalError( "Unable to create temporary file for redo script (%u)\n", + GetLastError(), + 0 + ); + } + + pImlRedo = CreateIml( FormatTempFileName( InstalerDirectory, &RedoScriptId ), TRUE ); + if (pImlRedo == NULL) { + FatalError( "Unable to create redo script '%ws' (%u)\n", + (ULONG)FormatTempFileName( InstalerDirectory, &RedoScriptId ), + GetLastError() + ); + } + } + else { + pImlRedo = NULL; + } + + Result = ProcessUndoIml( pImlUndo, pImlRedo ); + + CloseIml( pImlUndo ); + if (pImlRedo != NULL) { + CloseIml( pImlRedo ); + if (!MoveFileEx( FormatTempFileName( InstalerDirectory, &RedoScriptId ), + ImlPath, + MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED + ) + ) { + FatalError( "Unable to rename redo script '%ws' (%u)\n", + (ULONG)FormatTempFileName( InstalerDirectory, &RedoScriptId ), + GetLastError() + ); + } + } + + exit( Result ); + return Result; +} + + +BOOLEAN +DeleteFileOrDirectory( + PWSTR Name + ) +{ + DWORD FileAttributes; + + FileAttributes = GetFileAttributes( Name ); + if (FileAttributes == 0xFFFFFFFF) { + return TRUE; + } + + if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + return RemoveDirectory( Name ); + } + else { + return DeleteFile( Name ); + } +} + +BOOLEAN +ProcessUndoFileIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PIML_FILE_RECORD pFile + ) +{ + PIML_FILE_RECORD_CONTENTS pOldFile; + PIML_FILE_RECORD_CONTENTS pNewFile; + USHORT UniqueId = 0; + HANDLE FileHandle; + PWSTR BackupFileName; + DWORD FileAttributes; + DWORD BytesWritten; + + pOldFile = MP( PIML_FILE_RECORD_CONTENTS, pImlUndo, pFile->OldFile ); + pNewFile = MP( PIML_FILE_RECORD_CONTENTS, pImlUndo, pFile->NewFile ); + printf( " %ws - ", MP( PWSTR, pImlUndo, pFile->Name ) ); + switch( pFile->Action ) { + case CreateNewFile: + printf( "deleting" ); + SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ), + FILE_ATTRIBUTE_NORMAL + ); + if (!DeleteFileOrDirectory( MP( PWSTR, pImlUndo, pFile->Name ) )) { + printf( " - error (%u)", GetLastError() ); + } + printf( "\n" ); + break; + + case ModifyOldFile: + case DeleteOldFile: + FileAttributes = GetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ) ); + printf( "restoring old file" ); + if (FileAttributes != 0xFFFFFFFF) { + SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ), + FILE_ATTRIBUTE_NORMAL + ); + BackupFileName = CreateBackupFileName( &UniqueId ); + if (BackupFileName == NULL) { + printf( " - unable to find temporary name for restore\n" ); + break; + } + else + if (!MoveFile( MP( PWSTR, pImlUndo, pFile->Name ), + BackupFileName + ) + ) { + printf( " - unable to rename existing to temporary name (%u)\n", + GetLastError() + ); + break; + } + } + else { + BackupFileName = NULL; + } + + if (pOldFile != NULL) { + if (pOldFile->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (!CreateDirectory( MP( PWSTR, pImlUndo, pFile->Name ), NULL )) { + printf( " - unable to create directory (%u)", + GetLastError() + ); + } + } + else { + FileHandle = CreateFile( MP( PWSTR, pImlUndo, pFile->Name ), + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_NEW, + 0, + NULL + ); + if (FileHandle != INVALID_HANDLE_VALUE) { + if (WriteFile( FileHandle, + MP( PVOID, pImlUndo, pOldFile->Contents ), + pOldFile->FileSize, + &BytesWritten, + NULL + ) && + BytesWritten == pOldFile->FileSize + ) { + if (!SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ), + pOldFile->FileAttributes + ) + ) { + printf( " - unable to restore attributes (%u)", + GetLastError() + ); + } + else + if (!SetFileTime( FileHandle, + &pOldFile->LastWriteTime, + &pOldFile->LastWriteTime, + &pOldFile->LastWriteTime + ) + ) { + printf( " - unable to restore last write time (%u)", + GetLastError() + ); + } + else + if (BackupFileName != NULL) { + DeleteFile( BackupFileName ); + BackupFileName = NULL; + } + } + else { + printf( " - unable to restore contents (%u)", + GetLastError() + ); + } + + CloseHandle( FileHandle ); + } + else { + printf( " - unable to create file (%u)", + GetLastError() + ); + } + } + } + else { + printf( " - old contents missing from .IML file" ); + } + + if (BackupFileName != NULL) { + DeleteFile( MP( PWSTR, pImlUndo, pFile->Name ) ); + MoveFile( BackupFileName, MP( PWSTR, pImlUndo, pFile->Name ) ); + } + printf( "\n" ); + break; + + case ModifyFileDateTime: + printf( "restoring date/time\n" ); + FileHandle = CreateFile( MP( PWSTR, pImlUndo, pFile->Name ), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (FileHandle != INVALID_HANDLE_VALUE) { + if (!SetFileTime( FileHandle, + &pOldFile->LastWriteTime, + &pOldFile->LastWriteTime, + &pOldFile->LastWriteTime + ) + ) { + printf( " - unable to restore last write time (%u)", + GetLastError() + ); + } + + CloseHandle( FileHandle ); + } + else { + printf( " - unable to open file (%u)", + GetLastError() + ); + } + break; + + case ModifyFileAttributes: + printf( "restoring attributes" ); + if (!SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ), + pOldFile->FileAttributes + ) + ) { + printf( " - unable to restore attributes (%u)", + GetLastError() + ); + } + printf( "\n" ); + break; + } + + return TRUE; +} + + +BOOLEAN +ProcessRedoFileIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PIML_FILE_RECORD pFile, + PINSTALLATION_MODIFICATION_LOGFILE pImlRedo + ) +{ + HANDLE FindHandle; + WIN32_FIND_DATA FindFileData; + + if (pFile->Action == CreateNewFile) { + // + // Created a new file. So do the same in the redo + // script, with the existing contents of the new file + // + ImlAddFileRecord( pImlRedo, + CreateNewFile, + MP( PWSTR, pImlUndo, pFile->Name ), + NULL, + NULL, + 0 + ); + } + else + if (pFile->Action == ModifyOldFile) { + // + // Modified an existing file. Create a similar record + // in the redo script that will hold the new contents + // + ImlAddFileRecord( pImlRedo, + ModifyOldFile, + MP( PWSTR, pImlUndo, pFile->Name ), + NULL, + NULL, + 0 + ); + } + else { + // + // Modified the file attributes and/or date and time. Get the current + // values and save them in the redo script + // + FindHandle = FindFirstFile( MP( PWSTR, pImlUndo, pFile->Name ), + &FindFileData + ); + if (FindHandle != INVALID_HANDLE_VALUE) { + ImlAddFileRecord( pImlRedo, + ModifyFileDateTime, + MP( PWSTR, pImlUndo, pFile->Name ), + NULL, + &FindFileData.ftLastWriteTime, + FindFileData.dwFileAttributes + ); + FindClose( FindHandle ); + } + } + + return TRUE; +} + + +BOOLEAN +ProcessUndoKeyIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PIML_KEY_RECORD pKey + ) +{ + PIML_VALUE_RECORD pValue; + PIML_VALUE_RECORD_CONTENTS pOldValue; + PIML_VALUE_RECORD_CONTENTS pNewValue; + NTSTATUS Status; + UNICODE_STRING KeyName; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE KeyHandle; + UNICODE_STRING ValueName; + + KeyHandle = NULL; + if (pKey->Values != 0 || pKey->Action == CreateNewKey) { + printf( " %ws - ", MP( PWSTR, pImlUndo, pKey->Name ) ); + RtlInitUnicodeString( &KeyName, MP( PWSTR, pImlUndo, pKey->Name ) ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + if (pKey->Action != DeleteOldKey) { + if (pKey->Action == CreateNewKey) { + printf( "deleting" ); + } + else { + printf( "modifying" ); + } + Status = NtOpenKey( &KeyHandle, DELETE | GENERIC_WRITE, &ObjectAttributes ); + } + else { + printf( "creating" ); + Status = NtCreateKey( &KeyHandle, + GENERIC_WRITE, + &ObjectAttributes, + 0, + NULL, + 0, + NULL + ); + } + + if (!NT_SUCCESS( Status )) { + KeyHandle = NULL; + printf( " - failed (0x%08x)", Status ); + } + printf( "\n" ); + + if (KeyHandle != NULL) { + pValue = MP( PIML_VALUE_RECORD, pImlUndo, pKey->Values ); + while (pValue != NULL) { + pOldValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->OldValue ); + pNewValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->NewValue ); + printf( " %ws - ", MP( PWSTR, pImlUndo, pValue->Name ) ); + RtlInitUnicodeString( &ValueName, + MP( PWSTR, pImlUndo, pValue->Name ) + ); + if (pValue->Action == CreateNewValue) { + printf( "deleting" ); + Status = NtDeleteValueKey( KeyHandle, &ValueName ); + } + else { + if (pValue->Action == DeleteOldValue) { + printf( "creating" ); + } + else { + printf( "restoring" ); + } + + Status = NtSetValueKey( KeyHandle, + &ValueName, + 0, + pOldValue->Type, + MP( PWSTR, pImlUndo, pOldValue->Data ), + pOldValue->Length + ); + } + + if (!NT_SUCCESS( Status )) { + printf( " - failed (0x%08x)", Status ); + } + printf( "\n" ); + + pValue = MP( PIML_VALUE_RECORD, pImlUndo, pValue->Next ); + } + } + } + + if (KeyHandle != NULL) { + if (pKey->Action == CreateNewKey) { + Status = NtDeleteKey( KeyHandle ); + if (!NT_SUCCESS( Status )) { + printf( " *** delete of above key failed (0x%08x)", Status ); + } + } + NtClose( KeyHandle ); + } + + return TRUE; +} + + +BOOLEAN +ProcessRedoKeyIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PIML_KEY_RECORD pKey, + PINSTALLATION_MODIFICATION_LOGFILE pImlRedo + ) +{ + PIML_VALUE_RECORD pValue; + PIML_VALUE_RECORD_CONTENTS pOldValue; + PIML_VALUE_RECORD_CONTENTS pNewValue; + POFFSET Values; + + Values = 0; + if ((pKey->Values != 0 || pKey->Action == CreateNewKey) && + pKey->Action != DeleteOldKey + ) { + // + // Created or modified an existing key and/or values. + // + pValue = MP( PIML_VALUE_RECORD, pImlUndo, pKey->Values ); + while (pValue != NULL) { + pOldValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->OldValue ); + pNewValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->NewValue ); + if (pValue->Action == CreateNewValue) { + if (pNewValue != NULL) { + ImlAddValueRecord( pImlRedo, + pValue->Action, + MP( PWSTR, pImlUndo, pValue->Name ), + pNewValue->Type, + pNewValue->Length, + MP( PWSTR, pImlUndo, pNewValue->Data ), + 0, + 0, + NULL, + &Values + ); + } + } + else + if (pValue->Action == ModifyOldValue) { + if (pOldValue != NULL && pNewValue != NULL) { + ImlAddValueRecord( pImlRedo, + pValue->Action, + MP( PWSTR, pImlUndo, pValue->Name ), + pNewValue->Type, + pNewValue->Length, + MP( PWSTR, pImlUndo, pNewValue->Data ), + pOldValue->Type, + pOldValue->Length, + MP( PWSTR, pImlUndo, pOldValue->Data ), + &Values + ); + } + } + else + if (pValue->Action == DeleteOldValue) { + if (pOldValue != NULL) { + ImlAddValueRecord( pImlRedo, + pValue->Action, + MP( PWSTR, pImlUndo, pValue->Name ), + 0, + 0, + NULL, + pOldValue->Type, + pOldValue->Length, + MP( PWSTR, pImlUndo, pOldValue->Data ), + &Values + ); + } + } + + pValue = MP( PIML_VALUE_RECORD, pImlUndo, pValue->Next ); + } + } + + ImlAddKeyRecord( pImlRedo, + pKey->Action, + MP( PWSTR, pImlUndo, pKey->Name ), + Values + ); + return TRUE; +} + +BOOLEAN +ProcessUndoIniIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PIML_INI_RECORD pIni + ) +{ + PIML_INISECTION_RECORD pSection; + PIML_INIVARIABLE_RECORD pVariable; + HANDLE FileHandle; + BOOLEAN FileNameShown; + BOOLEAN SectionNameShown; + + FileNameShown = FALSE; + pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pIni->Sections ); + while (pSection != NULL) { + SectionNameShown = FALSE; + pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pSection->Variables ); + while (pVariable != NULL) { + if (!FileNameShown) { + printf( "%ws\n", MP( PWSTR, pImlUndo, pIni->Name ) ); + FileNameShown = TRUE; + } + + if (!SectionNameShown) { + printf( " [%ws]", MP( PWSTR, pImlUndo, pSection->Name ) ); + if (pSection->Action == DeleteOldSection) { + printf( " - deleting" ); + } + printf( "\n" ); + SectionNameShown = TRUE; + } + + printf( " %ws = ", MP( PWSTR, pImlUndo, pVariable->Name ) ); + if (pVariable->Action == CreateNewVariable) { + printf( "deleting" ); + if (!WritePrivateProfileString( MP( PWSTR, pImlUndo, pSection->Name ), + MP( PWSTR, pImlUndo, pVariable->Name ), + NULL, + MP( PWSTR, pImlUndo, pIni->Name ) + ) + ) { + printf( " - failed (%u)", GetLastError() ); + } + printf( "\n" ); + } + else { + printf( "restoring" ); + if (!WritePrivateProfileString( MP( PWSTR, pImlUndo, pSection->Name ), + MP( PWSTR, pImlUndo, pVariable->Name ), + MP( PWSTR, pImlUndo, pVariable->OldValue ), + MP( PWSTR, pImlUndo, pIni->Name ) + ) + ) { + printf( " - failed (%u)", GetLastError() ); + } + printf( "\n" ); + } + + pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pVariable->Next ); + } + + if (pSection->Action == CreateNewSection) { + if (!FileNameShown) { + printf( "%ws\n", MP( PWSTR, pImlUndo, pIni->Name ) ); + FileNameShown = TRUE; + } + + if (!SectionNameShown) { + printf( " [%ws]", MP( PWSTR, pImlUndo, pSection->Name ) ); + if (pSection->Action == CreateNewSection) { + printf( " - deleting" ); + } + SectionNameShown = TRUE; + printf( "\n" ); + } + + if (!WritePrivateProfileSection( MP( PWSTR, pImlUndo, pSection->Name ), + NULL, + MP( PWSTR, pImlUndo, pIni->Name ) + ) + ) { + printf( " *** delete of above section name failed (%u)\n", + GetLastError() + ); + } + } + + pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pSection->Next ); + } + + if (pIni->Action == CreateNewIniFile) { + printf( "%ws - deleting", MP( PWSTR, pImlUndo, pIni->Name ) ); + if (!DeleteFile( MP( PWSTR, pImlUndo, pIni->Name ) )) { + printf( " - failed (%u)", GetLastError() ); + } + printf( "\n" ); + FileNameShown = TRUE; + } + else { + FileHandle = CreateFile( MP( PWSTR, pImlUndo, pIni->Name ), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (FileHandle != INVALID_HANDLE_VALUE) { + SetFileTime( FileHandle, + &pIni->LastWriteTime, + &pIni->LastWriteTime, + &pIni->LastWriteTime + ); + CloseHandle( FileHandle ); + } + } + + if (FileNameShown) { + printf( "\n" ); + } + return TRUE; +} + + +BOOLEAN +ProcessRedoIniIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PIML_INI_RECORD pIni, + PINSTALLATION_MODIFICATION_LOGFILE pImlRedo + ) +{ + PIML_INISECTION_RECORD pSection; + PIML_INIVARIABLE_RECORD pVariable; + POFFSET Variables, Sections; + + pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pIni->Sections ); + Sections = 0; + while (pSection != NULL) { + pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pSection->Variables ); + Variables = 0; + while (pVariable != NULL) { + ImlAddIniVariableRecord( pImlRedo, + pVariable->Action, + MP( PWSTR, pImlUndo, pVariable->Name ), + MP( PWSTR, pImlUndo, pVariable->OldValue ), + MP( PWSTR, pImlUndo, pVariable->NewValue ), + &Variables + ); + + pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pVariable->Next ); + } + + if (Variables != 0) { + ImlAddIniSectionRecord( pImlRedo, + pSection->Action, + MP( PWSTR, pImlUndo, pSection->Name ), + Variables, + &Sections + ); + } + + pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pSection->Next ); + } + + if (Sections != 0) { + ImlAddIniRecord( pImlRedo, + pIni->Action, + MP( PWSTR, pImlUndo, pIni->Name ), + &pIni->LastWriteTime, + Sections + ); + } + + return TRUE; +} + + +int +ProcessUndoIml( + PINSTALLATION_MODIFICATION_LOGFILE pImlUndo, + PINSTALLATION_MODIFICATION_LOGFILE pImlRedo + ) +{ + PIML_FILE_RECORD pFile; + PIML_KEY_RECORD pKey; + PIML_INI_RECORD pIni; + + if (pImlUndo->NumberOfFileRecords > 0) { + printf( "Undoing File Modifications:\n" ); + pFile = MP( PIML_FILE_RECORD, pImlUndo, pImlUndo->FileRecords ); + while (pFile != NULL) { + if (pFile->Name != 0) { + if (pImlRedo != NULL) { + ProcessRedoFileIml( pImlUndo, pFile, pImlRedo ); + } + + ProcessUndoFileIml( pImlUndo, pFile ); + } + + pFile = MP( PIML_FILE_RECORD, pImlUndo, pFile->Next ); + } + + printf( "\n" ); + } + + if (pImlUndo->NumberOfKeyRecords > 0) { + printf( "Undoing Registry Modifications:\n" ); + pKey = MP( PIML_KEY_RECORD, pImlUndo, pImlUndo->KeyRecords ); + while (pKey != NULL) { + if (pImlRedo != NULL) { + ProcessRedoKeyIml( pImlUndo, pKey, pImlRedo ); + } + + ProcessUndoKeyIml( pImlUndo, pKey ); + + pKey = MP( PIML_KEY_RECORD, pImlUndo, pKey->Next ); + } + + printf( "\n" ); + } + + if (pImlUndo->NumberOfIniRecords > 0) { + printf( "Undoing .INI File modifications:\n" ); + pIni = MP( PIML_INI_RECORD, pImlUndo, pImlUndo->IniRecords ); + while (pIni != NULL) { + if (pImlRedo != NULL) { + ProcessRedoIniIml( pImlUndo, pIni, pImlRedo ); + } + + ProcessUndoIniIml( pImlUndo, pIni); + + pIni = MP( PIML_INI_RECORD, pImlUndo, pIni->Next ); + } + } + + return 0; +} diff --git a/private/sdktools/instaler/undoinst.rc b/private/sdktools/instaler/undoinst.rc new file mode 100644 index 000000000..61608cfe0 --- /dev/null +++ b/private/sdktools/instaler/undoinst.rc @@ -0,0 +1,12 @@ +#include "instaler.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Instaler Undo Program" +#define VER_INTERNALNAME_STR "UNDOINST\0" +#define VER_ORIGINALFILENAME_STR "UNDOINST.EXE" + +#include "common.ver" + +RCINCLUDE errormsg.rc |