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.
 
 
 
 
 
 

1845 lines
47 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
For Internal use only!
Module Name:
INFSCAN
globalscan.cpp
Abstract:
Global scanner class
entry points GlobalScan::ParseArgs
and GlobalScan::Scan
are called from main()
History:
Created July 2001 - JamieHun
--*/
#include "precomp.h"
#pragma hdrstop
GlobalScan::GlobalScan()
/*++
Routine Description:
Initialize class variables
--*/
{
InfFilter = INVALID_HANDLE_VALUE;
ThreadCount = 0;
GeneratePnfs = false;
GeneratePnfsOnly = false;
Pedantic = false;
Trace = false;
IgnoreErrors = false;
TargetsToo = false;
DetermineCopySections = false;
LimitedSourceDisksFiles = false;
BuildChangedDevices = BUILD_CHANGED_DEVICES_DISABLED;
SourceFileList = INVALID_HANDLE_VALUE;
NewFilter = INVALID_HANDLE_VALUE;
DeviceFilterList = INVALID_HANDLE_VALUE;
NextJob = Jobs.end();
SpecifiedNames = false;
}
GlobalScan::~GlobalScan()
/*++
Routine Description:
Release any allocated data/files
--*/
{
if(InfFilter != INVALID_HANDLE_VALUE) {
SetupCloseInfFile(InfFilter);
}
if(SourceFileList != INVALID_HANDLE_VALUE) {
CloseHandle(SourceFileList);
}
if(NewFilter != INVALID_HANDLE_VALUE) {
CloseHandle(NewFilter);
}
if(DeviceFilterList != INVALID_HANDLE_VALUE) {
CloseHandle(DeviceFilterList);
}
}
int
GlobalScan::ParseVersion(LPCSTR ver)
/*++
Routine Description:
Parse a version string into constituent parts
Arguments:
ver - version string as passed into argv[]
Return Value:
0 on success
--*/
{
//
// <plat>.<maj>.<min>.<typ>.<suite>
//
PTSTR cpy = CopyString(ver);
int res = Version.Parse(cpy);
delete [] cpy;
if(res == 4) {
Usage();
return 2;
}
return res;
}
int
GlobalScan::ParseArgs(int argc,char *argv[])
/*++
Routine Description:
Parse command line parameters
Arguments:
argc/argv as passed into main
Return Value:
0 on success
--*/
{
int i;
int res;
SafeString arg;
for(i = 1; i < argc; i++) {
if((argv[i][0] != TEXT('/')) && (argv[i][0] != TEXT('-'))) {
break;
}
if(!argv[i][1] || (argv[i][2] && !isdigit(argv[i][2]))) {
Usage();
return 2;
}
switch(*(argv[i]+1)) {
case 'B' :
case 'b' :
//
// Take supplied textfile as list of "unchanged" build files
// report a list of devices that use (copy) files that are not
// part of this unchanged list
//
// SP build special
// use in conjunction with /E
//
BuildChangedDevices = (DWORD)strtoul(argv[i]+2,NULL,0);
if(!BuildChangedDevices) {
BuildChangedDevices = BUILD_CHANGED_DEVICES_DEFAULT;
}
BuildChangedDevices |= BUILD_CHANGED_DEVICES_ENABLED;
i++;
if(i == argc) {
Usage();
return 2;
} else {
StringList list;
res = LoadListFromFile(SafeStringA(argv[i]),list);
if(res != 0) {
return res;
}
StringList::iterator li;
for(li = list.begin(); li != list.end(); li++) {
BuildUnchangedFiles.insert(*li);
}
}
break;
case 'C' :
case 'c' :
//
// Create Filter INF specified in the next argument
//
i++;
if(i == argc) {
Usage();
return 2;
}
if(NewFilter == INVALID_HANDLE_VALUE) {
NewFilter = CreateFileA(argv[i],
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(NewFilter == INVALID_HANDLE_VALUE) {
fprintf(stderr,"#*** Cannot open file \"%s\" for writing\n",argv[i]);
return 3;
}
Write(NewFilter,WRITE_INF_HEADER);
}
break;
case 'D' :
case 'd' :
//
// Determine other copy sections
//
DetermineCopySections = true;
break;
case 'E' :
case 'e' :
//
// Create a list of device = inf
//
i++;
if(i == argc) {
Usage();
return 2;
}
if(DeviceFilterList == INVALID_HANDLE_VALUE) {
DeviceFilterList = CreateFileA(argv[i],
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(DeviceFilterList == INVALID_HANDLE_VALUE) {
fprintf(stderr,"#*** Cannot open file \"%s\" for writing\n",argv[i]);
return 3;
}
}
break;
case 'F' :
case 'f' :
//
// Filter the list based on the INF in the next argument
//
i++;
if(i == argc) {
Usage();
return 2;
}
FilterPath = ConvertString(argv[i]);
break;
case 'G':
case 'g':
//
// generate PNF's (see also Z)
//
GeneratePnfs = true;
break;
case 'H' :
case 'h' :
case '?' :
//
// Display usage help
//
Usage();
return 1;
case 'I' :
case 'i' :
//
// ignore
//
IgnoreErrors = true;
break;
case 'N' :
case 'n' :
//
// named file
//
i++;
if(i == argc) {
Usage();
return 2;
}
SpecifiedNames = true;
_strlwr(argv[i]);
arg = ConvertString(argv[i]);
if(ExcludeInfs.find(arg) == ExcludeInfs.end()) {
NamedInfList.push_back(arg);
//
// make sure it appears only once
//
ExcludeInfs.insert(arg);
}
break;
case 'O' :
case 'o' :
//
// override path (if an INF is in this (relative) location,
// it's used instead
// multiple overrides can be given
// "/O ." is always assumed to be last unless explicitly given
//
i++;
if(i == argc) {
Usage();
return 2;
}
arg = ConvertString(argv[i]);
Overrides.push_back(arg);
break;
case 'P' :
case 'p' :
//
// pedantic mode - INF's must match expectations in filter
//
Pedantic = true;
break;
case 'Q' :
case 'q' :
//
// output source+target files (used in conjunction with /S
//
i++;
if(i == argc) {
Usage();
return 2;
}
if(SourceFileList == INVALID_HANDLE_VALUE) {
TargetsToo = true;
SourceFileList = CreateFileA(argv[i],
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(SourceFileList == INVALID_HANDLE_VALUE) {
fprintf(stderr,"#*** Cannot open file \"%s\" for writing\n",argv[i]);
return 3;
}
}
break;
case 'R' :
case 'r' :
//
// trace
//
Trace = true;
break;
case 'S' :
case 's' :
//
// output source file
//
i++;
if(i == argc) {
Usage();
return 2;
}
if(SourceFileList == INVALID_HANDLE_VALUE) {
SourceFileList = CreateFileA(argv[i],
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(SourceFileList == INVALID_HANDLE_VALUE) {
fprintf(stderr,"#*** Cannot open file \"%s\" for writing\n",argv[i]);
return 3;
}
}
break;
case 'T':
case 't':
//
// specify number of threads
//
i++;
if(i == argc) {
Usage();
return 2;
}
ThreadCount = atoi(argv[i]);
break;
case 'V' :
case 'v' :
//
// version
//
i++;
if(i == argc) {
Usage();
return 2;
}
res = ParseVersion(argv[i]);
if(res != 0) {
return res;
}
break;
case 'W' :
case 'w' :
//
// include, alternative to 'N'
//
i++;
if(i == argc) {
Usage();
return 2;
} else {
SpecifiedNames = true;
StringList list;
res = LoadListFromFile(SafeStringA(argv[i]),list);
if(res != 0) {
return res;
}
StringList::iterator li;
for(li = list.begin(); li != list.end(); li++) {
if(ExcludeInfs.find(*li) == ExcludeInfs.end()) {
NamedInfList.push_back(*li);
//
// insert only once
// stop a 2nd/subsequent insert
//
ExcludeInfs.insert(*li);
}
}
}
break;
case 'X' :
case 'x' :
//
// exclude, mask out future files added to list
//
i++;
if(i == argc) {
Usage();
return 2;
} else {
StringList list;
res = LoadListFromFile(SafeStringA(argv[i]),list);
if(res != 0) {
return res;
}
StringList::iterator li;
for(li = list.begin(); li != list.end(); li++) {
ExcludeInfs.insert(*li);
}
}
break;
case 'Y':
case 'y':
LimitedSourceDisksFiles = true;
break;
case 'Z':
case 'z':
//
// generate PNF's only
//
GeneratePnfs = true;
GeneratePnfsOnly = true;
break;
default:
//
// Display usage help
//
Usage();
return 2;
}
}
if(i < argc) {
SourcePath = ConvertString(argv[i]);
i++;
}
if(i != argc) {
Usage();
return 2;
}
return 0;
}
int
GlobalScan::Scan()
/*++
Routine Description:
Do the actual scanning
Arguments:
none
Return Value:
0 on success
--*/
{
int res;
StringList ParseInfList;
StringList LayoutInfList;
if(Trace) {
_ftprintf(stderr,TEXT("#### Obtaining list of INF files\n"));
}
Overrides.push_back(TEXT("."));
if (!SpecifiedNames) {
//
// enumerate all the INF's if none were explicitly mentioned
//
StringList::iterator dir;
for (dir = Overrides.begin(); dir != Overrides.end(); dir++) {
//
// for each directory
//
WIN32_FIND_DATA findData;
HANDLE findHandle;
ZeroMemory(&findData,sizeof(findData));
SafeString mask;
res = ExpandFullPath(*dir,TEXT("*.INF"),mask);
if(res != 0) {
return res;
}
if(Trace) {
_ftprintf(stderr,TEXT("#### Scanning %s\n"),mask.c_str());
}
findHandle = FindFirstFile(mask.c_str(),&findData);
if(findHandle == INVALID_HANDLE_VALUE) {
continue;
}
do {
if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
if(findData.nFileSizeHigh != 0) {
continue;
}
if(findData.nFileSizeLow == 0) {
continue;
}
_tcslwr(findData.cFileName);
SafeString name = findData.cFileName; // saves lots of automatics
if(ExcludeInfs.find(name) != ExcludeInfs.end()) {
//
// not allowed to process an INF with this name
// (previously obtained or specifically excluded)
//
continue;
}
//
// make a note of the filename so we effectively override it
//
ExcludeInfs.insert(name);
//
// make the final name
//
SafeString fullname;
res = ExpandFullPath(*dir,name,fullname);
if(res != 0) {
return res;
}
if(name.compare(TEXT("layout.inf")) == 0) {
//
// looks like a (the) layout file
// these are parsed ahead of other INF's
//
LayoutInfList.push_back(fullname);
} else {
ParseInfList.push_back(fullname);
}
} while (FindNextFile(findHandle,&findData));
FindClose(findHandle);
}
} else {
//
// INF's were manually specified, find where they are located
//
StringList::iterator name;
StringList::iterator dir;
for(name = NamedInfList.begin(); name != NamedInfList.end(); name++) {
SafeString fullname;
res = ExpandFullPathWithOverride(*name,fullname);
if(res != 0) {
return res;
}
if(_tcsicmp(GetFileNamePart(name->c_str()),TEXT("layout.inf"))==0) {
//
// looks lie a layout file
// parse ahead of other INF's
//
LayoutInfList.push_back(fullname);
} else {
ParseInfList.push_back(fullname);
}
}
}
if(ParseInfList.empty() && LayoutInfList.empty()) {
_ftprintf(stderr,TEXT("#*** No files\n"));
return 1;
}
if(FilterPath.length() && !GeneratePnfsOnly) {
GetFullPathName(FilterPath,FilterPath);
InfFilter = SetupOpenInfFile(FilterPath.c_str(),NULL,INF_STYLE_WIN4,NULL);
if(InfFilter == INVALID_HANDLE_VALUE) {
_ftprintf(stderr,TEXT("#*** Cannot open filter\n"));
return 3;
}
if(Trace) {
_ftprintf(stderr,TEXT("#### Loading filter %s\n"),FilterPath.c_str());
}
LoadFileDispositions();
LoadOtherCopySections();
}
if((NewFilter == INVALID_HANDLE_VALUE) && !DetermineCopySections) {
FileDisposition & disp = GetGuidDisposition(NULL_GUID);
if(!disp.Filtered) {
//
// default disposition for NULL guid's
//
disp.FilterAction = ACTION_IGNOREINF;
}
}
StringList::iterator i;
if(GeneratePnfsOnly) {
//
// do nothing special with layout files because all we'll be doing
// is generating PNF's
// so merge them into ParseInfList
//
for(i = LayoutInfList.begin(); i != LayoutInfList.end() ; i++) {
ParseInfList.push_back(*i);
}
} else {
if(Trace) {
_ftprintf(stderr,TEXT("#### Scanning Layout.Inf file(s) sequentially\n"));
}
for(i = LayoutInfList.begin(); i != LayoutInfList.end() ; i++) {
SafeString &full_inf = *i;
if(GeneratePnfs) {
GeneratePnf(full_inf);
}
//
// this stuff has to be done sequentially
//
GetFileDisposition(full_inf).FilterAction |= ACTION_EARLYLOAD; // override
InfScan *pInfScan = new InfScan(this,full_inf); // may throw bad_alloc
SerialJobs.push_back(pInfScan);
pInfScan->ThisIsLayoutInf = true;
res = pInfScan->Run();
if(res == 0) {
//
// parse [SourceDisksFiles*]
//
pInfScan->PrimaryInf->Locked = true;
LayoutInfs.push_back(pInfScan->PrimaryInf);
if(pInfScan->PrimaryInf->LooksLikeLayoutInf) {
//
// parse [WinntDirectories]
// (only makes sense if layout.inf extended syntax detected)
//
res = pInfScan->PrimaryInf->LoadWinntDirectories(GlobalDirectories);
}
if(NewFilter != INVALID_HANDLE_VALUE) {
//
// ensure we indicate this INF should always be processed
// at some point we can handle this flag specially
//
GetFileDisposition(full_inf).FilterAction |= ACTION_EARLYLOAD;
}
}
pInfScan->PartialCleanup();
if(res != 0) {
return res;
}
}
}
if(GeneratePnfs) {
//
// process Pnf's either now
// or add them to Job list
//
if(Trace) {
if(ThreadCount) {
_ftprintf(stderr,TEXT("#### Adding Pnf generation Jobs\n"));
} else {
_ftprintf(stderr,TEXT("#### Generating Pnf's sequentially\n"));
}
}
for(i = ParseInfList.begin(); i != ParseInfList.end() ; i++) {
SafeString &full_inf = *i;
if(ThreadCount) {
//
// add to job list
//
PnfGen *pJob = new PnfGen(full_inf); // may throw bad_alloc
Jobs.push_back(pJob);
} else {
//
// do now
//
GeneratePnf(full_inf);
}
}
//
// limit threads to # of INF's
//
if(Jobs.size() < ThreadCount) {
ThreadCount = Jobs.size();
}
}
if(!GeneratePnfsOnly) {
//
// process Inf's either now or queue for job processing
//
if(Trace) {
if(ThreadCount) {
_ftprintf(stderr,TEXT("#### Adding Inf scanning Jobs\n"));
} else {
_ftprintf(stderr,TEXT("#### Scanning Inf's sequentially\n"));
}
}
for(i = ParseInfList.begin(); i != ParseInfList.end() ; i++) {
SafeString &full_inf = *i;
InfScan *pJob = new InfScan(this,full_inf); // may throw bad_alloc
if(ThreadCount) {
//
// add to job list
//
Jobs.push_back(pJob);
} else {
//
// do now
//
SerialJobs.push_back(pJob);
res = pJob->Run();
pJob->PartialCleanup();
if(res != 0) {
return res;
}
}
}
}
if(ThreadCount) {
//
// use worker threads
//
// see if #jobs > #threads
//
if(Jobs.size() < ThreadCount) {
ThreadCount = Jobs.size();
}
if(Trace) {
_ftprintf(stderr,TEXT("#### Spinning %u threads\n"),ThreadCount);
}
//
// generate the thread objects
//
res = GenerateThreads();
if(res != 0) {
return res;
}
//
// start the threads
// they will start picking up the jobs
//
if(Trace) {
_ftprintf(stderr,TEXT("#### Starting threads\n"));
}
res = StartThreads();
if(res != 0) {
return res;
}
//
// wait for all threads to finish
//
if(Trace) {
_ftprintf(stderr,TEXT("#### Waiting for Jobs to finish\n"));
}
res = FinishThreads();
if(res != 0) {
return res;
}
}
//
// merge any results
//
if(Trace) {
_ftprintf(stderr,TEXT("#### Merge results\n"));
}
res = FinishJobs();
if(res != 0) {
return res;
}
if(GeneratePnfsOnly) {
return 0;
}
//
// post operations
//
if(res == 0) {
res = BuildNewInfFilter();
}
if(res == 0) {
res = BuildDeviceInfMap();
}
if(res == 0) {
res = BuildFinalSourceList();
}
if(Trace) {
_ftprintf(stderr,TEXT("#### Finish\n"));
}
return res;
}
int
GlobalScan::GenerateThreads()
/*++
Routine Description:
Create required number of Job threads
Threads are initially stopped
Arguments:
none
Return Value:
0 on success
--*/
{
int c;
for(c=0; c< ThreadCount;c++) {
JobThreads.push_back(JobThread(this));
}
return 0;
}
int
GlobalScan::StartThreads()
/*++
Routine Description:
Kick off the job threads to start processing the jobs
Arguments:
none
Return Value:
0 on success
--*/
{
//
// this is the first job in the list
//
NextJob = Jobs.begin();
//
// now kick off the threads to start looking for
// and processing jobs
//
JobThreadList::iterator i;
for(i = JobThreads.begin(); i != JobThreads.end(); i++) {
if(!i->Begin()) {
_ftprintf(stderr,TEXT("#*** Could not start thread\n"));
return 3;
}
}
return 0;
}
int
GlobalScan::FinishThreads()
/*++
Routine Description:
Wait for all job threads to finish
Arguments:
none
Return Value:
0 on success
--*/
{
JobThreadList::iterator i;
for(i = JobThreads.begin(); i != JobThreads.end(); i++) {
int res = (int)(i->Wait());
if(res != 0) {
return res;
}
}
return 0;
}
int
GlobalScan::FinishJobs()
/*++
Routine Description:
Do finish processing on each job sequentially
this includes any serialized jobs
Arguments:
none
Return Value:
0 on success
--*/
{
JobList::iterator i;
//
// two passes
// first PreResults to do any final prep's
//
for(i = SerialJobs.begin(); i != SerialJobs.end(); i++) {
int res = i->PreResults();
if(res != 0) {
return res;
}
}
for(i = Jobs.begin(); i != Jobs.end(); i++) {
int res = i->PreResults();
if(res != 0) {
return res;
}
}
//
// now actual Results phase
//
for(i = SerialJobs.begin(); i != SerialJobs.end(); i++) {
int res = i->Results();
if(res != 0) {
return res;
}
}
for(i = Jobs.begin(); i != Jobs.end(); i++) {
int res = i->Results();
if(res != 0) {
return res;
}
}
return 0;
}
int
GlobalScan::ExpandFullPath(const SafeString & subdir,const SafeString & name,SafeString & target)
/*++
Routine Description:
Expand full path taking into account specified SourcePath
Arguments:
subdir - subdirectory of SourcePath if not ""
name - filename (may be wildcard and may include a subdirectory)
target - generated full path name
Return Value:
0
--*/
{
SafeString given = PathConcat(SourcePath,PathConcat(subdir,name));
GetFullPathName(given,target);
return 0;
}
int
GlobalScan::ExpandFullPathWithOverride(const SafeString & name,SafeString & target)
/*++
Routine Description:
Expand full path taking into account Overrides
look for each SourcePath\<override>\name
and take first found converting it into full path
Arguments:
name - filename (may include a subdirectory)
target - generated full path name
Return Value:
0
--*/
{
StringList::iterator dir;
int res;
for(dir = Overrides.begin(); dir != Overrides.end(); dir++) {
res = ExpandFullPath(*dir,name,target);
if(res != 0) {
return res;
}
DWORD attr = GetFileAttributes(target.c_str());
if((attr == (DWORD)(-1)) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
//
// the named file doesn't exist in this particular
// override directory
//
continue;
}
//
// we found an override match
//
return 0;
}
//
// since the last overrides entry is ".", just return
// last generated name
//
return 0;
}
int GlobalScan::SaveForCrossInfInstallCheck(const SafeString & desc,const SafeString & src)
/*++
Routine Description:
Not thread safe, called during PreResults
Save description->src mapping
for later call to CheckCrossInfInstallCheck
(we can't do the check here else we'd randomly pick one inf over another
to report the conflict and we want to fail both inf's)
Arguments:
desc - lower-case device description
src - full name of INF currently being checked
Return Value:
0
--*/
{
StringToStringset::iterator i;
i = GlobalInfDescriptions.find(desc);
if(i == GlobalInfDescriptions.end()) {
//
// description doesn't exist
// create a new entry desc->src
//
StringSet s;
s.insert(src);
GlobalInfDescriptions.insert(StringToStringset::value_type(desc,s));
} else {
//
// description exists
// add this src (if it doesn't already exist)
//
i->second.insert(src);
}
return 0;
}
int GlobalScan::SaveForCrossInfDeviceCheck(const SafeString & hwid,const SafeString & src)
/*++
Routine Description:
Not thread safe, called during PreResults
Save hwid->src mapping
for later call to CheckCrossInfInstallCheck
(we can't do the check here else we'd randomly pick one inf over another
to report the conflict and we want to fail both inf's)
Arguments:
hwid - lower-case hardware ID
src - full name of INF currently being checked
Return Value:
0
--*/
{
StringToStringset::iterator i;
i = GlobalInfHardwareIds.find(hwid);
if(i == GlobalInfHardwareIds.end()) {
//
// hwid doesn't exist
// create a new entry desc->src
//
StringSet s;
s.insert(src);
GlobalInfHardwareIds.insert(StringToStringset::value_type(hwid,s));
} else {
//
// hwid exists
// add this src (if it doesn't already exist)
//
i->second.insert(src);
}
return 0;
}
int
GlobalScan::CheckCrossInfInstallConflict(const SafeString & desc,const SafeString & src, bool & f,SafeString & others)
/*++
Routine Description:
Not thread safe, called during PreResults
given a "description"
return f=true if found in some INF other than 'src'
return f=false if not found (INF added)
Arguments:
desc - lower-case device description
src - full name of INF currently being checked
f - return true if exists in another inf
others - descriptive list of conflicting INF's
Return Value:
0
--*/
{
f = false;
StringToStringset::iterator i;
i = GlobalInfDescriptions.find(desc);
if(i == GlobalInfDescriptions.end()) {
//
// shouldn't happen, but do right thing
//
return 0;
}
StringSet & s = i->second;
StringSet::iterator ii;
//
// report any conflicts other than self
//
for(ii = s.begin(); ii != s.end(); ii++) {
SafeString & str = *ii;
if(str == src) {
continue;
}
if(f) {
others += TEXT(" & ") + str;
} else {
f = true;
others = str;
}
}
return 0;
}
int
GlobalScan::CheckCrossInfDeviceConflict(const SafeString & hwid,const SafeString & src, bool & f,SafeString & others)
/*++
Routine Description:
Not thread safe, called during PreResults
given a "hardwareId"
return f=true if found in some INF other than 'src'
return f=false if not found (INF added)
Arguments:
hwid - lower-case hardware ID
src - full name of INF currently being checked
f - return true if exists in another inf
others - descriptive list of conflicting INF's
Return Value:
0
--*/
{
f = false;
StringToStringset::iterator i;
i = GlobalInfHardwareIds.find(hwid);
if(i == GlobalInfHardwareIds.end()) {
//
// shouldn't happen, but do right thing
//
return 0;
}
StringSet & s = i->second;
StringSet::iterator ii;
//
// report any conflicts other than self
//
for(ii = s.begin(); ii != s.end(); ii++) {
SafeString & str = *ii;
if(str == src) {
continue;
}
if(f) {
others += TEXT(" & ") + str;
} else {
f = true;
others = str;
}
}
return 0;
}
int GlobalScan::AddSourceFiles(StringList & sources)
/*++
Routine Description:
Add the list 'sources' to the known set of source files
Arguments:
sources - list of source files to add
Return Value:
0
--*/
{
if(SourceFileList != INVALID_HANDLE_VALUE) {
StringList::iterator i;
for(i = sources.begin(); i != sources.end(); i++) {
GlobalFileSet.insert(*i);
}
}
return 0;
}
JobEntry * GlobalScan::GetNextJob()
/*++
Routine Description:
Get next job safely
Arguments:
none
Return Value:
next job or NULL
--*/
{
ProtectedSection ThisSectionIsA(BottleNeck);
if(NextJob == Jobs.end()) {
return NULL;
}
JobEntry * Job = &*NextJob;
NextJob++;
return Job;
}
int GlobalScan::LoadFileDispositions()
/*++
Routine Description:
Load global error dispositions from filter
Load file/guid top-level dispositions
(actual error tables for these are loaded on demand)
Arguments:
none
Return Value:
0 on success
--*/
{
//
// load filter tables
//
int res;
INFCONTEXT filterContext;
if(InfFilter == INVALID_HANDLE_VALUE) {
return 0;
}
//
// load top-level filter table
//
if(SetupFindFirstLine(InfFilter,SECTION_FILEFILTERS,NULL,&filterContext)) {
do {
SafeString filename;
FileDisposition disp;
if(!MyGetStringField(&filterContext,FILEFILTERS_KEY_FILENAME,filename)) {
continue;
}
if(FileDispositions.find(filename) != FileDispositions.end()) {
continue;
}
if(!SetupGetIntField(&filterContext,FILEFILTERS_FIELD_ACTION,&disp.FilterAction)) {
disp.FilterAction = ACTION_DEFAULT;
}
MyGetStringField(&filterContext,FILEFILTERS_FIELD_SECTION,disp.FilterErrorSection);
MyGetStringField(&filterContext,FILEFILTERS_FIELD_GUID,disp.FileGuid);
disp.Filtered = true;
FileDispositions.insert(FileDispositionMap::value_type(filename,disp));
} while (SetupFindNextLine(&filterContext,&filterContext));
}
if(SetupFindFirstLine(InfFilter,SECTION_GUIDFILTERS,NULL,&filterContext)) {
do {
SafeString guid;
FileDisposition disp;
if(!MyGetStringField(&filterContext,GUIDFILTERS_KEY_GUID,guid)) {
continue;
}
if(GuidDispositions.find(guid) != GuidDispositions.end()) {
continue;
}
if(!SetupGetIntField(&filterContext,GUIDFILTERS_FIELD_ACTION,&disp.FilterAction)) {
disp.FilterAction = ACTION_DEFAULT;
}
MyGetStringField(&filterContext,GUIDFILTERS_FIELD_SECTION,disp.FilterErrorSection);
disp.Filtered = true;
GuidDispositions.insert(FileDispositionMap::value_type(guid,disp));
} while (SetupFindNextLine(&filterContext,&filterContext));
}
//
// preload global error table
//
GlobalErrorFilters.LoadFromInfSection(InfFilter,SECTION_ERRORFILTERS);
return 0;
}
int GlobalScan::LoadOtherCopySections()
/*++
Routine Description:
Load copy filters
Load file/guid top-level dispositions
(actual error tables for these are loaded on demand)
Arguments:
none
Return Value:
0 on success
--*/
{
//
// load filter tables
//
int res;
INFCONTEXT filterContext;
if(InfFilter == INVALID_HANDLE_VALUE) {
return 0;
}
//
// load top-level filter table
//
if(SetupFindFirstLine(InfFilter,SECTION_INSTALLS,NULL,&filterContext)) {
//
// file = install[,install....]
//
do {
SafeString filename;
SafeString section;
int c;
if(!MyGetStringField(&filterContext,0,filename)) {
continue;
}
StringSet & sects = GlobalOtherInstallSections[filename];
for(c=1; MyGetStringField(&filterContext,c,section);c++) {
sects.insert(section);
}
} while(SetupFindNextLine(&filterContext,&filterContext));
}
return 0;
}
int GlobalScan::GetCopySections(const SafeString & filename,StringSet & target)
/*++
Routine Description:
Return cached list of copy sections from filter
Arguments:
filename (without path)
target - merged with list of install sections
Return Value:
0 = success
--*/
{
StringToStringset::iterator i;
i = GlobalOtherInstallSections.find(filename);
if(i == GlobalOtherInstallSections.end()) {
return 0;
}
StringSet & sects = i->second;
StringSet::iterator ii;
for(ii = sects.begin(); ii != sects.end(); ii++) {
target.insert(*ii);
}
return 0;
}
int GlobalScan::SetCopySections(const SafeString & filename,const StringSet & sections)
/*++
Routine Description:
Not thread safe
upgrade global table with extra copy sections
Arguments:
filename (without path)
sections - list of install sections to merge in
Return Value:
0 = success
--*/
{
StringSet::iterator i;
StringSet & sects = GlobalOtherInstallSections[filename];
for(i = sections.begin(); i != sections.end(); i++) {
sects.insert(*i);
}
return 0;
}
FileDisposition & GlobalScan::GetFileDisposition(const SafeString & pathname)
/*++
Routine Description:
Return a file disposition entry for specified file
Note that the returned structure may be modified
However the table itself is shared
Arguments:
full path or filename
Return Value:
modifiable entry
--*/
{
//
// assume filename is lower-case
// we need to get just the actual name
//
SafeString filename = GetFileNamePart(pathname);
FileDispositionMap::iterator i;
ProtectedSection ThisSectionIsA(BottleNeck);
i = FileDispositions.find(filename);
if(i == FileDispositions.end()) {
//
// create and return
//
return FileDispositions[filename];
}
return i->second;
}
FileDisposition & GlobalScan::GetGuidDisposition(const SafeString & guid)
/*++
Routine Description:
Return a guid disposition entry for specified guid
Note that the returned structure may be modified
However the table itself is shared
Arguments:
full guid {...}
Return Value:
modifiable entry
--*/
{
FileDispositionMap::iterator i;
//
// assume guid-string is lower-case
//
ProtectedSection ThisSectionIsA(BottleNeck);
i = GuidDispositions.find(guid);
if(i == GuidDispositions.end()) {
//
// create and return
//
return GuidDispositions[guid];
}
return i->second;
}
int GlobalScan::BuildFinalSourceList()
/*++
Routine Description:
If requested, build a complete list of source files
Arguments:
NONE
Return Value:
0 on success
--*/
{
if(SourceFileList == INVALID_HANDLE_VALUE) {
return 0;
}
if(Trace) {
_ftprintf(stderr,TEXT("#### Build source list\n"));
}
StringSet::iterator i;
for(i = GlobalFileSet.begin(); i != GlobalFileSet.end(); i++) {
Write(SourceFileList,*i);
Write(SourceFileList,"\r\n");
}
return 0;
}
int GlobalScan::BuildNewInfFilter()
/*++
Routine Description:
If requested, complete a filter INF
Arguments:
NONE
Return Value:
0 on success
--*/
{
if(NewFilter == INVALID_HANDLE_VALUE) {
return 0;
}
if(Trace) {
_ftprintf(stderr,TEXT("#### Build filter\n"));
}
FileDispositionMap::iterator i;
//
// File Dispositions table
//
Write(NewFilter,TEXT("\r\n[") SECTION_FILEFILTERS TEXT("]\r\n"));
for(i = FileDispositions.begin(); i != FileDispositions.end(); i++) {
if(i->second.Filtered) {
basic_ostringstream<TCHAR> line;
line << QuoteIt(i->first) << TEXT(" = ");
line << TEXT("0x") << setfill(TEXT('0')) << setw(8) << hex << i->second.FilterAction << setfill(TEXT(' ')) << TEXT(",");
line << QuoteIt(i->second.FilterErrorSection) << TEXT(",");
line << QuoteIt(i->second.FileGuid);
line << TEXT("\r\n");
Write(NewFilter,line.str());
}
}
//
// Guid Dispositions
//
Write(NewFilter,TEXT("\r\n[") SECTION_GUIDFILTERS TEXT("]\r\n"));
for(i = GuidDispositions.begin(); i != GuidDispositions.end(); i++) {
if(i->second.Filtered) {
basic_ostringstream<TCHAR> line;
line << QuoteIt(i->first) << TEXT(" = ");
line << TEXT("0x") << setfill(TEXT('0')) << setw(8) << hex << i->second.FilterAction << setfill(TEXT(' ')) << TEXT("\r\n");
Write(NewFilter,line.str());
}
}
//
// other copy sections
//
if(GlobalOtherInstallSections.size()) {
Write(NewFilter,TEXT("\r\n[") SECTION_INSTALLS TEXT("]\r\n"));
StringToStringset::iterator s;
for(s = GlobalOtherInstallSections.begin(); s != GlobalOtherInstallSections.end(); s++) {
StringSet & sects = s->second;
StringSet::iterator ss;
for(ss = sects.begin(); ss != sects.end(); ss++) {
basic_ostringstream<TCHAR> line;
line << QuoteIt(s->first) << TEXT(" = ");
line << QuoteIt(*ss) << TEXT("\r\n");
Write(NewFilter,line.str());
}
}
}
return 0;
}
bool GlobalScan::IsFileChanged(const SafeString & file) const
{
SafeString fnp = GetFileNamePart(file);
//
// appears to have changed
//
return BuildUnchangedFiles.find(fnp) == BuildUnchangedFiles.end();
}
int GlobalScan::BuildDeviceInfMap()
/*++
Routine Description:
Create a list of "hardwareId" = "file"
to DeviceFilterList
Return Value:
0
--*/
{
if(DeviceFilterList == INVALID_HANDLE_VALUE) {
return 0;
}
StringToStringset::iterator i;
for(i = GlobalInfHardwareIds.begin(); i != GlobalInfHardwareIds.end(); i++) {
const SafeString &hwid = i->first;
StringSet &s = i->second;
Write(DeviceFilterList,QuoteIt(hwid));
bool f = false;
StringSet::iterator ii;
//
// report all INF's hwid appears in
//
for(ii = s.begin(); ii != s.end(); ii++) {
SafeString & str = *ii;
if(f) {
Write(DeviceFilterList,",");
} else {
Write(DeviceFilterList," = ");
f = true;
}
Write(DeviceFilterList,QuoteIt(*ii));
}
Write(DeviceFilterList,"\r\n");
}
return 0;
}
int GlobalScan::LoadListFromFile(const SafeStringA & file,StringList & list)
/*++
Routine Description:
Load a list of strings from a text file (ANSI filename)
file - name of file to load
list - returned list of strings
Return Value:
0
--*/
{
HANDLE hFile = CreateFileA(file.c_str(),
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE) {
fprintf(stderr,"#*** Cannot open file \"%s\" for reading\n",file.c_str());
return 3;
}
int res = LoadListFromFile(hFile,list);
CloseHandle(hFile);
if(res!=0) {
fprintf(stderr,"#*** Failure reading file \"%s\"\n",file.c_str());
}
return res;
}
int GlobalScan::LoadListFromFile(const SafeStringW & file,StringList & list)
/*++
Routine Description:
Load a list of strings from a text file (Unicode filename)
file - name of file to load
list - returned list of strings
Return Value:
0
--*/
{
HANDLE hFile = CreateFileW(file.c_str(),
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE) {
fprintf(stderr,"#*** Cannot open file \"%S\" for reading\n",file.c_str());
return 3;
}
int res = LoadListFromFile(hFile,list);
CloseHandle(hFile);
if(res!=0) {
fprintf(stderr,"#*** Failure reading file \"%S\"\n",file.c_str());
}
return res;
}
int GlobalScan::LoadListFromFile(HANDLE hFile,StringList & list)
/*++
Routine Description:
Load a list of strings from a text file (handle)
file - name of file to load
list - returned list of strings
Return Value:
0
--*/
{
DWORD sz = GetFileSize(hFile,NULL);
if(sz == INVALID_FILE_SIZE) {
return 3;
}
if(sz==0) {
//
// nothing to read
//
return 0;
}
LPSTR buffer = new CHAR[sz+1];
DWORD actsz;
if(!ReadFile(hFile,buffer,sz,&actsz,NULL)) {
delete [] buffer;
return 3;
}
buffer[actsz] = 0;
while(actsz>0 && buffer[actsz-1] == ('Z'-'@'))
{
actsz--;
buffer[actsz] = 0;
}
LPSTR linestart = buffer;
while(*linestart) {
LPSTR lineend = strchr(linestart,'\n');
if(lineend==NULL) {
lineend += strlen(linestart);
} else if(lineend == linestart) {
linestart = lineend+1;
continue;
} else {
if(lineend[-1] == '\r') {
lineend[-1] = '\0';
}
if(*lineend) {
*lineend = '\0';
lineend++;
}
}
_strlwr(linestart);
list.push_back(ConvertString(linestart));
linestart = lineend;
}
delete [] buffer;
return 0;
}