|
|
#include <iostream.h>
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <tchar.h>
#include <wchar.h>
#include "CheckINF.h"
#include "hcttools.h"
#include "logutils.h"
// The master INF is opened first
// Then all the infs that are pointed to in the master are opened
// Then all the infs that are pointed to in the subcomp infs are opened
// All these things make a big open INF file
// bunch of section names
const PTSTR tszOptionalComponents = TEXT("Optional Components"); const PTSTR tszComponents = TEXT("Components"); const PTSTR tszLayoutFile = TEXT("LayoutFile"); const PTSTR tszIconIndex = TEXT("IconIndex");
/*++
Routine description: Check the validity of a set of INF files used by OC Manager Argument: Standard main argument Return Value: None --*/
VOID __cdecl main(INT argc, TCHAR *argv[]) { TCHAR tszMsg[MaxStringSize];
const PTSTR tszFunctionName = TEXT("main");
if (argc < 2) { _stprintf(tszMsg, TEXT("Correct Usage: %s INFFileNameToCheck [/l] [/m]"), argv[0]);
MessageBox(NULL, tszMsg, TEXT("Incorrect argument"), MB_ICONERROR | MB_OK);
return; }
g_bUseLog = FALSE; g_bUseMsgBox = FALSE; g_bUseConsole = TRUE; g_bMasterInf = TRUE;
// Parse the argument and set global variables
for (INT i = 1; i < argc; i++) { if (_tcscmp(argv[i], TEXT("/m")) == 0 || _tcscmp(argv[i], TEXT("/M")) == 0 || _tcscmp(argv[i], TEXT("-m")) == 0 || _tcscmp(argv[i], TEXT("-M")) == 0 ) {
g_bUseMsgBox = TRUE; } if (_tcscmp(argv[i], TEXT("/l")) == 0 || _tcscmp(argv[i], TEXT("/L")) == 0 || _tcscmp(argv[i], TEXT("-l")) == 0 || _tcscmp(argv[i], TEXT("-L")) == 0 ) {
g_bUseLog = TRUE; } }
// we will see if there is any path seperator in the filename
// if there is, we assume it is the full path
// if there is not, we assume it is in the current directory
PTSTR tszFilename = argv[1];
while (*tszFilename) { if (*tszFilename == TEXT('\\')) { break; } tszFilename++; }
// Let's initialize the log
if (g_bUseLog) { InitLog(TEXT("checkinf.log"), TEXT("Inf File Check Log"), TRUE); }
TCHAR tszDir[MaxStringSize];
if (!*tszFilename) { // Get the currect path
GetCurrentDirectory(MaxBufferSize, tszDir);
if (tszDir[_tcslen(tszDir)-1] != TEXT('\\')) { tszDir[_tcslen(tszDir)+1] = 0; tszDir[_tcslen(tszDir)] = TEXT('\\'); }
CheckINF(tszDir, argv[1]); }
else { CheckINF(NULL, argv[1]); }
if (g_bUseLog) { ExitLog(); }
return; }
/*++
Routine description: Check the validity of an INF file Argument: TCHAR *tszDir : Where the Inf files are TCHAR *tszFilename : file name of the inf file to check Return value: FALSE means there is something wrong TRUE means everything going well --*/
BOOL CheckINF(IN TCHAR *tszDir, IN TCHAR *tszFilename) { UINT uiError; HINF hinfHandle;
TCHAR tszMsg[256];
TCHAR tszSubINFName[256][MaxStringSize]; UINT uiNumComponents;
INFCONTEXT infContext;
BOOL bSuccess;
const PTSTR tszFunctionName = TEXT("CheckINF");
// Open the INF Files
if (tszDir && *tszDir) { _stprintf(tszMsg, TEXT("%s%s"), tszDir, tszFilename); hinfHandle = SetupOpenInfFile(tszMsg, NULL, INF_STYLE_WIN4, &uiError); }
else { hinfHandle = SetupOpenInfFile(tszFilename, NULL, INF_STYLE_WIN4, &uiError); }
if (hinfHandle == INVALID_HANDLE_VALUE) { // If the openning failed, try the system default path
if (!tszDir) { hinfHandle = SetupOpenInfFile(tszFilename, NULL, INF_STYLE_WIN4, &uiError); if (hinfHandle != INVALID_HANDLE_VALUE) { LogError(TEXT("File openned in system path"), INFO, tszFunctionName); } } if (hinfHandle == INVALID_HANDLE_VALUE) { _stprintf(tszMsg, TEXT("Error opeing INF file %s"), tszFilename);
MessageBox(NULL, tszMsg, tszFunctionName, MB_OK); return FALSE; } }
_stprintf(tszMsg, TEXT("%s opened"), tszFilename); LogError(tszMsg, INFO, tszFunctionName);
bSuccess = SetupFindFirstLine(hinfHandle, tszComponents, NULL, &infContext);
if (!bSuccess) { // This is not a master inf file
g_bMasterInf = FALSE; LogError(TEXT("[Components] section not found."), INFO, tszFunctionName); }
else {
// in the [Components] section, get all the INF file names
// and using SetupOpenAppendFile to append to the current handle
uiNumComponents = SetupGetLineCount(hinfHandle, tszComponents);
if (uiNumComponents < 1) {
LogError(TEXT("Too few components in the [Components] section"), SEV2, tszFunctionName);
return TRUE; }
for (UINT i = 0; i < uiNumComponents; i++) { UINT uiNumFieldCount;
uiNumFieldCount = SetupGetFieldCount(&infContext);
if (uiNumFieldCount < 3) { tszSubINFName[i][0] = 0; SetupFindNextLine(&infContext, &infContext);
continue; }
SetupGetStringField(&infContext, 3, tszSubINFName[i], MaxBufferSize, NULL);
SetupFindNextLine(&infContext, &infContext); }
// It is assumed that the master INF doesn't contain path
for (UINT j = 0; j < uiNumComponents; j++) { if (tszSubINFName[j][0]) { _stprintf(tszMsg, TEXT("%s%s"), tszDir, tszSubINFName[j]);
bSuccess = SetupOpenAppendInfFile(tszMsg, hinfHandle, NULL);
if (!bSuccess) { _stprintf(tszMsg, TEXT("Error opening %s"), tszMsg); LogError(tszMsg, SEV2, tszFunctionName); }
else { _stprintf(tszMsg, TEXT("%s opened"), tszMsg); LogError(tszMsg, INFO, tszFunctionName);
} } } }
// Now the file is opened
ComponentList clList;
FillList(hinfHandle, &clList, tszDir);
CheckIconIndex(hinfHandle, &clList);
CheckNeedRelationship(&clList);
CheckExcludeRelationship(&clList);
CheckParentRelationship(&clList);
CheckCopyFiles(hinfHandle, &clList);
CheckSuspicious(hinfHandle, &clList);
CheckSameId(&clList);
CheckDescription(hinfHandle, &clList);
CheckModes(hinfHandle, &clList);
SetupCloseInfFile(hinfHandle);
if (g_bMasterInf) { CheckLayoutFile(tszSubINFName, uiNumComponents, tszDir); } else{ _tcscpy(tszSubINFName[0], tszFilename); CheckLayoutFile(tszSubINFName, 1, tszDir);
}
return TRUE;
}
/*++
Routine Description: This routine creates the component list and fill the relation list of each component on the list Argument: HINF hinfHandle : a handle to the Inf file Component *pclList : a pointer to the component list TCHAR *tszDir : current working directory Return Value: The return value is not used --*/ BOOL FillList(IN OUT HINF hinfHandle, IN OUT ComponentList *pclList, IN TCHAR *tszDir) { INFCONTEXT infContext; BOOL bSuccess;
UINT uiNumComponents;
TCHAR tszMsg[MaxStringSize];
const PTSTR tszFunctionName = TEXT("FillList");
bSuccess = SetupFindFirstLine(hinfHandle, tszOptionalComponents, NULL, &infContext);
if (!bSuccess) { LogError(TEXT("There is no [Optional Components] section"), SEV2, tszFunctionName);
return FALSE; }
// Get the number of components in this INF file
uiNumComponents = SetupGetLineCount(hinfHandle, tszOptionalComponents);
if (uiNumComponents <= 0) { LogError(TEXT("There is no optional component"), SEV2, tszFunctionName);
return FALSE; }
// Build a array of all the component names listed
TCHAR Components[256][MaxStringSize];
UINT count = 0; for (UINT l = 0; l < uiNumComponents; l++) { bSuccess = SetupGetStringField(&infContext, 0, Components[count], MaxBufferSize, NULL); if (bSuccess) { SetupFindNextLine(&infContext, &infContext); count++; } else { LogError(TEXT("Error getting component name"), SEV2, tszFunctionName); return TRUE; } }
// For each component listed here
// There should be a section with the same name
// otherwise there is an error
Component *pcNewComponent;
for (UINT i = 0; i < uiNumComponents; i++) {
bSuccess = SetupFindFirstLine(hinfHandle, Components[i], NULL, &infContext);
if (!bSuccess) { _stprintf(tszMsg, TEXT("Can't find the section [%s]"), Components[i]);
LogError(tszMsg, SEV2, tszFunctionName);
return FALSE; }
// add the component to the list
pcNewComponent = pclList->AddComponent(Components[i]);
// Figure out the parent id from the INF File
pcNewComponent->GetParentIdFromINF(hinfHandle);
}
// Now go through the list and fill the prlChildrenList
// of each component
Component *pcComponent;
pclList->ResetList();
while (!pclList->Done()) {
pcComponent = pclList->GetNext(); pcComponent->BuildChildrenList(pclList); }
// Now go through the INF for a second time
// This time the need and exclude relationlist is filled
TCHAR tszId[MaxStringSize];
for (UINT k = 0; k < uiNumComponents; k++) {
bSuccess = SetupFindFirstLine(hinfHandle, Components[k], NULL, &infContext);
if (!bSuccess) { _stprintf(tszMsg, TEXT("Can't find the section [%s]"), Components[k]);
LogError(tszMsg, SEV2, tszFunctionName);
return TRUE; }
// Get the needs= line
bSuccess = SetupFindFirstLine(hinfHandle, Components[k], TEXT("Needs"), &infContext);
if (bSuccess) { UINT uiNumNeeds = SetupGetFieldCount(&infContext);
if (uiNumNeeds == 0) { _stprintf(tszMsg, TEXT("Too few field for the Needs key in [%s]"), Components[k]);
LogError(tszMsg, SEV2, tszFunctionName); }
for (UINT j = 1; j <= uiNumNeeds; j++) { SetupGetStringField(&infContext, j, tszId, MaxBufferSize, NULL);
Component *pcTemp = pclList->LookupComponent(Components[k]);
if (!pcTemp) { // Can't find Components[k]
// This can only happen if there is something wrong
// in the code
LogError(TEXT("Something wrong in the code"), SEV2, tszFunctionName);
return TRUE; }
else { pcTemp->GetNeedList()->AddRelation(tszId); } } }
// Get the exclude
bSuccess = SetupFindFirstLine(hinfHandle, Components[k], TEXT("Exclude"), &infContext);
if (bSuccess) { UINT uiNumExcludes = SetupGetFieldCount(&infContext);
if (uiNumExcludes == 0) { _stprintf(tszMsg, TEXT("Too few field for Exclude= in section [%s]"), Components[k]);
LogError(tszMsg, SEV2, tszFunctionName);
}
for (UINT l = 1; l <= uiNumExcludes; l++) { SetupGetStringField(&infContext, l, tszId, MaxBufferSize, NULL);
Component *pcTmp = NULL; pcTmp = pclList->LookupComponent(tszId);
if (!pcTmp) { _stprintf(tszMsg, TEXT("Unknown component %s in section [%s]"), tszId, Components[k]);
LogError(tszMsg, SEV2, tszFunctionName); } else { pcTmp->GetExcludeList()->AddRelation(Components[k]); pcTmp = pclList->LookupComponent(Components[k]); pcTmp->GetExcludeList()->AddRelation(tszId); } } } }
return TRUE; }
/*++
Routine Description: Routine to check the IconIndex key of each component Argument: HINF hinfHandle : A handle to the Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckIconIndex(IN HINF hinfHandle, IN ComponentList *pclList) { // Go through each of the component in the list
PTSTR tszId;
TCHAR tszMsg[MaxStringSize];
BOOL bSuccess;
INFCONTEXT infContext;
INT nIconIndex;
TCHAR tszTemp[MaxStringSize];
const PTSTR tszFunctionName = TEXT("CheckIconIndex");
pclList->ResetList();
while (!pclList->Done()) { tszId = pclList->GetNext()->GetComponentId();
bSuccess = SetupFindFirstLine(hinfHandle, tszId, tszIconIndex, &infContext); if (!bSuccess) { _stprintf(tszMsg, TEXT("IconIndex not present for component %s"), tszId);
LogError(tszMsg, SEV2, tszFunctionName); continue; }
UINT uiNumField = SetupGetFieldCount(&infContext);
if (uiNumField < 1) { _stprintf(tszMsg, TEXT("%s has less than 2 fields for component %s"), tszIconIndex, tszId); LogError(tszMsg, SEV2, tszFunctionName);
}
else if (uiNumField > 1) { _stprintf(tszMsg, TEXT("%s has more than 2 fields for component %s"), tszIconIndex, tszId); LogError(tszMsg, SEV2, tszFunctionName); } else { bSuccess = SetupGetIntField(&infContext, 1, &nIconIndex); if (bSuccess) { // Check the range of the iconindex returned
if (nIconIndex < 0 || nIconIndex > 66) { _stprintf(tszMsg, TEXT("Invalid icon index %d for component %s"), nIconIndex, tszId); LogError(tszMsg, SEV2, tszFunctionName);
} else if (nIconIndex == 12 || nIconIndex == 13 || nIconIndex == 25) { _stprintf(tszMsg, TEXT("Component %s is using icon index %d"), tszId, nIconIndex); LogError(tszMsg, SEV2, tszFunctionName);
} } else { bSuccess = SetupGetStringField(&infContext, 1, tszTemp, MaxBufferSize, NULL);
if (!bSuccess) { _stprintf(tszMsg, TEXT("Error reading the value of %s in [%s]"), tszIconIndex, tszId); LogError(tszMsg, SEV2, tszFunctionName);
} else { if (_tcscmp(tszTemp, TEXT("*")) != 0 ) { _stprintf(tszMsg, TEXT("Invalid value of %s in [%s]"), tszIconIndex, tszId); LogError(tszMsg, SEV2, tszFunctionName);
} } } } }
return TRUE; }
/*++
Routine Description: Routine that checks the need relationship amond component Argument: ComponentList *pclList : A pointer to the list of component Return Value: The return value is not used --*/
BOOL CheckNeedRelationship(IN ComponentList *pclList) { Component *pcComponent;
TCHAR tszMsg[MaxStringSize];
BOOL bNonExist = FALSE;
const PTSTR tszFunctionName = TEXT("CheckNeedRelationship");
// First thing to check
// There should not be a component that needs
// a categorical component
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
if (pcComponent->IsParentOfOthers() && pcComponent->IsNeededByOthers(pclList)) {
_stprintf(tszMsg, TEXT("%s has subcomponent and is needed by others"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} }
// Second thing to check
// There should not be a categorical component
// that needs another component
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
if (pcComponent->IsParentOfOthers() && pcComponent->NeedOthers() != NULL) {
_stprintf(tszMsg, TEXT("%s has subcomponent, and needs another component"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} }
// Third thing to check
// There should not be Need and Exclude at the same time
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
if (pcComponent->NeedAndExcludeAtSameTime(pclList)) { _stprintf(tszMsg, TEXT("%s is needed and excluded by the same component"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} }
// Fouth thing to check
// Every component should need an existent component
// if the argument is a master inf file
Relation *prNeed;
if (g_bMasterInf) { pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
pcComponent->GetNeedList()->ResetList();
while (!pcComponent->GetNeedList()->Done()) {
prNeed = pcComponent->GetNeedList()->GetNext(); if (!pclList->LookupComponent(prNeed->GetComponentId())) { _stprintf(tszMsg, TEXT("%s needs %s, which is not in the list"), pcComponent->GetComponentId(), prNeed->GetComponentId());
LogError(tszMsg, SEV2, tszFunctionName);
bNonExist = TRUE; } } } }
// Fifth thing to check
// There should not be cycles
if (g_bMasterInf && !bNonExist) {
pclList->ResetList(); while (!pclList->Done()) { pcComponent = pclList->GetNext(); // Recursive calls to find the cycle
CheckNeedCycles(pcComponent, pclList); } }
return TRUE; }
/*++
Routine Description: Routine that checks the exclude relation among components Argument: ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckExcludeRelationship(IN ComponentList *pclList) { TCHAR tszMsg[MaxStringSize];
Component *pcComponent;
const PTSTR tszFunctionName = TEXT("CheckExcludeRelationship");
// Can't exclude a categorical component
// a categorical component can't exclude another component
pclList->ResetList();
while (!pclList->Done()) {
pcComponent = pclList->GetNext();
if (pcComponent->IsParentOfOthers() && pcComponent->IsExcludedByOthers(pclList)) {
_stprintf(tszMsg, TEXT("%s has subcomponent and is excluded by other componennts"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
}
if (pcComponent->IsParentOfOthers() && pcComponent->ExcludeOthers() != NULL) {
_stprintf(tszMsg, TEXT("%s has subcomponent and excludes other components"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
}
}
// Component should exclude an existent component
Relation *prExclude;
if (g_bMasterInf) { pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
pcComponent->GetExcludeList()->ResetList();
while (!pcComponent->GetExcludeList()->Done()) {
prExclude = pcComponent->GetExcludeList()->GetNext(); if (!pclList->LookupComponent(prExclude->GetComponentId())) { _stprintf(tszMsg, TEXT("%s excludes %s, which is not in the list"), pcComponent->GetComponentId(), prExclude->GetComponentId());
LogError(tszMsg, SEV2, tszFunctionName);
} } } }
return TRUE; }
/*++
Routine Description: Routine that checks the parent relationship among components Argument: ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckParentRelationship(IN ComponentList *pclList) { TCHAR tszMsg[MaxStringSize];
Component *pcComponent;
BOOL bNonExist = FALSE;
const PTSTR tszFunctionName = TEXT("CheckParentRelationship");
// The child should always be valid
// otherwise there is something seriously wrong in the code
// I will add this checking code in anyway
Relation *prChild;
if (g_bMasterInf) { pclList->ResetList(); while (!pclList->Done()) { pcComponent = pclList->GetNext(); pcComponent->GetChildrenList()->ResetList(); while (!pcComponent->GetChildrenList()->Done()) { prChild = pcComponent->GetChildrenList()->GetNext(); if (!pclList->LookupComponent(prChild->GetComponentId())) { _stprintf(tszMsg, TEXT("%s is parent of %s, which is not in the list"), pcComponent->GetComponentId(), prChild->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName); bNonExist = TRUE; } } } } // There should not be any cycles
if (!bNonExist && g_bMasterInf) {
pclList->ResetList(); while (!pclList->Done()) { pcComponent = pclList->GetNext(); CheckParentCycles(pcComponent, pclList); } }
return TRUE; }
/*++
Routine Description: Routine that makes sure categorical component doesn't have a CopyFiles key Argument: HINF hinfHandle : A handle to the open Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckCopyFiles(IN HINF hinfHandle, IN ComponentList *pclList) { Component *pcComponent = NULL;
BOOL bSuccess;
INFCONTEXT infContext;
TCHAR tszMsg[MaxStringSize];
const PTSTR tszFunctionName = TEXT("CheckCopyFiles");
// A categorical component can't have a [CopyFiles] section
pclList->ResetList();
while (!pclList->Done()) {
pcComponent = pclList->GetNext();
if (pcComponent->IsParentOfOthers()) {
bSuccess = SetupFindFirstLine(hinfHandle, pcComponent->GetComponentId(), TEXT("CopyFiles"), &infContext); if (bSuccess) { _stprintf(tszMsg, TEXT("%s has subcomponent, and has copyfiles section"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} } }
return TRUE;
}
/*++
Routine Description: Routine that checks for suspicious keys in the component section Argument: HINF hinfHandle : A handle to the open Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckSuspicious(IN HINF hinfHandle, IN ComponentList *pclList) { // A categorical component can't have any code
// associated with it, which includes add registry
// register services, etc.
// Go through all the component that has subcomponent
// read the lines in its section, looking for anything suspicious
INFCONTEXT infContext; BOOL bSuccess; Component *pcComponent;
TCHAR tszMsg[MaxStringSize];
UINT uiNumLineCount;
TCHAR tszTemp[MaxStringSize];
const PTSTR tszFunctionName = TEXT("CheckSuspicious");
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
if (pcComponent->IsParentOfOthers()) { // This component has children
bSuccess = SetupFindFirstLine(hinfHandle, pcComponent->GetComponentId(), NULL, &infContext); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to locate the component %s in Inf file"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} uiNumLineCount = SetupGetLineCount(hinfHandle, pcComponent->GetComponentId()); if (uiNumLineCount < 1) { _stprintf(tszMsg, TEXT("%s has too few lines in its section"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
}
for (UINT i = 0; i < uiNumLineCount; i++) { // Go through each line
// see if there is something we don't know
SetupGetStringField(&infContext, 0, tszTemp, MaxBufferSize, NULL);
// We only understand: OptionDesc, Tip, IconIndex,
// Parent, Needs, Excludes, SubCompInf, Modes
if (_tcscmp(tszTemp, TEXT("OptionDesc")) != 0 && _tcscmp(tszTemp, TEXT("Tip")) != 0 && _tcscmp(tszTemp, TEXT("IconIndex")) != 0 && _tcscmp(tszTemp, TEXT("Parent")) != 0 && _tcscmp(tszTemp, TEXT("SubCompInf")) != 0 && _tcscmp(tszTemp, TEXT("ExtraSetupFiles")) != 0) {
// Hit something we don't understand
_stprintf(tszMsg, TEXT("In section [%s], I don't understand key %s"), pcComponent->GetComponentId(), tszTemp); LogError(tszMsg, SEV2, tszFunctionName);
} SetupFindNextLine(&infContext, &infContext); } } } return TRUE;
}
/*++
Routine Description: Routine that checks if there is any need relation cycles among components (not implemented) Argument: Component *pcComponent : A pointer to the component to check ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckNeedCycles(IN Component *pcComponent, IN ComponentList *pclList) { const PTSTR tszFunctionName = TEXT("CheckNeedCycles");
// We can't change the value of pclList,
// or we will mess up the CheckNeedRelationship function
RelationList *prlStack = new RelationList();
RecursiveCheckNeedCycles(pcComponent, pclList, prlStack);
delete prlStack;
return TRUE;
}
/*++
Routine Description: Routine that is to be called recursively to determine if there is any cycles in the need relationship Argument: Component *pcComponent : A pointer to the component to check ComponentList *pclList : A pointer to the component list RelationList *prlStack : A list of nodes that have been visited Return Value: The return value is not used --*/
BOOL RecursiveCheckNeedCycles(IN Component *pcComponent, IN ComponentList *pclList, IN RelationList *prlStack) { Component *pcNeeded;
const PTSTR tszFunctionName = TEXT("RecursiveCheckNeedCycles");
Relation *prNeed = NULL;
TCHAR tszMsg[MaxStringSize];
pcComponent->GetNeedList()->ResetList();
while (!pcComponent->GetNeedList()->Done()) { prNeed = pcComponent->GetNeedList()->GetNext(); pcNeeded = pclList->LookupComponent(prNeed->GetComponentId());
if (!pcNeeded) { _stprintf(tszMsg, TEXT("%s needs component %s, which is not in the list"), pcComponent->GetComponentId(), prNeed->GetComponentId());
LogError(tszMsg, SEV2, tszFunctionName);
return TRUE; }
// if pcNeeded is already in the stack,
// state the error and returns
// Otherwise add pcNeeded to the stack,
// call CheckNeedCycles with pcNeeded and pclList
prlStack->ResetList();
while (!prlStack->Done()) { if (_tcscmp(prlStack->GetNext()->GetComponentId(), pcNeeded->GetComponentId()) == 0) {
_stprintf(tszMsg, TEXT("need relation cycle exists starting from %s"), pcNeeded->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName); return TRUE; } }
prlStack->AddRelation(pcNeeded->GetComponentId());
RecursiveCheckNeedCycles(pcNeeded, pclList, prlStack); }
// Before returning from this function
// pop out the node added into the stack
pcComponent->GetNeedList()->ResetList();
while (!pcComponent->GetNeedList()->Done()) { prNeed = pcComponent->GetNeedList()->GetNext(); prlStack->RemoveRelation(prNeed->GetComponentId()); }
return TRUE; }
/*++
Routine Description: Routine that checks if there is any parent relation cycles among components (not implemented) Argument: Component *pcComponent : A pointer to the component to check ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckParentCycles(IN Component *pcComponent, IN ComponentList *pclList) { const PTSTR tszFunctionName = TEXT("CheckParentCycles");
RelationList *prlStack = new RelationList();
RecursiveCheckParentCycles(pcComponent, pclList, prlStack);
delete prlStack;
return TRUE;
}
/*++
Routine Description: Routine that is to be called recursively to determine if there is any cycles in the parent relationship Argument: Component *pcComponent : A pointer to the component to check ComponentList *pclList : A pointer to the component list RelationList *prlStack : A list of nodes that have been visited Return Value: The return value is not used --*/
BOOL RecursiveCheckParentCycles(IN Component *pcComponent, IN ComponentList *pclList, IN RelationList *prlStack) {
Component *pcChild;
const PTSTR tszFunctionName = TEXT("RecursiveCheckParentCycles");
Relation *prChild = NULL;
TCHAR tszMsg[MaxStringSize];
pcComponent->GetChildrenList()->ResetList();
while (!pcComponent->GetChildrenList()->Done()) { prChild = pcComponent->GetChildrenList()->GetNext(); pcChild = pclList->LookupComponent(prChild->GetComponentId());
if (!pcChild) { _stprintf(tszMsg, TEXT("%s has component %s as child, which is not in the list"), pcComponent->GetComponentId(), prChild->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName); return TRUE; }
// if pcChild is already in the stack,
// state the error and returns
// Otherwise add pcChild to the stack,
// call CheckNeedCycles with pcNeeded and pclList
prlStack->ResetList();
while (!prlStack->Done()) { if (_tcscmp(prlStack->GetNext()->GetComponentId(), pcChild->GetComponentId()) == 0) { _stprintf(tszMsg, TEXT("Parent relation cycle exists starting from %s"), pcChild->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName); return TRUE; } }
prlStack->AddRelation(pcChild->GetComponentId());
RecursiveCheckParentCycles(pcChild, pclList, prlStack); }
pcComponent->GetChildrenList()->ResetList();
while (!pcComponent->GetChildrenList()->Done()) { prChild = pcComponent->GetChildrenList()->GetNext(); prlStack->RemoveRelation(prChild->GetComponentId());
}
return TRUE; }
/*++
Routine Description: Routine that checks if there are components with the same ID Argument: ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckSameId(IN ComponentList *pclList) { const PTSTR tszFunctionName = TEXT("CheckSameId");
pclList->ResetList();
Component *pcComponent;
while (!pclList->Done()) { pcComponent = pclList->GetNext();
pcComponent->IsThereSameId(pclList); }
return TRUE; }
/*++
Routine Description: Routine that checks if the top level components are the ones that are listed in the master INF file Argument: HINF hinfHandle : A handle to the open Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckTopLevelComponent(IN HINF hinfHandle, IN ComponentList *pclList) { const PTSTR tszFunctionName = TEXT("CheckTopLevelComponent");
Component *pcComponent;
BOOL bSuccess;
INFCONTEXT infContext;
TCHAR tszMsg[MaxStringSize];
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
if (pcComponent->IsTopLevelComponent()) { // Check if this component exists in the [Components] section
bSuccess = SetupFindFirstLine(hinfHandle, tszComponents, pcComponent->GetComponentId(), &infContext); if (!bSuccess) { _stprintf(tszMsg, TEXT("Component %s doesn't have a parent, but it is not listed in the [Components] section"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} } }
return TRUE; }
/*++
Routine Description: Routine that checks if every component has a description and tip, and that no two components have the same description if they share a common parent Argument: HINF hinfHandle : A handle to the open Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckDescription(IN HINF hinfHandle, IN ComponentList *pclList) { const PTSTR tszFunctionName = TEXT("CheckDescription");
Component *pcComponent;
BOOL bSuccess;
TCHAR tszMsg[MaxStringSize];
INFCONTEXT infContext;
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
// We probably have to add two members to the class
// but let's how this works out
// Allocate a new structure for this node
pcComponent->pDescAndTip = new DescAndTip;
// Get the data from the inf file
bSuccess = SetupFindFirstLine(hinfHandle, pcComponent->GetComponentId(), TEXT("OptionDesc"), &infContext); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to find OptionDesc for component %s"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} else { bSuccess = SetupGetStringField(&infContext, 1, pcComponent->pDescAndTip->tszDesc, MaxBufferSize, NULL); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to read OptionDesc field of component %s"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
}
// Now see if it is a real description or a string
if (pcComponent->pDescAndTip->tszDesc[0] == TEXT('%')) { bSuccess = SetupFindFirstLine(hinfHandle, TEXT("Strings"), Strip(pcComponent->pDescAndTip->tszDesc), NULL); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to find key %s in [Strings] section"), pcComponent->pDescAndTip->tszDesc); LogError(tszMsg, SEV2, tszFunctionName);
} else { bSuccess = SetupGetStringField(&infContext, 1, pcComponent->pDescAndTip->tszDesc, MaxBufferSize, NULL); } } else { // Do nothing
} }
// Now Get the tip stuff, it is basically the same as desc
bSuccess = SetupFindFirstLine(hinfHandle, pcComponent->GetComponentId(), TEXT("Tip"), &infContext); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to find Tip key for component %s"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} else { bSuccess = SetupGetStringField(&infContext, 1, pcComponent->pDescAndTip->tszTip, MaxBufferSize, NULL); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to read Tip field for component %s"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
}
// Now see if it is a real description or a string
if (pcComponent->pDescAndTip->tszTip[0] == TEXT('%')) { bSuccess = SetupFindFirstLine(hinfHandle, TEXT("Strings"), Strip(pcComponent->pDescAndTip->tszTip), NULL); if (!bSuccess) { _stprintf(tszMsg, TEXT("Unable to find key %s in [Strings] section"), pcComponent->pDescAndTip->tszTip); LogError(tszMsg, SEV2, tszFunctionName);
} else { bSuccess = SetupGetStringField(&infContext, 1, pcComponent->pDescAndTip->tszTip, MaxBufferSize, NULL); } } else { // Do nothing
} } }
// Now all the tip and desc thing is filled
// Loop through the component, see if there are two components with
// the same description
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
pcComponent->IsThereSameDesc(pclList); }
// Now go through the list and delete the field
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext(); delete (pcComponent->pDescAndTip); }
return TRUE;
}
/*++
Routine Description: Routine that checks if every component has the correct mode value Toplevel component should not have Modes= line, and the modes value should only be 0 through 3 Argument: HINF hinfHandle : A handle to the open Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckModes(IN HINF hinfHandle, IN ComponentList *pclList) { // Go through each component, two things to check
// a component with children should not have a mode line
// the value of the fields should be between 0 and 3
//SETUPMODE_MINIMAL = 0;
//SETUPMODE_TYPICAL = 1;
//SETUPMODE_LAPTOP = 2;
//SETUPMODE_CUSTOM = 3;
TCHAR tszMsg[MaxStringSize]; INFCONTEXT infContext; BOOL bSuccess;
UINT uiNumFields;
const PTSTR tszFunctionName = TEXT("CheckModes");
INT nMode;
Component *pcComponent;
pclList->ResetList();
while (!pclList->Done()) { pcComponent = pclList->GetNext();
bSuccess = SetupFindFirstLine(hinfHandle, pcComponent->GetComponentId(), TEXT("Modes"), &infContext); if (bSuccess) { // Found the mode line
// first check if this a component with children
if (pcComponent->IsParentOfOthers()) { _stprintf(tszMsg, TEXT("%s has subcomponent, and has Modes = line"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} else { // Check the validity of the fields
uiNumFields = SetupGetFieldCount(&infContext); if (uiNumFields < 1 || uiNumFields > 4) { _stprintf(tszMsg, TEXT("Invalid number of fields in section [%s]"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} for (UINT i = 1; i <= uiNumFields; i++) { bSuccess = SetupGetIntField(&infContext, i, &nMode); if (!bSuccess) { _stprintf(tszMsg, TEXT("Failed to get Mode value in section [%s]"), pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} if (nMode < 0 || nMode > 3) { _stprintf(tszMsg, TEXT("Invalid mode value %d in section [%s]"), nMode, pcComponent->GetComponentId()); LogError(tszMsg, SEV2, tszFunctionName);
} } } } }
return TRUE; }
/*++
Routine Description: Routine that checks if the every INF file has a line LayoutFile = layout.inf No file should ever use [SourceDisksFiles] or [SourceDisksNames] section Argument: HINF hinfHandle : A handle to the open Inf file ComponentList *pclList : A pointer to the component list Return Value: The return value is not used --*/
BOOL CheckLayoutFile(IN TCHAR tszSubINFName[MaxStringSize][MaxStringSize], IN UINT uiNumComponents, IN TCHAR *tszDir) { TCHAR tszMsg[MaxStringSize];
BOOL bSuccess;
HINF hinfHandle;
INFCONTEXT infContext;
UINT uiError;
TCHAR tszLine[MaxStringSize];
const PTSTR tszFunctionName = TEXT("CheckLayoutFile");
// Now check the LayoutFile in each INF file
for (UINT m = 0; m < uiNumComponents; m++) { if (tszSubINFName[m][0]) { _stprintf(tszMsg, TEXT("%s%s"), tszDir, tszSubINFName[m]); hinfHandle = SetupOpenInfFile(tszMsg, NULL, INF_STYLE_WIN4, &uiError);
// We assume the hinf handle is valid
bSuccess = SetupFindFirstLine(hinfHandle, TEXT("Version"), tszLayoutFile, &infContext);
if (!bSuccess) {
_stprintf(tszMsg, TEXT("LayoutFile not found in file %s"), tszSubINFName[m]);
LogError(tszMsg, SEV2, tszFunctionName);
SetupCloseInfFile(hinfHandle);
continue;
}
// Check if the value of the key is Layout.inf
TCHAR tszLayoutFileName[MaxStringSize];
bSuccess = SetupGetStringField(&infContext, 1, tszLayoutFileName, MaxBufferSize, NULL);
if (!bSuccess) { _stprintf(tszMsg, TEXT("Error reading the value of the %s in %s"), tszLayoutFile, tszSubINFName[m]); } if ( _tcsicmp(tszLayoutFileName, TEXT("Layout.inf")) != 0 ) { _stprintf(tszMsg, TEXT("The value of LayoutFile= %s in %s is invalid"), tszLayoutFileName, tszSubINFName[m]); }
if (!bSuccess || _tcsicmp(tszLayoutFileName, TEXT("Layout.inf")) != 0 ) {
LogError(tszMsg, SEV2, tszFunctionName); }
// Now check that we should not have SourceDisksNames
// or SourceDisksFiles sections
bSuccess = SetupFindFirstLine(hinfHandle, TEXT("SourceDisksNames"), NULL, &infContext);
if (bSuccess) { _stprintf(tszMsg, TEXT("[SourceDisksNames] section presents in %s"), tszSubINFName[m]);
LogError(tszMsg, SEV2, tszFunctionName);
}
bSuccess = SetupFindFirstLine(hinfHandle, TEXT("SourceDisksFiles"), NULL, &infContext);
if (bSuccess) { _stprintf(tszMsg, TEXT("[SourceDisksFiles] section presents in %s"), tszSubINFName[m]); LogError(tszMsg, SEV2, tszFunctionName); }
SetupCloseInfFile(hinfHandle);
} }
return TRUE;
}
/*++
Routine Description: Routine that logs an error depending on the ways some global variables are set Argument: TCHAR *tszMsg: Error Message to log DWORD dwErrorLevel: How serious the error is TCHAR *tszFunctionName: the function name this error is detected Return Value: The return value is not used --*/
VOID LogError(IN TCHAR *tszMsg, IN DWORD dwErrorLevel, IN TCHAR *tszFunctionName) { double fn = 1.00;
if (g_bUseLog) { Log(fn, dwErrorLevel, tszMsg); } if (g_bUseMsgBox) { if (dwErrorLevel == INFO) { // We will not put up anything
}
else { MessageBox(NULL, tszMsg, tszFunctionName, MB_ICONERROR | MB_OK); } } if (g_bUseConsole) {
TCHAR tszContent[MaxStringSize];
_tcscpy(tszContent, tszMsg); _tcscat(tszContent, TEXT("\n")); _ftprintf(stdout, tszContent);
}
}
/*++
Routine Description: Routine that gets rid of the first and last char of a string Argument: TCHAR *tszString: Error Message to log Return Value: The return value is not used --*/
TCHAR *Strip(TCHAR *tszString) { TCHAR tszTemp[MaxStringSize];
_tcscpy(tszTemp, (tszString+1));
tszTemp[_tcslen(tszTemp)-1] = 0;
_tcscpy(tszString, tszTemp);
return tszString; }
|