Windows2003-3790/base/ntsetup/hwdb/hwdb.c
2020-09-30 16:53:55 +02:00

1822 lines
45 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
hwdb.c
Abstract:
PNP device manipulation routines.
Adapted from the win95upg project.
Author:
Ovidiu Temereanca (ovidiut) 02-Jul-2000 Initial implementation
Revision History:
--*/
#include "pch.h"
#include "hwdbp.h"
#define DBG_HWDB "Hwdb"
static HANDLE g_hHwdbHeap = NULL;
static PCSTR g_TempDir = NULL;
#define HWCOMPDAT_SIGNATURE "HwCompDat-v2"
#define MAX_PNPID 1024
#ifdef DEBUG
extern BOOL g_DoLog;
extern BOOL g_ResetLog;
#endif
typedef struct {
HANDLE File;
HASHITEM InfFileOffset;
BOOL UnsupportedDevice;
PHWDB Hwbd;
} SAVE_ENUM_PARAMS, *PSAVE_ENUM_PARAMS;
PCWSTR
pConvertMultiSzToUnicode (
IN PCSTR MultiSz
)
{
UINT logChars;
if (!MultiSz) {
return NULL;
}
logChars = MultiSzSizeInCharsA (MultiSz);
return DbcsToUnicodeN (NULL, MultiSz, logChars);
}
//
// REM - g_ExcludedInfs was removed because hwdb will be used for any 3rd party driver files
// and we need to make suer ALL infs are scanned
//
//
// Implementation
//
BOOL
WINAPI
MigUtil_Entry (
HINSTANCE hInstance,
DWORD dwReason,
LPVOID lpReserved
);
HINSTANCE g_hInst;
HANDLE g_hHeap;
BOOL
HwdbpInitialized (
VOID
)
{
return g_hHwdbHeap != NULL;
}
BOOL
HwdbpInitialize (
VOID
)
{
BOOL b = TRUE;
//
// only initialize data once
//
MYASSERT (!g_hHwdbHeap);
g_hHwdbHeap = HeapCreate (0, 65536, 0);
if (!g_hHwdbHeap) {
return FALSE;
}
#ifdef DEBUG
g_DoLog = TRUE;
g_ResetLog = TRUE;
#endif
g_hHeap = g_hHwdbHeap;
if (!g_hInst) {
//
// If DllMain didn't set this, then set it now
//
g_hInst = GetModuleHandle (NULL);
}
if (!MigUtil_Entry (g_hInst, DLL_PROCESS_ATTACH, NULL)) {
b = FALSE;
}
if (!b) {
HwdbpTerminate ();
}
return b;
}
VOID
HwdbpTerminate (
VOID
)
{
HwdbpSetTempDir (NULL);
MigUtil_Entry (g_hInst, DLL_PROCESS_DETACH, NULL);
if (g_hHwdbHeap) {
HeapDestroy (g_hHwdbHeap);
g_hHwdbHeap = NULL;
}
}
BOOL
pReadDword (
IN HANDLE File,
OUT PDWORD Data
)
/*++
Routine Description:
pReadDword reads the next DWORD at the current file position of File.
Arguments:
File - Specifies file to read
Data - Receives the DWORD
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
Call GetLastError for additional failure information.
--*/
{
DWORD BytesRead;
return ReadFile (File, Data, sizeof (DWORD), &BytesRead, NULL) &&
BytesRead == sizeof (DWORD);
}
BOOL
pReadWord (
IN HANDLE File,
OUT PWORD Data
)
/*++
Routine Description:
pReadWord reads the next WORD at the current file position of File.
Arguments:
File - Specifies file to read
Data - Receive s the WORD
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
Call GetLastError for additional failure information.
--*/
{
DWORD BytesRead;
return ReadFile (File, Data, sizeof (WORD), &BytesRead, NULL) &&
BytesRead == sizeof (WORD);
}
BOOL
pReadString (
IN HANDLE File,
OUT PSTR Buf,
IN DWORD BufSizeInBytes
)
/*++
Routine Description:
pReadString reads a WORD length from File, and then reads in the
string from File.
Arguments:
File - Specifies file to read
Buf - Receives the zero-terminated string
BufSizeInBytes - Specifies the size of Buf in bytes
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
This function will fail if the string is larger than Buf.
Call GetLastError for additional failure information.
--*/
{
DWORD BytesRead;
WORD Length;
MYASSERT (BufSizeInBytes);
if (!BufSizeInBytes) {
return FALSE;
}
if (!pReadWord (File, &Length)) {
return FALSE;
}
if ((Length + 1 ) * sizeof (CHAR) > BufSizeInBytes) {
return FALSE;
}
if (Length) {
if (!ReadFile (File, Buf, Length, &BytesRead, NULL) ||
Length != BytesRead
) {
return FALSE;
}
}
Buf[Length] = 0;
return TRUE;
}
BOOL
pWriteDword (
IN HANDLE File,
IN DWORD Val
)
/*++
Routine Description:
pWriteDword writes the specified DWORD value to File.
Arguments:
File - Specifies file to write to
Val - Specifies value to write
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
Call GetLastError for additional failure information.
--*/
{
DWORD bytesWritten;
return WriteFile (File, &Val, sizeof (Val), &bytesWritten, NULL) &&
bytesWritten == sizeof (Val);
}
BOOL
pWriteWord (
IN HANDLE File,
IN WORD Val
)
/*++
Routine Description:
pWriteWord writes the specified WORD vlue to File.
Arguments:
File - Specifies file to write to
Val - Specifies value to write
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
Call GetLastError for additional failure information.
--*/
{
DWORD bytesWritten;
return WriteFile (File, &Val, sizeof (Val), &bytesWritten, NULL) &&
bytesWritten == sizeof (Val);
}
BOOL
pWriteString (
IN HANDLE File,
IN PCSTR String
)
/*++
Routine Description:
pWriteString writes a string to a File
Arguments:
File - Specifies file to write to
String - Specifies the zero-terminated string
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
Call GetLastError for additional failure information.
--*/
{
DWORD bytesWritten;
DWORD Length;
PCSTR End;
BOOL b = TRUE;
Length = lstrlenA (String);
if (Length > 0xffff) {
SetLastError (ERROR_INTERNAL_ERROR);
DEBUGMSGA ((DBG_ERROR, "pWriteString: string too long!"));
return FALSE;
}
b = pWriteWord (File, (WORD)Length);
if (b && Length) {
b = WriteFile (File, String, Length, &bytesWritten, NULL) &&
Length == bytesWritten;
}
return b;
}
PHWDB
HwdbpOpen (
IN PCSTR DatabaseFile OPTIONAL
)
{
CHAR buffer[MAX_PATH];
CHAR infFile[MAX_MBCHAR_PATH];
CHAR pnpId[1024];
CHAR sig[sizeof (HWCOMPDAT_SIGNATURE)];
DWORD rc;
HANDLE file = INVALID_HANDLE_VALUE;
PHWDB phwdb;
DWORD BytesRead;
HASHITEM infOffset, result;
BOOL b = FALSE;
__try {
phwdb = (PHWDB) MemAlloc (g_hHwdbHeap, 0, sizeof (*phwdb));
if (!phwdb) {
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
__leave;
}
ZeroMemory (phwdb, sizeof (*phwdb));
//
// Create hash tables
//
phwdb->InfFileTable = HtAlloc ();
phwdb->PnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
phwdb->UnsupPnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
if (!phwdb->InfFileTable || !phwdb->PnpIdTable || !phwdb->UnsupPnpIdTable) {
__leave;
}
if (DatabaseFile) {
if (!GetFullPathNameA (DatabaseFile, ARRAYSIZE(buffer), buffer, NULL)) {
__leave;
}
//
// Try to open the file
//
file = CreateFileA (
buffer,
GENERIC_READ,
FILE_SHARE_READ, // share for read access
NULL, // no security attribs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL // no template
);
if (file == INVALID_HANDLE_VALUE) {
__leave;
}
//
// Look at the signature
//
ZeroMemory (sig, sizeof(sig));
if (!ReadFile (file, sig, sizeof (HWCOMPDAT_SIGNATURE) - 1, &BytesRead, NULL) ||
lstrcmpA (HWCOMPDAT_SIGNATURE, sig)
) {
SetLastError (ERROR_BAD_FORMAT);
__leave;
}
//
// Get INF checksum
//
if (!pReadDword (file, &phwdb->Checksum)) {
SetLastError (ERROR_BAD_FORMAT);
__leave;
}
//
// Read in all PNP IDs
//
for (;;) {
//
// Get INF file name. If empty, we are done.
//
if (!pReadString (file, infFile, sizeof (infFile))) {
SetLastError (ERROR_BAD_FORMAT);
__leave;
}
if (*infFile == 0) {
break;
}
infOffset = HtAddStringA (phwdb->InfFileTable, infFile);
if (!infOffset) {
__leave;
}
//
// Read in all PNP IDs for the INF
//
for (;;) {
//
// Get the PNP ID. If empty, we are done.
//
if (!pReadString (file, pnpId, sizeof (pnpId))) {
SetLastError (ERROR_BAD_FORMAT);
__leave;
}
if (*pnpId == 0) {
break;
}
//
// Add to hash table
//
if (*pnpId == '!') {
result = HtAddStringExA (phwdb->UnsupPnpIdTable, pnpId + 1, &infOffset, CASE_INSENSITIVE);
} else {
result = HtAddStringExA (phwdb->PnpIdTable, pnpId, &infOffset, CASE_INSENSITIVE);
}
if (!result) {
__leave;
}
}
}
}
b = TRUE;
}
__finally {
rc = GetLastError ();
if (file != INVALID_HANDLE_VALUE) {
CloseHandle (file);
}
if (!b && phwdb) {
if (phwdb->InfFileTable) {
HtFree (phwdb->InfFileTable);
}
if (phwdb->PnpIdTable) {
HtFree (phwdb->PnpIdTable);
}
if (phwdb->UnsupPnpIdTable) {
HtFree (phwdb->UnsupPnpIdTable);
}
MemFree (g_hHwdbHeap, 0, phwdb);
}
SetLastError (rc);
}
return phwdb;
}
/*
BOOL
pWriteHashTableString (
IN HASHTABLE HashTable,
IN HASHITEM Index,
IN PCSTR String,
IN PVOID ExtraData,
IN UINT ExtraDataSize,
IN LPARAM lParam
)
{
MYASSERT (String && *String);
return pWriteString ((HANDLE)lParam, String);
}
*/
BOOL
pSavePnpID (
IN HASHTABLE Table,
IN HASHITEM StringId,
IN PCSTR String,
IN PVOID ExtraData,
IN UINT ExtraDataSize,
IN LPARAM lParam
)
/*++
Routine Description:
pSavePnpID is a string table callback function that writes a PNP
ID to the file indicated in the params struct (the lParam argument).
This function only writes PNP IDs for a specific INF file (indicated
by the ExtraData arg).
Arguments:
Table - Specifies table being enumerated
StringId - Specifies offset of string in Table
String - Specifies string being enumerated
ExtraData - Specifies a pointer to a LONG that holds the INF ID
to enumerate. The PNP ID's INF ID must match this
parameter.
lParam - Specifies a pointer to a SAVE_ENUM_PARAMS struct
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
--*/
{
PSAVE_ENUM_PARAMS params;
CHAR bangString[MAX_PNPID + 2];
BOOL b = TRUE;
params = (PSAVE_ENUM_PARAMS) lParam;
if (*(HASHITEM UNALIGNED*)ExtraData == params->InfFileOffset) {
//
// Write this PNP ID to the file
//
if (params->UnsupportedDevice) {
bangString[0] = '!';
b = SUCCEEDED (StringCchCopyA (bangString + 1, ARRAYSIZE(bangString) - 1, String)) &&
pWriteString (params->File, bangString);
} else {
b = pWriteString (params->File, String);
}
}
return b;
}
BOOL
pSaveInfWithPnpIDList (
IN HASHTABLE Table,
IN HASHITEM StringId,
IN PCSTR String,
IN PVOID ExtraData,
IN UINT ExtraDataSize,
IN LPARAM lParam
)
/*++
Routine Description:
pSaveInfWithPnpIDList is a string table callback function and is called for
each INF in g_InfFileTable.
This routine writes the name of the INF to disk, and then enumerates
the PNP IDs for the INF, writing them to disk.
The PNP ID list is terminated with an empty string.
Arguments:
Table - Specifies g_InfFileTable
StringId - Specifies offset of String in g_InfFileTable
String - Specifies current INF file being enumerated
ExtraData - unused
ExtraDataSize - unused
lParam - Specifies a pointer to SAVE_ENUM_PARAMS struct.
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
--*/
{
PSAVE_ENUM_PARAMS params;
params = (PSAVE_ENUM_PARAMS) lParam;
params->InfFileOffset = StringId;
//
// Save the file name
//
if (!pWriteString (params->File, String)) {
return FALSE;
}
//
// Enumerate all PNP IDs
//
params->UnsupportedDevice = FALSE;
if (!EnumHashTableWithCallbackA (params->Hwbd->PnpIdTable, pSavePnpID, lParam)) {
LOGA ((LOG_ERROR, "Error while saving device list."));
return FALSE;
}
params->UnsupportedDevice = TRUE;
if (!EnumHashTableWithCallbackA (params->Hwbd->UnsupPnpIdTable, pSavePnpID, lParam)) {
LOGA ((LOG_ERROR, "Error while saving device list. (2)"));
return FALSE;
}
//
// Terminate the PNP ID list
//
if (!pWriteString (params->File, "")) {
return FALSE;
}
return TRUE;
}
BOOL
HwdbpFlush (
IN PHWDB Hwdb,
IN PCSTR OutputFile
)
{
CHAR buffer[MAX_PATH];
DWORD rc;
HANDLE file = INVALID_HANDLE_VALUE;
DWORD bytesWritten;
SAVE_ENUM_PARAMS params;
BOOL b = FALSE;
__try {
if (!OutputFile) {
SetLastError (ERROR_INVALID_PARAMETER);
__leave;
}
if (!GetFullPathNameA (OutputFile, ARRAYSIZE(buffer), buffer, NULL)) {
__leave;
}
//
// Try to open the file
//
file = CreateFileA (
OutputFile,
GENERIC_WRITE,
0, // no sharing
NULL, // no security attribs
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL // no template
);
if (file == INVALID_HANDLE_VALUE) {
__leave;
}
//
// Write the signature
//
if (!WriteFile (file, HWCOMPDAT_SIGNATURE, sizeof (HWCOMPDAT_SIGNATURE) - 1, &bytesWritten, NULL)) {
__leave;
}
//
// Store INF checksum
//
if (!pWriteDword (file, Hwdb->Checksum)) {
__leave;
}
//
// Enumerate the INF table, writing the INF file name and all PNP IDs
//
params.File = file;
params.Hwbd = Hwdb;
if (!EnumHashTableWithCallbackA (
Hwdb->InfFileTable,
pSaveInfWithPnpIDList,
(LPARAM) (&params)
)) {
DEBUGMSGA ((DBG_WARNING, "SaveDeviceList: EnumHashTableWithCallbackA returned FALSE"));
__leave;
}
//
// end with an empty string
//
pWriteString (file, "");
b = TRUE;
}
__finally {
rc = GetLastError ();
if (file != INVALID_HANDLE_VALUE) {
CloseHandle (file);
}
if (!b) {
DeleteFile (OutputFile);
}
SetLastError (rc);
}
return b;
}
BOOL
HwdbpClose (
IN PHWDB Hwdb
)
{
BOOL b = FALSE;
__try {
if (Hwdb) {
if (Hwdb->InfFileTable) {
HtFree (Hwdb->InfFileTable);
}
if (Hwdb->PnpIdTable) {
HtFree (Hwdb->PnpIdTable);
}
if (Hwdb->UnsupPnpIdTable) {
HtFree (Hwdb->UnsupPnpIdTable);
}
MemFree (g_hHwdbHeap, 0, Hwdb);
b = TRUE;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
}
return b;
}
BOOL
HwpIsValidInfName (
IN PCSTR FileName,
OUT PSTR UncompressedFileName,
IN DWORD BufferSizeInChars
)
{
PSTR p;
PCSTR* q;
PCSTR comparationName;
if (!FileName || *FileName == 0) {
MYASSERT (FALSE);
return FALSE;
}
if (FAILED (StringCchCopyA (UncompressedFileName, BufferSizeInChars, FileName))) {
return FALSE;
}
p = our_mbsdec (UncompressedFileName, GetEndOfStringA (UncompressedFileName));
if (!p) {
return FALSE;
}
if (*p == '_') {
*p = 'f';
comparationName = UncompressedFileName;
} else {
if (_mbctolower (_mbsnextc (p)) != 'f') {
return FALSE;
}
*UncompressedFileName = 0;
comparationName = FileName;
}
return TRUE;
}
BOOL
HwpAddPnpIdsInInf (
IN PCSTR InfPath,
IN OUT PHWDB Hwdb,
IN PCSTR SourceDirectory,
IN PCSTR InfFilename,
IN HWDBAPPENDINFSCALLBACKA Callback, OPTIONAL
IN PVOID CallbackContext, OPTIONAL
IN BOOL CallbackIsUnicode
)
/*++
Routine Description:
HwpAddPnpIdsInInf scans an NT INF and places all hardware device
IDs in the PNP string table.
Arguments:
InfPath - The path to an INF file
Hwdb - Database to append PNPIDs to
Return Value:
TRUE if the function completes successfully, or FALSE if it fails.
Call GetLastError for additional failure information.
--*/
{
HINF inf;
INFCONTEXT is;
INFCONTEXT isMfg;
INFCONTEXT isDev;
CHAR manufacturer[2048];
CHAR devSection[2048];
CHAR pnpId[2048];
BOOL unsupportedDevice;
PSTR AppendPos;
CHAR trimmedPnpId[512];
CHAR field[12];
PCSTR p;
LONG rc;
BOOL b;
PCSTR fileName;
PCWSTR uInfPath = NULL;
PCWSTR uSourceDirectory = NULL;
PCWSTR uInfFilename = NULL;
HASHITEM infOffset = NULL;
BOOL result = FALSE;
//
// Determine if this is an NT4 INF
//
inf = SetupOpenInfFileA (InfPath, NULL, INF_STYLE_WIN4, NULL);
if (inf == INVALID_HANDLE_VALUE) {
DEBUGMSGA ((DBG_ERROR, "HwpAddPnpIdsInInf: SetupOpenInfFileA (%s) failed", InfPath));
return FALSE;
}
DEBUGMSGA ((DBG_HWDB, "HwpAddPnpIdsInInf: analyzing %s", InfPath));
__try {
//
// Enumerate [Manufacturer] section
//
if (SetupFindFirstLineA (inf, "Manufacturer", NULL, &is)) {
do {
//
// Get the manufacturer name
//
if (!SetupGetLineTextA (&is, NULL, NULL, NULL, manufacturer, ARRAYSIZE(manufacturer), NULL)) {
DEBUGMSGA ((
DBG_ERROR,
"HwpAddPnpIdsInInf: SetupGetLineText failed at line %u in [Manufacturer]",
is.Line
));
__leave;
}
//
// Enumerate the devices listed in the manufacturer's section,
// looking for PnpId
//
if (!SetupFindFirstLineA (inf, manufacturer, NULL, &isMfg)) {
rc = GetLastError();
//
// if section not found, move on to next manufacturer
//
if (rc == ERROR_SECTION_NOT_FOUND || rc == ERROR_LINE_NOT_FOUND) {
DEBUGMSGA ((
DBG_HWDB,
"HwpAddPnpIdsInInf: manufacturer %s section does not exist",
manufacturer
));
continue;
}
DEBUGMSGA ((
DBG_ERROR,
"HwpAddPnpIdsInInf: error searching for lines in [%s]",
manufacturer
));
__leave;
}
do {
if (!SetupGetStringFieldA (&isMfg, 1, devSection, ARRAYSIZE(devSection), NULL)) {
DEBUGMSGA ((
DBG_HWDB,
"HwpAddPnpIdsInInf: error retrieving first field in line %u in [%s]",
isMfg.Line,
devSection
));
continue;
}
//
// Try platform-specific section first, then section.NT, then section
//
AppendPos = GetEndOfStringA (devSection);
#if defined(_AMD64_)
if (FAILED (StringCchPrintfA (
AppendPos,
ARRAYSIZE(devSection) - (AppendPos - devSection),
TEXT(".%s"),
INFSTR_PLATFORM_NTAMD64
))) {
#elif defined(_IA64_)
if (FAILED (StringCchPrintfA (
AppendPos,
ARRAYSIZE(devSection) - (AppendPos - devSection),
TEXT(".%s"),
INFSTR_PLATFORM_NTIA64
))) {
#elif defined(_X86_)
if (FAILED (StringCchPrintfA (
AppendPos,
ARRAYSIZE(devSection) - (AppendPos - devSection),
TEXT(".%s"),
INFSTR_PLATFORM_NTX86
))) {
#else
#error "No Target Architecture"
#endif
__leave;
}
b = SetupFindFirstLineA (inf, devSection, NULL, &isDev);
if (!b) {
if (FAILED (StringCchPrintfA (
AppendPos,
ARRAYSIZE(devSection) - (AppendPos - devSection),
TEXT(".%s"),
INFSTR_PLATFORM_NT
))) {
__leave;
}
b = SetupFindFirstLineA (inf, devSection, NULL, &isDev);
if (!b) {
*AppendPos = 0;
b = SetupFindFirstLineA (inf, devSection, NULL, &isDev);
}
}
unsupportedDevice = FALSE;
if (b) {
if (SetupFindFirstLineA (inf, devSection, "DeviceUpgradeUnsupported", &isDev)) {
if (SetupGetStringFieldA (&isDev, 1, field, ARRAYSIZE(field), NULL)) {
if (atoi (field)) {
unsupportedDevice = TRUE;
}
}
}
} else {
DEBUGMSGA ((
DBG_HWDB,
"HwpAddPnpIdsInInf: no device section [%s] for [%s]",
devSection,
manufacturer
));
}
//
// Get the device id
//
if (!SetupGetMultiSzFieldA (&isMfg, 2, pnpId, ARRAYSIZE(pnpId), NULL)) {
DEBUGMSGA ((
DBG_HWDB,
"HwpAddPnpIdsInInf: error retrieving PNPID field(s) in line %u in [%s]",
isMfg.Line,
manufacturer
));
continue;
}
//
// Add each device id to the hash table
//
p = pnpId;
while (*p) {
BOOL b = TRUE;
//
// first invoke the callback (if specified)
//
if (Callback) {
if (CallbackIsUnicode) {
PCWSTR uPnpid = ConvertAtoW (p);
if (!uPnpid) {
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
__leave;
}
if (!uInfPath) {
uInfPath = ConvertAtoW (InfPath);
}
if (!uSourceDirectory) {
uSourceDirectory = ConvertAtoW (SourceDirectory);
}
if (!uInfFilename) {
uInfFilename = ConvertAtoW (InfFilename);
}
b = (*(HWDBAPPENDINFSCALLBACKW)Callback) (CallbackContext, uPnpid, uInfFilename, uSourceDirectory, uInfPath);
FreeConvertedStr (uPnpid);
} else {
b = (*Callback) (CallbackContext, p, InfFilename, SourceDirectory, InfPath);
}
}
if (b) {
//
// First time through add the INF file name to string table
//
if (!infOffset) {
if (Hwdb->InfFileTable) {
fileName = _mbsrchr (InfPath, '\\') + 1;
infOffset = HtAddStringA (Hwdb->InfFileTable, fileName);
if (!infOffset) {
DEBUGMSGA ((DBG_ERROR, "Cannot add %s to table of INFs.", fileName));
__leave;
}
}
}
if (FAILED (StringCchCopyA (trimmedPnpId, ARRAYSIZE(trimmedPnpId), SkipSpaceA (p)))) {
__leave;
}
TruncateTrailingSpaceA (trimmedPnpId);
if (!HtAddStringExA (
unsupportedDevice ? Hwdb->UnsupPnpIdTable : Hwdb->PnpIdTable,
trimmedPnpId,
(PVOID)&infOffset,
CASE_INSENSITIVE
)) {
DEBUGMSGA ((
DBG_ERROR,
"HwpAddPnpIdsInInf: cannot add %s to table of PNP IDs",
trimmedPnpId
));
__leave;
}
}
p = GetEndOfStringA (p) + 1;
}
} while (SetupFindNextLine (&isMfg, &isMfg));
} while (SetupFindNextLine (&is, &is));
} else {
rc = GetLastError();
//
// If section not found, return success
//
if (rc == ERROR_SECTION_NOT_FOUND || rc == ERROR_LINE_NOT_FOUND) {
SetLastError (ERROR_SUCCESS);
DEBUGMSGA ((
DBG_HWDB,
"HwpAddPnpIdsInInf: %s has no [manufacturer] section or it's empty",
InfPath
));
} else {
DEBUGMSGA ((
DBG_ERROR,
"HwpAddPnpIdsInInf: error trying to find the [manufacturer] section",
InfPath
));
__leave;
}
}
result = TRUE;
}
__finally {
PushError();
SetupCloseInfFile (inf);
FreeConvertedStr (uInfPath);
FreeConvertedStr (uSourceDirectory);
FreeConvertedStr (uInfFilename);
PopError();
DEBUGMSGA ((DBG_HWDB, "HwpAddPnpIdsInInf: done parsing %s", InfPath));
}
return result;
}
BOOL
HwdbpAppendInfs (
IN PHWDB Hwdb,
IN PCSTR SourceDirectory,
IN HWDBAPPENDINFSCALLBACKA Callback, OPTIONAL
IN PVOID CallbackContext, OPTIONAL
IN BOOL CallbackIsUnicode
)
{
HANDLE h;
WIN32_FIND_DATA fd;
CHAR buffer[MAX_PATH];
CHAR uncompressedFile[MAX_PATH];
CHAR fullPath[MAX_PATH];
DWORD rc;
if (!g_TempDir) {
//
// the temp dir must be set first
//
SetLastError (ERROR_INVALID_FUNCTION);
return FALSE;
}
if (FAILED (StringCchPrintfA (buffer, ARRAYSIZE(buffer), "%s\\*.in?", SourceDirectory))) {
SetLastError (ERROR_INVALID_PARAMETER);
DEBUGMSGA ((
DBG_ERROR,
"HwdbpAppendInfs: SourceDir name too long: %s",
SourceDirectory
));
return FALSE;
}
h = FindFirstFileA (buffer, &fd);
if (h != INVALID_HANDLE_VALUE) {
do {
if (!HwpIsValidInfName (fd.cFileName, buffer, ARRAYSIZE(buffer))) {
continue;
}
if (*buffer) {
if (FAILED (StringCchPrintfA (uncompressedFile, ARRAYSIZE(uncompressedFile), "%s\\%s", g_TempDir, buffer))) {
SetLastError (ERROR_INVALID_PARAMETER);
DEBUGMSGA ((
DBG_ERROR,
"HwdbpAppendInfs: file name too long: %s\\%s",
g_TempDir,
buffer
));
continue;
}
if (FAILED (StringCchPrintfA (fullPath, ARRAYSIZE(fullPath), "%s\\%s", SourceDirectory, fd.cFileName))) {
SetLastError (ERROR_INVALID_PARAMETER);
DEBUGMSGA ((
DBG_ERROR,
"HwdbpAppendInfs: file name too long: %s\\%s",
SourceDirectory,
fd.cFileName
));
continue;
}
SetFileAttributesA (uncompressedFile, FILE_ATTRIBUTE_NORMAL);
DeleteFileA (uncompressedFile);
rc = SetupDecompressOrCopyFileA (fullPath, uncompressedFile, 0);
if (rc != ERROR_SUCCESS) {
LOGA ((
LOG_ERROR,
"HwdbpAppendInfs: Could not decompress %s to %s",
fullPath,
uncompressedFile
));
continue;
}
} else {
if (FAILED (StringCchPrintfA (uncompressedFile, ARRAYSIZE(uncompressedFile), "%s\\%s", SourceDirectory, fd.cFileName))) {
SetLastError (ERROR_INVALID_PARAMETER);
DEBUGMSGA ((
DBG_ERROR,
"HwdbpAppendInfs: file name too long: %s\\%s",
g_TempDir,
buffer
));
continue;
}
}
if (!HwpAddPnpIdsInInf (
uncompressedFile,
Hwdb,
SourceDirectory,
*buffer ? buffer : fd.cFileName,
Callback,
CallbackContext,
CallbackIsUnicode
)) {
DEBUGMSGA ((
DBG_ERROR,
"HwdbpAppendInfs: HwpAddPnpIdsInInf(%s) failed",
*buffer ? fullPath : uncompressedFile
));
continue;
}
if (*buffer) {
SetFileAttributesA (uncompressedFile, FILE_ATTRIBUTE_NORMAL);
DeleteFileA (uncompressedFile);
}
} while (FindNextFile (h, &fd));
FindClose (h);
}
return TRUE;
}
BOOL
pAppendToHashTable (
IN HASHTABLE HashTable,
IN HASHITEM Index,
IN PCSTR String,
IN PVOID ExtraData,
IN UINT ExtraDataSize,
IN LPARAM lParam
)
{
MYASSERT (lParam);
return HtAddStringA ((HASHTABLE)lParam, String) != NULL;
}
BOOL
HwdbpAppendDatabase (
IN PHWDB HwdbTarget,
IN PHWDB HwdbSource
)
{
#if 0
BOOL b = TRUE;
if (HwdbSource->PnpIdTable) {
if (!HwdbTarget->PnpIdTable) {
HwdbTarget->PnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
if (!HwdbTarget->PnpIdTable) {
b = FALSE;
}
}
if (b) {
b = EnumHashTableWithCallbackA (
HwdbSource->PnpIdTable,
pAppendToHashTable,
HwdbTarget->PnpIdTable
);
}
}
if (b && HwdbSource->UnsupPnpIdTable) {
if (!HwdbTarget->UnsupPnpIdTable) {
HwdbTarget->UnsupPnpIdTable = HtAllocWithData (sizeof (HASHITEM*));
if (!HwdbTarget->UnsupPnpIdTable) {
b = FALSE;
}
}
if (b) {
b = EnumHashTableWithCallbackA (
HwdbSource->UnsupPnpIdTable,
pAppendToHashTable,
HwdbTarget->UnsupPnpIdTable
);
}
}
return b;
#endif
//
// not implemented
//
return FALSE;
}
BOOL
HwdbpHasDriver (
IN PHWDB Hwdb,
IN PCSTR PnpId,
OUT PBOOL Unsupported
)
/*++
Routine Description:
HwdbpHasDriver determines if the PnpId is in the database
Arguments:
Hwdb - Specifies the database to search
PnpId - Specifies the PNPID to look for
Unsupported - Receives TRUE if the PNPID is unsupported
Return Value:
TRUE if the database has the PNPID
--*/
{
if (!Hwdb || !PnpId || !Unsupported) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// check if it's unsupported first
//
if (HtFindStringA (Hwdb->UnsupPnpIdTable, PnpId)) {
*Unsupported = TRUE;
return TRUE;
}
if (!HtFindStringA (Hwdb->PnpIdTable, PnpId)) {
return FALSE;
}
//
// fill out info
//
*Unsupported = FALSE;
return TRUE;
}
BOOL
HwdbpHasAnyDriver (
IN PHWDB Hwdb,
IN PCSTR PnpIds,
OUT PBOOL Unsupported
)
/*++
Routine Description:
HwdbpHasAnyDriver determines if any PNPID from the PnpIds multisz is in the database
Arguments:
Hwdb - Specifies the database to search
PnpIds - Specifies the list (multisz) of PNPIDs to look for
Unsupported - Receives TRUE if any PNPID in this list is unsupported
Return Value:
TRUE if the database has at least one of the PNPIDs in the list
--*/
{
BOOL bFound = FALSE;
PCSTR pnpID;
if (!Hwdb || !PnpIds || !Unsupported) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
for (pnpID = PnpIds; *pnpID; pnpID = strchr (pnpID, 0) + 1) {
//
// check if it's unsupported first
//
if (HtFindStringA (Hwdb->UnsupPnpIdTable, pnpID)) {
*Unsupported = TRUE;
return TRUE;
}
if (HtFindStringA (Hwdb->PnpIdTable, pnpID)) {
bFound = TRUE;
}
}
//
// fill out info
//
*Unsupported = FALSE;
return bFound;
}
#if 0
typedef struct {
PHWDB Hwdb;
PHWDBENUM_CALLBACKA EnumCallback;
PVOID UserContext;
} HWDBENUM_DATAA, *PHWDBENUM_DATAA;
typedef struct {
PHWDB Hwdb;
PHWDBENUM_CALLBACKW EnumCallback;
PVOID UserContext;
} HWDBENUM_DATAW, *PHWDBENUM_DATAW;
BOOL
pCallbackEnumA (
IN HASHTABLE HashTable,
IN HASHITEM Index,
IN PCSTR PnpId,
IN PVOID ExtraData,
IN UINT ExtraDataSize,
IN LPARAM lParam
)
{
PHWDBENUM_DATAA ped = (PHWDBENUM_DATAA)lParam;
/*
PPNPID_DATA data = (PPNPID_DATA)ExtraData;
MYASSERT (ExtraDataSize == sizeof (PNPID_DATA);
return (*ped->EnumCallback) (
ped->UserContext,
PnpId,
pGetInfPath (ped->Hwdb, data->InfOffset),
data->Flags
);
*/
return FALSE;
}
BOOL
HwdbpEnumeratePnpIdA (
IN PHWDB Hwdb,
IN PHWDBENUM_CALLBACKA EnumCallback,
IN PVOID UserContext
)
{
HWDBENUM_DATAA ed;
if (!Hwdb || !EnumCallback) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
ed.Hwdb = Hwdb;
ed.EnumCallback = EnumCallback;
ed.UserContext = UserContext;
return EnumHashTableWithCallbackA (Hwdb->PnpIdTable, pCallbackEnumA, (LPARAM)&ed);
}
BOOL
pCallbackEnumW (
IN HASHTABLE HashTable,
IN HASHITEM Index,
IN PCSTR PnpId,
IN PVOID ExtraData,
IN UINT ExtraDataSize,
IN LPARAM lParam
)
{
PHWDBENUM_DATAW ped = (PHWDBENUM_DATAW)lParam;
/*
PPNPID_DATA data = (PPNPID_DATA)ExtraData;
MYASSERT (ExtraDataSize == sizeof (PNPID_DATA);
return (*ped->EnumCallback) (
ped->UserContext,
PnpId,
pGetInfPath (ped->Hwdb, data->InfOffset),
data->Flags
);
*/
return FALSE;
}
BOOL
HwdbpEnumeratePnpIdW (
IN PHWDB Hwdb,
IN PHWDBENUM_CALLBACKW EnumCallback,
IN PVOID UserContext
)
{
HWDBENUM_DATAW ed;
if (!Hwdb || !EnumCallback) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
ed.Hwdb = Hwdb;
ed.EnumCallback = EnumCallback;
ed.UserContext = UserContext;
return EnumHashTableWithCallbackA (Hwdb->PnpIdTable, pCallbackEnumW, (LPARAM)&ed);
}
#endif
BOOL
HwdbpEnumFirstInfA (
OUT PHWDBINF_ENUMA EnumPtr,
IN PCSTR DatabaseFile
)
{
CHAR buffer[MAX_PATH];
CHAR sig[sizeof (HWCOMPDAT_SIGNATURE)];
DWORD checksum;
DWORD rc;
DWORD BytesRead;
HASHITEM infOffset;
PHWDBINF_ENUM_INTERNAL pei;
if (!DatabaseFile || !EnumPtr) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!GetFullPathNameA (DatabaseFile, MAX_PATH, buffer, NULL)) {
return FALSE;
}
EnumPtr->Internal = (PHWDBINF_ENUM_INTERNAL) MemAlloc (g_hHwdbHeap, 0, sizeof (HWDBINF_ENUM_INTERNAL));
if (!EnumPtr->Internal) {
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
ZeroMemory (EnumPtr->Internal, sizeof (HWDBINF_ENUM_INTERNAL));
pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
//
// Try to open the file
//
pei->File = CreateFileA (
buffer,
GENERIC_READ,
FILE_SHARE_READ, // share for read access
NULL, // no security attribs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL // no template
);
if (pei->File == INVALID_HANDLE_VALUE) {
return FALSE;
}
//
// Look at the signature
//
ZeroMemory (sig, sizeof(sig));
if (!ReadFile (pei->File, sig, sizeof (HWCOMPDAT_SIGNATURE) - 1, &BytesRead, NULL) ||
lstrcmpA (HWCOMPDAT_SIGNATURE, sig)
) {
SetLastError (ERROR_BAD_FORMAT);
goto exit;
}
//
// Get INF checksum
//
if (!pReadDword (pei->File, &checksum)) {
SetLastError (ERROR_BAD_FORMAT);
goto exit;
}
//
// Read in all PNP IDs
//
return HwdbpEnumNextInfA (EnumPtr);
exit:
HwdbpAbortEnumInfA (EnumPtr);
return FALSE;
}
BOOL
HwdbpEnumFirstInfW (
OUT PHWDBINF_ENUMW EnumPtr,
IN PCSTR DatabaseFile
)
{
HWDBINF_ENUMA ea;
if (!HwdbpEnumFirstInfA (&ea, DatabaseFile)) {
return FALSE;
}
EnumPtr->Internal = ea.Internal;
EnumPtr->InfFile = ConvertAtoW (ea.InfFile);
EnumPtr->PnpIds = pConvertMultiSzToUnicode (ea.PnpIds);
if (EnumPtr->InfFile && EnumPtr->PnpIds) {
return TRUE;
}
HwdbpAbortEnumInfW (EnumPtr);
return FALSE;
}
BOOL
HwdbpEnumNextInfA (
IN OUT PHWDBINF_ENUMA EnumPtr
)
{
CHAR pnpId[1024];
PHWDBINF_ENUM_INTERNAL pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
//
// Get next INF file name. If empty, we are done.
//
if (!pReadString (pei->File, EnumPtr->InfFile, sizeof (EnumPtr->InfFile))) {
SetLastError (ERROR_BAD_FORMAT);
goto exit;
}
if (EnumPtr->InfFile[0] == 0) {
SetLastError (ERROR_SUCCESS);
goto exit;
}
//
// Read in all PNP IDs for the INF
//
for (;;) {
//
// Get the PNP ID. If empty, we are done.
//
if (!pReadString (pei->File, pnpId, sizeof (pnpId))) {
SetLastError (ERROR_BAD_FORMAT);
goto exit;
}
if (*pnpId == 0) {
break;
}
if (!MultiSzAppendA (&pei->GrowBuf, pnpId)) {
SetLastError (ERROR_OUTOFMEMORY);
goto exit;
}
}
EnumPtr->PnpIds = (PCSTR)pei->GrowBuf.Buf;
return TRUE;
exit:
HwdbpAbortEnumInfA (EnumPtr);
return FALSE;
}
BOOL
HwdbpEnumNextInfW (
IN OUT PHWDBINF_ENUMW EnumPtr
)
{
HWDBINF_ENUMA ea;
ea.Internal = EnumPtr->Internal;
if (!HwdbpEnumNextInfA (&ea)) {
return FALSE;
}
EnumPtr->InfFile = ConvertAtoW (ea.InfFile);
EnumPtr->PnpIds = pConvertMultiSzToUnicode (ea.PnpIds);
if (EnumPtr->InfFile && EnumPtr->PnpIds) {
return TRUE;
}
HwdbpAbortEnumInfW (EnumPtr);
return FALSE;
}
VOID
HwdbpAbortEnumInfA (
IN OUT PHWDBINF_ENUMA EnumPtr
)
{
PHWDBINF_ENUM_INTERNAL pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
DWORD rc = GetLastError ();
if (pei) {
if (pei->File != INVALID_HANDLE_VALUE) {
CloseHandle (pei->File);
pei->File = INVALID_HANDLE_VALUE;
}
FreeGrowBuffer (&pei->GrowBuf);
}
SetLastError (rc);
}
VOID
HwdbpAbortEnumInfW (
IN OUT PHWDBINF_ENUMW EnumPtr
)
{
PHWDBINF_ENUM_INTERNAL pei = (PHWDBINF_ENUM_INTERNAL)EnumPtr->Internal;
DWORD rc = GetLastError ();
if (EnumPtr->InfFile) {
FreeConvertedStr (EnumPtr->InfFile);
EnumPtr->InfFile = NULL;
}
if (EnumPtr->PnpIds) {
FreeConvertedStr (EnumPtr->PnpIds);
EnumPtr->PnpIds = NULL;
}
if (pei) {
if (pei->File != INVALID_HANDLE_VALUE) {
CloseHandle (pei->File);
pei->File = INVALID_HANDLE_VALUE;
}
FreeGrowBuffer (&pei->GrowBuf);
}
SetLastError (rc);
}
BOOL
HwdbpSetTempDir (
IN PCSTR TempDir
)
{
BOOL b = TRUE;
if (TempDir) {
g_TempDir = DuplicateTextA (TempDir);
if (!g_TempDir) {
b = FALSE;
}
} else {
if (g_TempDir) {
FreeTextA (g_TempDir);
g_TempDir = NULL;
}
}
return b;
}