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.
506 lines
12 KiB
506 lines
12 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
For Internal use only!
|
|
|
|
Module Name:
|
|
|
|
INFSCAN
|
|
globals.cpp
|
|
|
|
Abstract:
|
|
|
|
Global functions (ie, not part of any class)
|
|
|
|
History:
|
|
|
|
Created July 2001 - JamieHun
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <initguid.h>
|
|
#include <new.h>
|
|
|
|
int
|
|
__cdecl
|
|
my_new_handler(size_t)
|
|
{
|
|
throw std::bad_alloc();
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
main(int argc,char *argv[])
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main point of entry
|
|
Defer to GlobalScan::ParseArgs and GlobalScan::Scan
|
|
|
|
Arguments:
|
|
|
|
argc - # of arguments passed on command line
|
|
argv - arguments passed on command line
|
|
|
|
Return Value:
|
|
|
|
0 on success
|
|
1 no files
|
|
2 bad usage
|
|
3 fatal error (out of memory)
|
|
|
|
stdout -- scan errors
|
|
stderr -- trace/fatal errors
|
|
|
|
--*/
|
|
{
|
|
int res;
|
|
_PNH _old_new_handler = _set_new_handler(my_new_handler);
|
|
int _old_new_mode = _set_new_mode(1);
|
|
|
|
try {
|
|
GlobalScan scanner;
|
|
|
|
res = scanner.ParseArgs(argc,argv);
|
|
if(res != 0) {
|
|
return res;
|
|
}
|
|
res = scanner.Scan();
|
|
|
|
} catch(bad_alloc &) {
|
|
res = 3;
|
|
}
|
|
if(res == 3) {
|
|
fprintf(stderr,"Out of memory!\n");
|
|
}
|
|
_set_new_mode(_old_new_mode);
|
|
_set_new_handler(_old_new_handler);
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
void FormatToStream(FILE * stream,DWORD fmt,DWORD flags,...)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format text to stream using a particular msg-id fmt
|
|
Used for displaying localizable messages
|
|
|
|
Arguments:
|
|
|
|
stream - file stream to output to, stdout or stderr
|
|
fmt - message id
|
|
... - parameters %1...
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
va_list arglist;
|
|
LPTSTR locbuffer = NULL;
|
|
DWORD count;
|
|
|
|
va_start(arglist, flags);
|
|
count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ALLOCATE_BUFFER|flags,
|
|
NULL,
|
|
fmt,
|
|
0, // LANGID
|
|
(LPTSTR) &locbuffer,
|
|
0, // minimum size of buffer
|
|
(flags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
|
|
? reinterpret_cast<va_list*>(va_arg(arglist,DWORD_PTR*))
|
|
: &arglist);
|
|
|
|
if(locbuffer) {
|
|
if(count) {
|
|
int c;
|
|
int back = 0;
|
|
while(((c = *CharPrev(locbuffer,locbuffer+count)) == TEXT('\r')) ||
|
|
(c == TEXT('\n'))) {
|
|
count--;
|
|
back++;
|
|
}
|
|
if(back) {
|
|
locbuffer[count++] = TEXT('\n');
|
|
locbuffer[count] = TEXT('\0');
|
|
}
|
|
_fputts(locbuffer,stream);
|
|
}
|
|
LocalFree(locbuffer);
|
|
}
|
|
}
|
|
|
|
PTSTR CopyString(PCTSTR arg, int extra)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a string into a newly allocated buffer
|
|
|
|
Arguments:
|
|
|
|
arg - string to copy
|
|
extra - extra characters to allow for
|
|
|
|
Return Value:
|
|
|
|
TCHAR[] buffer, delete with "delete []"
|
|
|
|
--*/
|
|
{
|
|
int max = _tcslen(arg)+1;
|
|
PTSTR chr = new TCHAR[max+extra]; // may throw bad_alloc
|
|
memcpy(chr,arg,max*sizeof(TCHAR));
|
|
return chr;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
PTSTR CopyString(PCSTR arg, int extra)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a string into a newly allocated buffer
|
|
Converting from ANSI to UNICODE
|
|
|
|
Arguments:
|
|
|
|
arg - string to copy
|
|
extra - extra characters to allow for
|
|
|
|
Return Value:
|
|
|
|
TCHAR[] buffer, delete with "delete []"
|
|
|
|
--*/
|
|
{
|
|
|
|
int max = strlen(arg)+1;
|
|
PTSTR chr = new TCHAR[max+extra]; // may throw bad_alloc
|
|
if(!MultiByteToWideChar(CP_ACP,0,arg,max,chr,max)) {
|
|
delete [] chr;
|
|
return NULL;
|
|
}
|
|
return chr;
|
|
}
|
|
#else
|
|
PTSTR CopyString(PCWSTR arg, int extra)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a string into a newly allocated buffer
|
|
Converting from UNICODE to ANSI
|
|
|
|
Arguments:
|
|
|
|
arg - string to copy
|
|
extra - extra characters to allow for
|
|
|
|
Return Value:
|
|
|
|
TCHAR[] buffer, delete with "delete []"
|
|
|
|
--*/
|
|
{
|
|
#error CopyString(PCWSTR arg,int extra)
|
|
}
|
|
#endif
|
|
|
|
int GetFullPathName(const SafeString & given,SafeString & target)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obtain full pathname
|
|
|
|
Arguments:
|
|
|
|
given - path to convert
|
|
target - full pathname on success, same as given on error
|
|
|
|
Return Value:
|
|
|
|
0 on success, !=0 on failure
|
|
|
|
--*/
|
|
{
|
|
DWORD len = GetFullPathName(given.c_str(),0,NULL,NULL);
|
|
if(len == 0) {
|
|
if(&target != &given) {
|
|
target = given;
|
|
}
|
|
return -1;
|
|
}
|
|
PTSTR chr = new TCHAR[len];
|
|
if(!chr) {
|
|
if(&target != &given) {
|
|
target = given;
|
|
}
|
|
return -1;
|
|
}
|
|
DWORD alen = GetFullPathName(given.c_str(),len,chr,NULL);
|
|
if((alen == 0) || (alen>len)) {
|
|
if(&target != &given) {
|
|
target = given;
|
|
}
|
|
delete [] chr;
|
|
return -1;
|
|
}
|
|
target = chr;
|
|
delete [] chr;
|
|
return 0;
|
|
}
|
|
|
|
SafeString PathConcat(const SafeString & path,const SafeString & tail)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Combine path and tail, returning newly combined string
|
|
inserts/removes path seperator if needed
|
|
|
|
Arguments:
|
|
|
|
path - first part
|
|
tail - last part
|
|
|
|
Return Value:
|
|
|
|
appended path
|
|
|
|
--*/
|
|
{
|
|
if(!path.length()) {
|
|
return tail;
|
|
}
|
|
if(!tail.length()) {
|
|
return path;
|
|
}
|
|
PCTSTR path_p = path.c_str();
|
|
int path_l = path.length();
|
|
int c = *CharPrev(path_p,path_p+path_l);
|
|
bool addslash = false;
|
|
bool takeslash = false;
|
|
if((c != TEXT('\\')) && (c != TEXT('/'))) {
|
|
addslash = true;
|
|
}
|
|
c = tail[0];
|
|
if((c == TEXT('\\')) || (c == TEXT('/'))) {
|
|
if(addslash) {
|
|
return path+tail;
|
|
} else {
|
|
return path+tail.substr(1);
|
|
}
|
|
} else {
|
|
if(addslash) {
|
|
return path+SafeString(TEXT("\\"))+tail;
|
|
} else {
|
|
return path+tail;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Usage(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Help information
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
_tprintf(TEXT("Usage: INFSCAN [/B <textfile>] [/C <output>] [/D] [/E <output>] [/F <filter>] [/G] [/I] {/N <infname>} {/O <dir>} [/P] [Q <output>] [/R] [/S <output>] [/T <count>] [/V <version>] [/W <textfile>] [/X <textfile>] [/Y] [/Z] [SourcePath]\n\n"));
|
|
_tprintf(TEXT("Options:\n\n"));
|
|
_tprintf(TEXT("/B <textfile> (build special) Filter /E based on a list of \"unchanged\" files\n"));
|
|
_tprintf(TEXT(" variation /B1 - based on copied files only\n"));
|
|
_tprintf(TEXT(" variation /B2 - based on INF files only\n"));
|
|
_tprintf(TEXT("/C <output> Create INF filter/report based on errors\n"));
|
|
_tprintf(TEXT("/D Determine non-driver installation sections\n"));
|
|
_tprintf(TEXT("/E <output> Create a DeviceToInf filter INF\n"));
|
|
_tprintf(TEXT("/F <filter> Filter based on INF: FilterInfPath\n"));
|
|
_tprintf(TEXT("/G Generate Pnfs first (see also /Z)\n"));
|
|
_tprintf(TEXT("/I Ignore errors (for when generating file list)\n"));
|
|
_tprintf(TEXT("/N <infname> Specify single INF name (/N may be used multiple times)\n"));
|
|
_tprintf(TEXT("/O <dir> Specify an override directory (/O may be used multiple times and parsed in order)\n"));
|
|
_tprintf(TEXT("/P Pedantic mode (show potential problems too)\n"));
|
|
_tprintf(TEXT("/Q <output> Source+Target copied files list (filtered by layout.inf) see also /S\n"));
|
|
_tprintf(TEXT("/R Trace (list all INF's)\n"));
|
|
_tprintf(TEXT("/S <output> Source copied files list (filtered by layout.inf) see also /Q\n"));
|
|
_tprintf(TEXT("/T <count> Specify number of threads to use\n"));
|
|
_tprintf(TEXT("/V <version> Version (eg NTx86.5.1)\n"));
|
|
_tprintf(TEXT("/W <textfile> List of files to include (alternative to /N)\n"));
|
|
_tprintf(TEXT("/X <textfile> List of files to exclude (same format as /W) overrides later includes\n"));
|
|
_tprintf(TEXT("/Y Don't check per-inf [SourceDisksFiles*]\n"));
|
|
_tprintf(TEXT("/Z Generate Pnfs and quit (see also /G)\n"));
|
|
_tprintf(TEXT("/? or /H Display brief usage message\n"));
|
|
}
|
|
|
|
|
|
|
|
bool MyGetStringField(PINFCONTEXT Context,DWORD FieldIndex,SafeString & result,bool downcase)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get a string field from an INF
|
|
downcase it if flag indicates it needs to be (typical case)
|
|
|
|
Arguments:
|
|
Context - from SetupFindFirstLine/SetupFindNextLine etc
|
|
FieldIndex - 0 for key, 1-n for parameter
|
|
result - string obtained
|
|
downcase - true (typical) to return result as lower-case
|
|
|
|
Return Value:
|
|
TRUE if success (result modified), FALSE otherwise (result left untouched)
|
|
|
|
--*/
|
|
{
|
|
TCHAR Buf[MAX_INF_STRING_LENGTH];
|
|
if(SetupGetStringField(Context,FieldIndex,Buf,MAX_INF_STRING_LENGTH,NULL)) {
|
|
if(downcase) {
|
|
_tcslwr(Buf);
|
|
}
|
|
result = Buf;
|
|
return true;
|
|
} else {
|
|
//
|
|
// leave result as is, allowing default capability
|
|
//
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SafeString QuoteIt(const SafeString & val)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Quote a string in such a way that it will be correctly parsed by SetupAPI
|
|
|
|
Arguments:
|
|
val - unquoted string
|
|
|
|
Return Value:
|
|
quoted string
|
|
|
|
--*/
|
|
{
|
|
if(val.empty()) {
|
|
//
|
|
// don't quote empty string
|
|
//
|
|
return val;
|
|
}
|
|
basic_ostringstream<TCHAR> result;
|
|
result << TEXT("\"");
|
|
LPCTSTR p = val.c_str();
|
|
LPCTSTR q;
|
|
while((q = wcsstr(p,TEXT("%\""))) != NULL) {
|
|
TCHAR c = *q;
|
|
q++; // include the special char
|
|
result << SafeString(p,q-p) << c; // write what we have so far, double up the special char
|
|
p = q;
|
|
}
|
|
result << p << TEXT("\"");
|
|
return result.str();
|
|
}
|
|
|
|
int GeneratePnf(const SafeString & pnf)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a single PNF
|
|
|
|
Arguments:
|
|
none
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
HINF hInf;
|
|
|
|
hInf = SetupOpenInfFile(pnf.c_str(),
|
|
NULL,
|
|
INF_STYLE_WIN4 | INF_STYLE_CACHE_ENABLE,
|
|
NULL
|
|
);
|
|
|
|
if(hInf != INVALID_HANDLE_VALUE) {
|
|
SetupCloseInfFile(hInf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Write(HANDLE hFile,const SafeStringW & str)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a string to specified file, converting UNICODE to ANSI
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
int len = WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),NULL,0,NULL,NULL);
|
|
if(!len) {
|
|
return;
|
|
}
|
|
LPSTR buf = new CHAR[len];
|
|
if(!buf) {
|
|
return;
|
|
}
|
|
int nlen = WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),buf,len,NULL,NULL);
|
|
if(!nlen) {
|
|
delete [] buf;
|
|
return;
|
|
}
|
|
DWORD written;
|
|
BOOL f = WriteFile(hFile,buf,len,&written,NULL);
|
|
delete [] buf;
|
|
}
|
|
|
|
void Write(HANDLE hFile,const SafeStringA & str)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a string to specified file as-is
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Return Value:
|
|
0 on success
|
|
|
|
--*/
|
|
{
|
|
DWORD written;
|
|
BOOL f = WriteFile(hFile,str.c_str(),str.length(),&written,NULL);
|
|
}
|
|
|