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.
485 lines
14 KiB
485 lines
14 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
For Internal use only!
|
|
|
|
Module Name:
|
|
|
|
INFSCAN
|
|
parseinfctx.cpp
|
|
|
|
Abstract:
|
|
|
|
Information about an individual INF (either primary INF
|
|
being parsed by InfScan or a secondary included INF)
|
|
|
|
WARNING! WARNING!
|
|
All of this implementation relies on intimate knowledge of
|
|
SetupAPI/TextMode Setup/GuiMode Setup parsing of INF files.
|
|
|
|
It is re-implemented here for speed due to having to process
|
|
700+ INF's in a single go at the cost of having to maintain
|
|
this.
|
|
|
|
DO NOT (I repeat) DO NOT re-implement the code here without
|
|
consultation with SetupAPI owner.
|
|
|
|
History:
|
|
|
|
Created July 2001 - JamieHun
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
int ParseInfContext::LoadSourceDisksFiles()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine all source media information (as of right now, we don't need
|
|
target disk information)
|
|
Build a per-file list of possible media/platform information
|
|
MAINTAINANCE: Keep in step with SourceDisksFiles syntax and decorations
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
static StringProdPair decorations[] = {
|
|
//
|
|
// listed from most specific to most generic
|
|
//
|
|
{ TEXT("SourceDisksFiles.x86"), PLATFORM_MASK_NTX86 },
|
|
{ TEXT("SourceDisksFiles.ia64"), PLATFORM_MASK_NTIA64 },
|
|
{ TEXT("SourceDisksFiles.amd64"), PLATFORM_MASK_NTAMD64 },
|
|
{ TEXT("SourceDisksFiles"), PLATFORM_MASK_ALL_ARCHITECTS },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
INFCONTEXT context;
|
|
int i;
|
|
DWORD platforms = pGlobalScan->Version.PlatformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN);
|
|
int res;
|
|
|
|
|
|
for(i=0;decorations[i].String;i++) {
|
|
DWORD plat = platforms & decorations[i].ProductMask;
|
|
if(plat) {
|
|
res = LoadSourceDisksFilesSection(plat,decorations[i].String);
|
|
if(res != 0) {
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ParseInfContext::LoadSourceDisksFilesSection(DWORD platform,const SafeString & section)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function for LoadSourceDisksFiles
|
|
loading information for a specific (decorated) section
|
|
|
|
Arguments:
|
|
platform - specific platform or platforms that section is valid for
|
|
section - section to load
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// see if specified section exists
|
|
// load section into TargetList of same name
|
|
//
|
|
INFCONTEXT context;
|
|
|
|
if(!SetupFindFirstLine(InfHandle,section.c_str(),NULL,&context)) {
|
|
return 0;
|
|
}
|
|
do {
|
|
SafeString filename;
|
|
SafeString name;
|
|
if(!MyGetStringField(&context,0,filename) || filename.empty()) {
|
|
pInfScan->Fail(MSG_BAD_FILENAME_ENTRY,section);
|
|
continue;
|
|
}
|
|
SourceDisksFilesEntry entry;
|
|
entry.Used = FALSE;
|
|
entry.Platform = platform;
|
|
if(!SetupGetIntField(&context,1,&entry.DiskId)) {
|
|
pInfScan->Fail(MSG_BAD_FILENAME_DISK,section,filename);
|
|
continue;
|
|
}
|
|
if(MyGetStringField(&context,2,name) && name.length()) {
|
|
entry.SubDir = name;
|
|
}
|
|
if(!SetupGetIntField(&context,8,&entry.TargetDirectory)) {
|
|
entry.TargetDirectory = 0;
|
|
}
|
|
if(!SetupGetIntField(&context,9,&entry.UpgradeDisposition)) {
|
|
entry.UpgradeDisposition = 3;
|
|
} else if((entry.UpgradeDisposition == 0) && MyGetStringField(&context,9,name) && name.empty()) {
|
|
//
|
|
// actually empty field
|
|
//
|
|
entry.UpgradeDisposition = 3;
|
|
}
|
|
if(!SetupGetIntField(&context,10,&entry.TextModeDisposition)) {
|
|
entry.TextModeDisposition = 3;
|
|
} else if((entry.TextModeDisposition == 0) && MyGetStringField(&context,10,name) && name.empty()) {
|
|
//
|
|
// actually empty field
|
|
//
|
|
entry.TextModeDisposition = 3;
|
|
}
|
|
if(MyGetStringField(&context,11,name) && name.length()) {
|
|
entry.TargetName = name;
|
|
}
|
|
if((entry.UpgradeDisposition != 3) || (entry.TextModeDisposition != 3)) {
|
|
if(entry.TargetDirectory) {
|
|
LooksLikeLayoutInf = TRUE;
|
|
} else {
|
|
pInfScan->Fail(MSG_TEXTMODE_DISPOSITION_MISSING_DIR,section,filename);
|
|
}
|
|
}
|
|
//
|
|
// is this a completely new entry for this file?
|
|
//
|
|
StringToSourceDisksFilesList::iterator sdfl = SourceDisksFiles.find(filename);
|
|
if(sdfl == SourceDisksFiles.end()) {
|
|
//
|
|
// never come across this name before (typical case)
|
|
//
|
|
SourceDisksFilesList blankList;
|
|
sdfl = SourceDisksFiles.insert(sdfl,StringToSourceDisksFilesList::value_type(filename,blankList));
|
|
SourceDisksFilesList & list = sdfl->second;
|
|
list.push_back(entry);
|
|
} else {
|
|
//
|
|
// there's already an entry for this filename
|
|
// see if this is an alternate location/info
|
|
//
|
|
SourceDisksFilesList & list = sdfl->second;
|
|
SourceDisksFilesList::iterator i;
|
|
BOOL conflict = FALSE;
|
|
BOOL duplicate = FALSE;
|
|
for(i = list.begin(); i != list.end(); i++) {
|
|
//
|
|
// existing entries
|
|
//
|
|
SourceDisksFilesEntry & e = *i;
|
|
//
|
|
// test numerics first then strings
|
|
//
|
|
if(entry.DiskId == e.DiskId &&
|
|
entry.TargetDirectory == e.TargetDirectory &&
|
|
entry.TextModeDisposition == e.TextModeDisposition &&
|
|
entry.UpgradeDisposition == e.UpgradeDisposition &&
|
|
entry.SubDir == e.SubDir &&
|
|
entry.TargetName == e.TargetName) {
|
|
//
|
|
// already listed
|
|
//
|
|
duplicate = TRUE;
|
|
break;
|
|
}
|
|
//
|
|
// the existing entry might be more specific than what we have
|
|
// eg, specific ia64, generic everything else
|
|
// so remove the flags from existing entry from mask
|
|
//
|
|
entry.Platform &= ~ e.Platform;
|
|
if(pInfScan->Pedantic()) {
|
|
conflict = TRUE;
|
|
}
|
|
}
|
|
if (duplicate) {
|
|
//
|
|
// duplicate/compatible entry listed
|
|
//
|
|
i->Platform |= entry.Platform;
|
|
} else {
|
|
//
|
|
// no duplicate or compatible
|
|
//
|
|
if (conflict) {
|
|
//
|
|
// different source listings for different platforms
|
|
// might be an error
|
|
//
|
|
pInfScan->Fail(MSG_SOURCE_CONFLICT,section,filename);
|
|
}
|
|
list.push_back(entry);
|
|
}
|
|
}
|
|
|
|
} while (SetupFindNextLine(&context,&context));
|
|
return 0;
|
|
}
|
|
|
|
int ParseInfContext::QuerySourceFile(DWORD platforms,const SafeString & section,const SafeString & source,SourceDisksFilesList & Target)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
See also InstallScan::QuerySourceFile
|
|
Determine list of possible source entries for given source file
|
|
This can be zero (bad layout)
|
|
1 (typical)
|
|
>1 (multiple targets)
|
|
WARNING! This shadows SetupAPI implementation always subject to change
|
|
MAINTAINANCE: keep in step with SetupAPI
|
|
|
|
Arguments:
|
|
platforms - bitmap list of platforms we're interested in
|
|
section - name of the copy section or install section (for error reporting only)
|
|
source - name of source file
|
|
Target - returned list of source media information
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// return list of entries matching source file
|
|
//
|
|
|
|
StringToSourceDisksFilesList::iterator sdfl = SourceDisksFiles.find(source);
|
|
|
|
if(sdfl == SourceDisksFiles.end()) {
|
|
//
|
|
// not found
|
|
// don't fail here, caller will try a few more alternatives
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
SourceDisksFilesList & list = sdfl->second;
|
|
SourceDisksFilesList::iterator i;
|
|
|
|
for(i = list.begin(); i != list.end(); i++) {
|
|
//
|
|
// existing entries
|
|
//
|
|
SourceDisksFilesEntry & e = *i;
|
|
if ((e.Platform & platforms) == 0) {
|
|
continue;
|
|
}
|
|
Target.push_back(e);
|
|
}
|
|
|
|
if(!Target.size()) {
|
|
pInfScan->Fail(MSG_SOURCE_NOT_LISTED_PLATFORM,section,source);
|
|
//
|
|
// indicate we errored out
|
|
//
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ParseInfContext::LoadWinntDirectories(IntToString & Target)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load the Layout.INF specific [WinntDirectories]
|
|
to aid in textmode vs setupapi consistency
|
|
WARNING! This relies heavily on current textmode implementation subject to change
|
|
MAINTAINANCE: Keep in step with textmode
|
|
|
|
Arguments:
|
|
Target - initialized with <id> to <subdirectory> mapping
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
if(pGlobalScan->IgnoreErrors && !pGlobalScan->TargetsToo) {
|
|
//
|
|
// don't bother if we're not interested in errors
|
|
// (unless we want target information)
|
|
//
|
|
return 0;
|
|
}
|
|
INFCONTEXT context;
|
|
|
|
if(!SetupFindFirstLine(InfHandle,TEXT("WinntDirectories"),NULL,&context)) {
|
|
return 0;
|
|
}
|
|
do {
|
|
int index;
|
|
TCHAR path[MAX_PATH];
|
|
if(SetupGetIntField(&context,0,&index) && index) {
|
|
if(!SetupGetStringField(&context,1,path,MAX_PATH,NULL) || !path[0]) {
|
|
continue;
|
|
}
|
|
_tcslwr(path);
|
|
IntToString::iterator i = Target.find(index);
|
|
if(i == Target.end()) {
|
|
Target[index] = path;
|
|
} else {
|
|
if(i->second.compare(path)!=0) {
|
|
//
|
|
// mismatch
|
|
//
|
|
pInfScan->Fail(MSG_WINNT_DIRECTORY_CONFLICT,i->second,path);
|
|
}
|
|
}
|
|
}
|
|
} while (SetupFindNextLine(&context,&context));
|
|
return 0;
|
|
}
|
|
|
|
int ParseInfContext::LoadDestinationDirs()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load the [DestinationDirs]
|
|
Also uses pGlobalScan->GlobalDirectories to remap certain ID's
|
|
WARNING! This relies heavily on current SetupAPI and textmode implementations subject to change
|
|
MAINTAINANCE: Keep in step with textmode vs SetupAPI directory ID's
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
if(pGlobalScan->IgnoreErrors && !pGlobalScan->TargetsToo) {
|
|
//
|
|
// don't bother if we're not interested in errors
|
|
// (unless we want target information)
|
|
//
|
|
return 0;
|
|
}
|
|
INFCONTEXT context;
|
|
|
|
if(!SetupFindFirstLine(InfHandle,TEXT("DestinationDirs"),NULL,&context)) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//
|
|
// MAINTAINANCE:
|
|
// this table needs to correlate to LAYOUT.INX
|
|
//
|
|
// process [DestinationDirs] if there is one
|
|
// <section> = dirid,subdir
|
|
//
|
|
// normalize following dirid's:
|
|
// 10,subdir - as is
|
|
// 11,subdir - 10,system32\subdir
|
|
// 12,subdir - 10,system32\drivers\subdir
|
|
// 17,subdir - 10,inf\subdir
|
|
// 18,subdir -
|
|
|
|
TCHAR section[LINE_LEN];
|
|
int dirid = 0;
|
|
TCHAR subdir[MAX_PATH];
|
|
int global_equiv[] = {
|
|
0,0,0,0,0,0,0,0,0,0,0, // 0-10
|
|
2, // 11 - system32
|
|
4, // 12 - system32/drivers
|
|
0,0,0,0, // 13-16
|
|
20, // 17 - inf
|
|
21, // 18 - help
|
|
0, // 19
|
|
22, // 20 - fonts
|
|
0
|
|
};
|
|
|
|
do {
|
|
int index;
|
|
TCHAR path[MAX_PATH];
|
|
if(!SetupGetStringField(&context,0,section,LINE_LEN,NULL) || !section[0]) {
|
|
continue;
|
|
}
|
|
_tcslwr(section);
|
|
if(!SetupGetIntField(&context,1,&dirid) || dirid == 0) {
|
|
pInfScan->Fail(MSG_DIRID_NOT_SPECIFIED,section);
|
|
dirid = 0;
|
|
}
|
|
if(!SetupGetStringField(&context,2,subdir,MAX_PATH,NULL)) {
|
|
subdir[0] = TEXT('\0');
|
|
}
|
|
_tcslwr(subdir);
|
|
TargetDirectoryEntry entry;
|
|
entry.Used = false;
|
|
entry.DirId = dirid;
|
|
entry.SubDir = subdir;
|
|
//
|
|
// certain dirid have a global equiv, remap
|
|
//
|
|
if(dirid>0 && dirid < ASIZE(global_equiv)) {
|
|
int equiv = global_equiv[dirid];
|
|
if(equiv) {
|
|
IntToString::iterator i = pGlobalScan->GlobalDirectories.find(equiv);
|
|
if(i != pGlobalScan->GlobalDirectories.end()) {
|
|
//
|
|
// we have a mapping relative to dirID 10.
|
|
//
|
|
entry.DirId = 10;
|
|
entry.SubDir = PathConcat(i->second,subdir);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// make a note
|
|
//
|
|
DestinationDirectories[section] = entry;
|
|
|
|
} while (SetupFindNextLine(&context,&context));
|
|
|
|
//
|
|
// now determine default
|
|
//
|
|
CopySectionToTargetDirectoryEntry::iterator tde = DestinationDirectories.find(TEXT("defaultdestdir"));
|
|
if(tde != DestinationDirectories.end()) {
|
|
DefaultTargetDirectory = tde;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ParseInfContext::PartialCleanup()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup information not required by results phase
|
|
In particular, INF handle must ALWAYS be closed
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
if(InfHandle != INVALID_HANDLE_VALUE) {
|
|
SetupCloseInfFile(InfHandle);
|
|
InfHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
SourceDisksFiles.clear();
|
|
CompletedCopySections.clear();
|
|
}
|