Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1450 lines
38 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
For Internal use only!
Module Name:
INFSCAN
infscan.cpp
Abstract:
Individual INF scanner class
entry point InfScan::Run
is invoked to parse an INF specified by InfScan::FullInfName
WARNING! WARNING!
SetupAPI implementation specific information is used
to do the parsing
History:
Created July 2001 - JamieHun
--*/
#include "precomp.h"
#pragma hdrstop
int PnfGen::Run()
/*++
Routine Description:
Job entry point: invoke GeneratePnf for context INF
Arguments:
NONE
Return Value:
0 on success
--*/
{
return GeneratePnf(InfName);
}
InfScan::InfScan(GlobalScan *globalScan,const SafeString & infName)
/*++
Routine Description:
Initialization
--*/
{
pGlobalScan = globalScan;
FullInfName = infName;
HasErrors = false;
ThisIsLayoutInf = false;
HasDependentFileChanged = false;
ScanDevices = false;
}
InfScan::~InfScan()
/*++
Routine Description:
Cleanup any dynamic data/handles
--*/
{
}
int
InfScan::Run()
/*++
Routine Description:
Job entry point: Parse a given Inf
Arguments:
NONE
Return Value:
0 on success
--*/
{
int res;
//
// see if this INF can be ignored
//
FileNameOnly = GetFileNamePart(FullInfName);
FileDisposition & disp = pGlobalScan->GetFileDisposition(FileNameOnly);
if((disp.FilterAction == ACTION_IGNOREINF) && (pGlobalScan->NewFilter == INVALID_HANDLE_VALUE)) {
//
// return here if the only flag set is ACTION_IGNOREINF
// if any other flags are set, we must at least load the inf
//
return 0;
}
FilterAction = disp.FilterAction;
FilterSection = disp.FilterErrorSection;
FilterGuid = disp.FileGuid;
if(pGlobalScan->BuildChangedDevices
|| (pGlobalScan->DeviceFilterList != INVALID_HANDLE_VALUE)
|| !pGlobalScan->IgnoreErrors) {
//
// maintain this flag so that we only scan devices if we need to
//
ScanDevices = true;
}
if((pGlobalScan->BuildChangedDevices & BUILD_CHANGED_DEVICES_INFCHANGED) &&
pGlobalScan->IsFileChanged(FullInfName)) {
HasDependentFileChanged = true;
}
PrimaryInf = Include(FullInfName,false);
if(PrimaryInf->InfHandle == INVALID_HANDLE_VALUE) {
FilterAction |= ACTION_IGNOREINF; // used when generating filters
if(Pedantic() && !HasErrors) {
Fail(MSG_INF_STYLE_WIN4);
}
return 0;
}
//
// obviously there must be [Version] information
// now see what kind of INF this is
//
res = CheckClassGuid();
if(res != 0) {
return res;
}
if(FilterAction & ACTION_IGNOREINF) {
return 0;
}
//
// if we haven't been filtered out, go on as if this is a driver INF
//
if(pGlobalScan->DetermineCopySections) {
res = GetCopySections();
if(res != 0) {
return res;
}
}
res = CheckDriverInf();
if(res != 0) {
return res;
}
res = ProcessCopySections();
if(res != 0) {
return res;
}
return res;
}
void
InfScan::Fail(int err,const StringList & errors)
/*++
Routine Description:
Handle an error while processing this INF
Arguments:
err = MSGID of error
errors = list of string parameters
Return Value:
NONE
--*/
{
if(pGlobalScan->IgnoreErrors) {
//
// not interested in errors, bail now
//
return;
}
//
// prep the entry we want to add
//
ReportEntry ent(errors);
ent.FilterAction = ACTION_FAILEDMATCH;
if(!HasErrors) {
//
// on first error determine what errors we'll allow or not
// (saves us processing filters for Good INF's)
//
if((pGlobalScan->InfFilter != INVALID_HANDLE_VALUE) &&
(pGlobalScan->NewFilter == INVALID_HANDLE_VALUE)) {
//
// per-file filters has precedence over per-guid filters
//
LocalErrorFilters.LoadFromInfSection(pGlobalScan->InfFilter,FilterSection);
LocalErrorFilters.LoadFromInfSection(pGlobalScan->InfFilter,GuidFilterSection);
}
HasErrors = true;
}
//
// If the global action doesn't tell us to ignore, we want to add
//
int action = LocalErrorFilters.FindReport(err,ent);
if(action & ACTION_NOMATCH) {
action = pGlobalScan->GlobalErrorFilters.FindReport(err,ent);
}
if (action & (ACTION_IGNOREINF|ACTION_IGNOREMATCH)) {
//
// whichever filter we used, indicated to ignore
//
return;
}
//
// add to our error table
//
action = LocalErrors.FindReport(err,ent,true);
}
int
InfScan::CheckClassGuid()
/*++
Routine Description:
Check to see if INF's ClassGUID is valid
Arguments:
NONE
Return Value:
0 on success
--*/
{
INFCONTEXT targetContext;
SafeString guid;
if(!SetupFindFirstLine(PrimaryInf->InfHandle,TEXT("Version"),TEXT("ClassGUID"),&targetContext)) {
if(SetupFindFirstLine(PrimaryInf->InfHandle,TEXT("Version"),TEXT("Class"),&targetContext)) {
//
// if Class is specified, ClassGUID needs to be too
//
Fail(MSG_NO_CLASS_GUID);
guid = INVALID_GUID;
} else {
//
// this is a file way to specify no guid
//
guid = NULL_GUID;
}
} else {
if(!MyGetStringField(&targetContext,1,guid)) {
Fail(MSG_INVALID_CLASS_GUID);
guid = INVALID_GUID;
}
if(guid.length() != 38) {
Fail(MSG_INVALID_CLASS_GUID);
guid = INVALID_GUID;
}
if(FilterGuid.length() != 0) {
if(FilterGuid != guid) {
Fail(MSG_INCORRECT_CLASS_GUID,FilterGuid);
FilterGuid = guid;
}
} else {
if((guid[0] != TEXT('{')) ||
(guid[37] != TEXT('}'))) {
Fail(MSG_INVALID_CLASS_GUID);
guid = INVALID_GUID;
}
}
}
if(FilterGuid.empty()) {
FilterGuid = guid;
}
//
// see if any global handling to be done with this GUID
//
FileDisposition & disp = pGlobalScan->GetGuidDisposition(guid);
FilterAction |= disp.FilterAction;
GuidFilterSection = disp.FilterErrorSection;
return 0;
}
int
InfScan::CheckSameInfInstallConflict(const SafeString & desc, const SafeString & sect, bool & f)
/*++
Routine Description:
Check to see if description appears twice in one INF for a different section
Arguments:
desc - description (lower-case)
sect - section being checked (lower-case)
f - returned true/false indicating duplicate
Return Value:
0
--*/
{
StringToString::iterator i;
i = LocalInfDescriptions.find(desc);
if(i != LocalInfDescriptions.end()) {
//
// already exists
//
if(i->second.compare(sect)==0) {
//
// but same section
//
f = false;
} else {
//
// different section
//
f = true;
Fail(MSG_LOCAL_DUPLICATE_DESC,sect,i->second,desc);
}
return 0;
}
//
// first time
//
LocalInfDescriptions[desc] = sect;
f = false;
return 0;
}
int
InfScan::CheckSameInfDeviceConflict(const SafeString & hwid, const SafeString & sect, bool & f)
/*++
Routine Description:
Check to see if hwid appears twice in one INF for a different section
(Ok for now)
Arguments:
hwid - hardware ID (lower-case)
sect - section being checked (lower-case)
f - returned true/false indicating duplicate
Return Value:
0
--*/
{
StringToString::iterator i;
i = LocalInfHardwareIds.find(hwid);
if(i != LocalInfHardwareIds.end()) {
//
// already exists
//
if(i->second.compare(sect)==0) {
//
// but same section
//
f = false;
} else {
//
// different section
//
f = true;
//Fail(MSG_LOCAL_DUPLICATE_DESC,sect,i->second,desc);
}
return 0;
}
//
// first time
//
LocalInfHardwareIds[hwid] = sect;
f = false;
return 0;
}
int
InfScan::PrepareCrossInfDeviceCheck()
/*++
Routine Description:
Invoke pGlobalScan::SaveForCrossInfInstallCheck
to prime table for later checks by CheckCrossInfInstallConflict
Arguments:
NONE
Return Value:
0
--*/
{
StringToString::iterator i;
for(i = LocalInfHardwareIds.begin(); i != LocalInfHardwareIds.end(); i++) {
if(pGlobalScan->BuildChangedDevices && !HasDependentFileChanged) {
//
// filter (only do this if !HasDependentFileChanged
// otherwise we'll get wrong results. We optimize
// writing stuff back)
//
if(ModifiedHardwareIds.find(i->first) == ModifiedHardwareIds.end()) {
continue;
}
}
pGlobalScan->SaveForCrossInfDeviceCheck(i->first,FileNameOnly);
}
return 0;
}
int
InfScan::PrepareCrossInfInstallCheck()
/*++
Routine Description:
Invoke pGlobalScan::SaveForCrossInfInstallCheck
to prime table for later checks by CheckCrossInfInstallConflict
Arguments:
NONE
Return Value:
0
--*/
{
StringToString::iterator i;
for(i = LocalInfDescriptions.begin(); i != LocalInfDescriptions.end(); i++) {
pGlobalScan->SaveForCrossInfInstallCheck(i->first,FileNameOnly);
}
return 0;
}
int
InfScan::CheckCrossInfDeviceConflicts()
/*++
Routine Description:
Invoke pGlobalScan::CheckCrossInfDeviceConflict
for each device in this INF to see if device is used in another INF
this is done during Results phase
Arguments:
desc - description (lower-case)
f - returned true/false indicating duplicate
Return Value:
0
--*/
{
StringToString::iterator i;
for(i = LocalInfHardwareIds.begin(); i != LocalInfHardwareIds.end(); i++) {
bool f;
const SafeString & hwid = i->first;
SafeString & sect = i->second;
SafeString other;
int res;
res = pGlobalScan->CheckCrossInfDeviceConflict(hwid,FileNameOnly,f,other);
if(res==0 && f) {
Fail(MSG_GLOBAL_DUPLICATE_HWID,sect,other,hwid);
}
}
return 0;
}
int
InfScan::CheckCrossInfInstallConflicts()
/*++
Routine Description:
Invoke pGlobalScan::CheckCrossInfInstallConflict
for each description in this INF to see if description is used in another INF
this is done during Results phase
Arguments:
desc - description (lower-case)
f - returned true/false indicating duplicate
Return Value:
0
--*/
{
StringToString::iterator i;
for(i = LocalInfDescriptions.begin(); i != LocalInfDescriptions.end(); i++) {
bool f;
const SafeString & desc = i->first;
SafeString & sect = i->second;
SafeString other;
int res;
res = pGlobalScan->CheckCrossInfInstallConflict(desc,FileNameOnly,f,other);
if(res==0 && f) {
Fail(MSG_GLOBAL_DUPLICATE_DESC,sect,other,desc);
}
}
return 0;
}
int
InfScan::CheckModelsSection(const SafeString & section,const StringList & shadowDecorations,DWORD platformMask,bool CopyElimination)
/*++
Routine Description:
Process a given models section
WARNING! may need to change if SetupAPI install behavior changes
MAINTAINANCE: This function expects [Models] to follow
<desc> = <sect>[,id....]
MAINTAINANCE: Must keep all possible decorations up to date
MAINTAINANCE: Must keep all shadow install sections up to date
Arguments:
section - name of models section
shadowDecorations - decorations to append (passed into CheckInstallSections)
PlatformMask - limit of platforms being processed
sections - returned list of decorated sections to be processed
CopyElimination - true if processing to eliminate from potential non-driver sections
Return Value:
0 on success
--*/
{
int res;
bool f;
INFCONTEXT context;
SafeString desc;
SafeString installsect;
HINF inf = PrimaryInf->InfHandle;
if(!SetupFindFirstLine(inf,section.c_str(),NULL,&context)) {
if(SetupGetLineCount(inf, section.c_str()) == -1) {
if(!CopyElimination) {
Fail(MSG_NO_LISTED_MODEL,section);
}
}
return 0;
}
//
// enumerate through each <desc> = <install>[,hwid...]
//
do {
if(CopyElimination) {
//
// CopyElimination pass
//
if(!MyGetStringField(&context,1,installsect) || installsect.empty()) {
continue;
}
//
// check for all possible install sections
//
InstallSectionBlobList sections;
res = CheckInstallSections(installsect,platformMask,shadowDecorations,sections,true,CopyElimination);
} else {
//
// Driver processing pass
//
if(!MyGetStringField(&context,0,desc) || desc.empty()) {
Fail(MSG_EXPECTED_DESCRIPTION,section);
continue;
}
if(!MyGetStringField(&context,1,installsect) || installsect.empty()) {
Fail(MSG_EXPECTED_INSTALL_SECTION,section,desc);
continue;
}
if(!pGlobalScan->IgnoreErrors) {
//
// only check for conflicts if we're going
// to report errors
//
res = CheckSameInfInstallConflict(desc,installsect,f);
if(res != 0) {
return res;
}
}
InstallSectionBlobList sections;
//
// check for all possible install sections
//
res = CheckInstallSections(installsect,platformMask,shadowDecorations,sections,true,CopyElimination);
if(ScanDevices) {
StringSet hwids;
//
// extract all hardware ID's handled
//
int hwidIter = 2;
SafeString hwid;
//
// inf-centric hardware ID's
// and fill in hwid for hardware ID's specific to this install line
//
while(MyGetStringField(&context,hwidIter++,hwid)) {
if(hwid.length()) {
hwids.insert(hwid);
res = CheckSameInfDeviceConflict(hwid,installsect,f);
if(res != 0) {
return res;
}
}
}
//
// install-section centric hardware ID's
//
InstallSectionBlobList::iterator isli;
for(isli = sections.begin(); isli != sections.end(); isli++) {
(*isli)->AddHWIDs(hwids);
}
}
}
} while (SetupFindNextLine(&context,&context));
return 0;
}
InstallSectionBlob InfScan::GetInstallSection(const SafeString & section)
/*++
Routine Description:
Obtain an install section (might already exist)
Arguments:
section - name of install section
Return Value:
InstallSection object related to the named install section
--*/
{
//
// see if we have one cached away
//
StringToInstallSectionBlob::iterator srch;
srch = UsedInstallSections.find(section);
if(srch != UsedInstallSections.end()) {
return srch->second;
}
//
// nope, so add one
//
InstallSectionBlob sect;
sect.create();
sect->pGlobalScan = pGlobalScan;
sect->pInfScan = this;
sect->Section = section;
UsedInstallSections[section] = sect;
return sect;
}
int
InfScan::CheckInstallSections(
const SafeString & namedSection,
DWORD platformMask,
const StringList & shadowDecorations,
InstallSectionBlobList & sections,
bool required,
bool CopyElimination)
/*++
Routine Description:
Given a section name
determine list of decorated sections to parse
Arguments:
namedSection - 'undecorated' section
shadowDecorations - sub-decorations appended to platform decorated section get complete list of install sections
sections - list of sections determined (CopyElimination = false)
warn - true if section is required
CopyElimination - true if processing to eliminate sections
Return Value:
0 on success
--*/
{
static StringProdPair decorations[] = {
//
// listed from most specific to most generic
// all lower-case
//
{ TEXT(".ntx86"), PLATFORM_MASK_NTX86 },
{ TEXT(".ntia64"), PLATFORM_MASK_NTIA64 },
{ TEXT(".ntamd64"), PLATFORM_MASK_NTAMD64 },
{ TEXT(".nt"), PLATFORM_MASK_NT },
{ TEXT(""), PLATFORM_MASK_ALL_ARCHITECTS },
{ NULL, 0 }
};
int i;
StringList::iterator ii;
SafeString sectFull;
SafeString sectFullDec;
if(CopyElimination) {
//
// copy elimination pass
//
for(i=0;decorations[i].String;i++) {
sectFull = namedSection + decorations[i].String;
PotentialInstallSections.erase(sectFull);
for(ii = shadowDecorations.begin(); ii != shadowDecorations.end(); ii++) {
sectFullDec = sectFull+*ii;
PotentialInstallSections.erase(sectFullDec);
}
}
return 0;
}
bool f = false;
DWORD platforms = platformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN);
HINF inf = PrimaryInf->InfHandle;
for(i=0;decorations[i].String;i++) {
DWORD plat = platforms & decorations[i].ProductMask;
if(plat) {
sectFull = namedSection + decorations[i].String;
//
// see if this section exists
//
if(SetupGetLineCount(inf, sectFull.c_str()) == -1) {
//
// nope, look for another one
//
continue;
}
f = true;
//
// return list of all sections potentially used
// over all platforms of interest
//
InstallSectionBlob sectInfo = GetInstallSection(sectFull);
sectInfo->PlatformMask |= plat;
sections.push_back(sectInfo);
//
// these sections are processed in parallel with primary section
//
for(ii = shadowDecorations.begin(); ii != shadowDecorations.end(); ii++) {
sectFullDec = sectFull+*ii;
PotentialInstallSections.erase(sectFullDec);
sectInfo = GetInstallSection(sectFullDec);
sectInfo->PlatformMask |= plat;
sections.push_back(sectInfo);
}
platforms &= ~plat;
}
}
if(!f) {
//
// no install section found at all
//
if(required) {
Fail(MSG_NO_ACTUAL_INSTALL_SECTION,namedSection);
}
} else if(Pedantic()) {
if(platforms) {
//
// an install section found but not all platforms covered
//
Fail(MSG_NO_GENERIC_INSTALL_SECTION,namedSection);
}
}
return 0;
}
int
InfScan::GetCopySections()
/*++
Routine Description:
Get initial list of sections (place into set for modification)
don't do anything that takes time yet
Arguments:
NONE
Return Value:
0 on success
--*/
{
StringList sections;
INFCONTEXT context;
pGlobalScan->SetupAPI.GetInfSections(PrimaryInf->InfHandle,sections);
StringList::iterator i;
for(i = sections.begin(); i != sections.end(); i++) {
PotentialInstallSections.insert(*i);
}
if(sections.empty()) {
return 0;
}
//
// get rid of some special cases
//
PotentialInstallSections.erase(TEXT("sourcedisksfiles"));
PotentialInstallSections.erase(TEXT("sourcedisksnames"));
PotentialInstallSections.erase(TEXT("version"));
PotentialInstallSections.erase(TEXT("strings"));
PotentialInstallSections.erase(TEXT("classinstall"));
PotentialInstallSections.erase(TEXT("manufacturer"));
//
// special pass of driver files
//
int res = CheckDriverInf(true);
if(res != 0) {
return res;
}
//
// now enumerate what we have left
//
StringSet::iterator ii;
for(ii = PotentialInstallSections.begin(); ii != PotentialInstallSections.end() ; ii++) {
const SafeString & str = *ii;
if(str.empty()) {
continue;
}
if(str[0] == TEXT('s')) {
if((_tcsncmp(str.c_str(),TEXT("sourcedisksfiles."),17)==0) ||
(_tcsncmp(str.c_str(),TEXT("sourcedisksnames."),17)==0) ||
(_tcsncmp(str.c_str(),TEXT("strings."),8)==0)) {
continue;
}
}
//
// for this section to be valid, it must have at least one
// CopyFiles = directive
//
if(!SetupFindFirstLine(PrimaryInf->InfHandle,str.c_str(),TEXT("copyfiles"),&context)) {
continue;
}
//
// ok, consider this
//
OtherInstallSections.insert(str);
}
return 0;
}
int
InfScan::ProcessCopySections()
/*++
Routine Description:
Process final list of copy sections
Arguments:
NONE
Return Value:
0 on success
--*/
{
int res = pGlobalScan->GetCopySections(FileNameOnly,OtherInstallSections);
if(res != 0) {
return res;
}
if(OtherInstallSections.empty()) {
return 0;
}
//
// make sure we haven't set IGNOREINF anywhere in our pass
//
FilterAction &= ~ ACTION_IGNOREINF;
//
// for each install section...
//
StringSet::iterator i;
DWORD platforms = pGlobalScan->Version.PlatformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN);
for(i = OtherInstallSections.begin(); i != OtherInstallSections.end(); i++) {
InstallScan s;
s.pGlobalScan = pGlobalScan;
s.pInfScan = this;
s.PlatformMask = platforms;
s.Section = *i;
s.NotDeviceInstall = true;
res =s.ScanInstallSection();
if(res != 0) {
return res;
}
}
return 0;
}
int
InfScan::CheckClassInstall(bool CopyElimination)
/*++
Routine Description:
Process one of the [classinstall32.*] sections
WARNING! may need to change if SetupAPI install behavior changes
Arguments:
sections - returned list of classinstall32 section variations
CopyElimination - true if just doing copy elimination
Return Value:
0 on success
--*/
{
StringList shadows; // currently none
InstallSectionBlobList sections;
return CheckInstallSections(TEXT("classinstall32"),
pGlobalScan->Version.PlatformMask,
shadows,
sections,
false,
CopyElimination);
}
int
InfScan::CheckDriverInf(bool CopyElimination)
/*++
Routine Description:
Process the [manufacturer] section
WARNING! may need to change if SetupAPI install behavior changes
MAINTAINANCE: This function expects [Manufacturer] to follow
<desc> = <sect>[,dec....]
MAINTAINANCE: Modify NodeVerInfo class if decr syntax changes
Arguments:
CopyElimination - true if just doing copy elimination
Return Value:
0 on success
--*/
{
INFCONTEXT context;
int res;
SafeString ModelSection;
SafeString DecSection;
SafeString ActualSection;
StringList shadows;
int dec;
HINF inf = PrimaryInf->InfHandle;
bool hasModels;
res = CheckClassInstall(CopyElimination);
if(res > 0) {
return res;
}
if(SetupFindFirstLine(inf,TEXT("manufacturer"),NULL,&context)) {
hasModels = true;
} else {
hasModels = false;
if(Pedantic()) {
Fail(MSG_NO_MANUFACTURER);
}
FilterAction |= ACTION_IGNOREINF;
if(UsedInstallSections.empty()) {
//
// no classinstall32 sections either, can return
//
return 0;
}
}
if(hasModels) {
//
// for a given DDInstall, also need to process these decorations
//
shadows.push_back(TEXT(".coinstallers"));
shadows.push_back(TEXT(".interfaces"));
//
// obtain list of all installation sections to parse
//
do {
//
// Model section entry
// expect <desc> = <section> [, dec [, dec ... ]]
//
if(!MyGetStringField(&context,1,ModelSection) || !ModelSection.length()) {
Fail(MSG_EXPECTED_MODEL_SECTION);
continue;
}
if(CopyElimination) {
PotentialInstallSections.erase(ModelSection);
}
//
// process all the model decorations
//
NodeVerInfoList nodes;
NodeVerInfoList::iterator i;
NodeVerInfo node;
//
// first entry is the default node (no decoration)
//
nodes.push_back(node);
//
// determine interesting decorations
//
for(dec = 2;MyGetStringField(&context,dec,DecSection);dec++) {
if(DecSection.length()) {
if(DecSection[0]==TEXT('.')) {
//
// cannot start with '.'
//
res = 4;
} else {
res = node.Parse(DecSection);
}
if(res == 4) {
Fail(MSG_MODEL_DECORATION_BAD,ModelSection,DecSection);
continue;
}
}
if(CopyElimination) {
//
// processing for copy sections
// can't do at same time as driver install processing
//
nodes.push_back(node);
} else if(node.IsCompatibleWith(pGlobalScan->Version)) {
//
// this is something to be considered
// see if this is better than anything
// we have so far based on the version
// criterias we're checking against
//
for(i = nodes.begin(); i != nodes.end(); i++) {
int test = node.IsBetter(*i,pGlobalScan->Version);
switch(test) {
case 1:
//
// *i is better
//
node.Rejected = true;
break;
case 0:
//
// node & *i are equally valid
//
break;
case -1:
//
// node & *i are the same
//
node.Rejected = true;
break;
case -2:
//
// node is better
//
(*i).Rejected = true;
break;
}
}
nodes.push_back(node);
}
}
//
// now look at each decorated models section in turn
// (that we've decided are interesting)
// adding any install sections to 'sections'
// for later processing
//
for(i = nodes.begin(); i != nodes.end(); i++) {
if((*i).Rejected) {
continue;
}
ActualSection = ModelSection;
if((*i).Decoration.length()) {
ActualSection+=(TEXT("."));
ActualSection+=((*i).Decoration);
if(CopyElimination) {
PotentialInstallSections.erase(ActualSection);
}
}
DWORD platforms = (*i).PlatformMask & pGlobalScan->Version.PlatformMask &
PLATFORM_MASK_ALL_ARCHITECTS;
res = CheckModelsSection(ModelSection,shadows,platforms,CopyElimination);
if(res != 0) {
return res;
}
}
} while (SetupFindNextLine(&context,&context));
}
if(CopyElimination || UsedInstallSections.empty()) {
//
// no sections to process
//
return 0;
}
//
// now parse all the device install sections
//
StringToInstallSectionBlob::iterator s;
for(s = UsedInstallSections.begin() ; s != UsedInstallSections.end(); s++) {
res = s->second->ScanInstallSection();
if(res != 0) {
return res;
}
if(s->second->HasDependentFileChanged) {
//
// merge hardware ID's back
// (optimization for now to do this only when needed)
//
s->second->GetHWIDs(ModifiedHardwareIds);
}
}
return 0;
}
ParseInfContextBlob & InfScan::Include(const SafeString & val,bool expandPath)
/*++
Routine Description:
Called to add an INF to our list of INF's required to process the
primary INF in question.
If 'expandPath' is false, this is the primary INF and we don't
need to determine the path of the INF
If 'expandPath' is true, this is an included INF.
Arguments:
val - name of INF
expandPath - true if we need to determine location of INF
Return Value:
Modifiable ParseInfContextBlob entry
--*/
{
SafeString infpath;
SafeString infname;
ParseInfContextMap::iterator i;
int res = 0;
if(expandPath) {
//
// we are being supplied (supposedly) only the name
//
infname = val;
} else {
//
// we are being supplied full pathname
//
infpath = val;
infname = GetFileNamePart(infpath.c_str());
}
i = Infs.find(infname);
if(i != Infs.end()) {
//
// already have it
//
return i->second;
}
if(expandPath) {
//
// we need to obtain full pathname
//
res = pGlobalScan->ExpandFullPathWithOverride(val,infpath);
}
ParseInfContextBlob & ThisInf = Infs[infname];
ThisInf.create();
ThisInf->InfName = infname;
ThisInf->pGlobalScan = pGlobalScan;
ThisInf->pInfScan = this;
if(res == 0) {
ThisInf->InfHandle = SetupOpenInfFile(infpath.c_str(),NULL,INF_STYLE_WIN4,NULL);
}
if(ThisInf->InfHandle == INVALID_HANDLE_VALUE) {
DWORD Err = GetLastError();
if(Err != ERROR_WRONG_INF_STYLE) {
Fail(MSG_OPENAPPENDINF,infname,infpath);
}
return ThisInf;
}
//
// load the source disks files and destination dirs that's in this INF
//
if(ThisIsLayoutInf || !pGlobalScan->LimitedSourceDisksFiles) {
ThisInf->LoadSourceDisksFiles();
}
ThisInf->LoadDestinationDirs();
return ThisInf;
}
int
InfScan::PartialCleanup()
/*++
Routine Description:
Clean up as much as we can
leaving only the info we need to complete the results phase
Whatever we do, don't leave INF handles open
700+ INF handles eats up virtual memory
Arguments:
NONE
Return Value:
0 on success
--*/
{
//
// 'LocalInfDescriptions' required for cross-checking
// 'LocalErrorFilters' required for cross-checking
// 'LocalErrors' required for output
// 'Infs' required for filter generation (but not handle)
//
PotentialInstallSections.clear();
UsedInstallSections.clear();
if(pGlobalScan->NewFilter == INVALID_HANDLE_VALUE) {
//
// for results generation only, we don't need Inf information
//
Infs.clear();
}
//
// If we still have Infs table, make sure all INF's are closed
//
ParseInfContextMap::iterator i;
for(i = Infs.begin(); i != Infs.end(); i++) {
i->second->PartialCleanup();
}
return 0;
}
int
InfScan::PreResults()
/*++
Routine Description:
Perform pre-results phase. Prime any global tables that will
be scanned by other InfScan functions during Results phase
In particular, do the cross-inf checking
Arguments:
NONE
Return Value:
0 on success
--*/
{
if(!pGlobalScan->IgnoreErrors) {
PrepareCrossInfInstallCheck();
PrepareCrossInfDeviceCheck();
} else {
if(pGlobalScan->DeviceFilterList != INVALID_HANDLE_VALUE) {
PrepareCrossInfDeviceCheck();
}
}
return 0;
}
int
InfScan::Results()
/*++
Routine Description:
Perform results phase. This function is called sequentially
so we can do thread-unsafe operations such as merging results
Arguments:
NONE
Return Value:
0 on success
--*/
{
int res;
//
// finish checking for cross-inf conflicts
//
if(!pGlobalScan->IgnoreErrors) {
CheckCrossInfInstallConflicts();
CheckCrossInfDeviceConflicts();
}
if(pGlobalScan->DetermineCopySections) {
pGlobalScan->SetCopySections(FileNameOnly,OtherInstallSections);
}
res = pGlobalScan->AddSourceFiles(SourceFiles);
if(res != 0) {
return res;
}
if(pGlobalScan->NewFilter == INVALID_HANDLE_VALUE) {
//
// display errors
//
ReportEntryMap::iterator byTag;
for(byTag = LocalErrors.begin(); byTag != LocalErrors.end(); byTag++) {
//
// this is our class/tag of error
//
int tag = byTag->first;
ReportEntrySet &s = byTag->second;
ReportEntrySet::iterator byText;
for(byText = s.begin(); byText != s.end(); byText++) {
//
// this is our actual error
//
(*byText)->Report(tag,FullInfName);
}
}
} else {
res = GenerateFilterInformation();
if(res != 0) {
return res;
}
}
return 0;
}
int InfScan::GenerateFilterInformation()
/*++
Routine Description:
Generate entries into the new filter file
called as part of results processing
Arguments:
NONE
Return Value:
0 on success
--*/
{
//
// generate all the filter information required
//
FileDisposition & filedisp = pGlobalScan->GetFileDisposition(FileNameOnly);
filedisp.Filtered = true;
filedisp.FilterAction = FilterAction;
filedisp.FileGuid = FilterGuid;
if(FilterGuid.length()) {
filedisp.FilterAction |= ACTION_CHECKGUID;
FileDisposition & guiddisp = pGlobalScan->GetGuidDisposition(FilterGuid);
guiddisp.Filtered = true;
guiddisp.FilterAction = ACTION_DEFAULT;
}
//
// process through all errors and create local error filter
// if there is any errors, designate a section name for the errors
//
if(HasErrors) {
filedisp.FilterErrorSection = GetFileNamePart(FullInfName) + TEXT(".Errors");
Write(pGlobalScan->NewFilter,"\r\n[");
Write(pGlobalScan->NewFilter,filedisp.FilterErrorSection);
Write(pGlobalScan->NewFilter,"]\r\n");
ReportEntryMap::iterator byTag;
for(byTag = LocalErrors.begin(); byTag != LocalErrors.end(); byTag++) {
//
// this is our class/tag of error
//
int tag = byTag->first;
ReportEntrySet &s = byTag->second;
ReportEntrySet::iterator byText;
for(byText = s.begin(); byText != s.end(); byText++) {
//
// this is our actual error
//
(*byText)->AppendFilterInformation(pGlobalScan->NewFilter,tag);
}
}
}
//
// process through all DestinationDirs
// and create a list of unprocessed sections
// for a 2nd pass CopyFiles
//
return 0;
}