564 lines
14 KiB
C
564 lines
14 KiB
C
|
/*
|
||
|
Module Name:
|
||
|
|
||
|
infdir.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements utility routines to manipulate structures used to
|
||
|
maintain track INF directories. These directories hold INF files that
|
||
|
we put parse and put change notifies on to track updates.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Andy Herron Apr 08 1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "binl.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "netinfp.h"
|
||
|
|
||
|
BOOLEAN StartedNetInfHandler = FALSE;
|
||
|
CRITICAL_SECTION NetInfLock;
|
||
|
LIST_ENTRY NetInfGlobalInfList;
|
||
|
|
||
|
ULONG
|
||
|
NetInfStartHandler (
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function just dereferences the block for the 'alive' reference.
|
||
|
This may cause it to be deleted.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pNetCards - A pointer to NETCARD_INF_BLOCK block allocated. Contains all
|
||
|
the persistant info required for the netcards.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Windows Error.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (StartedNetInfHandler == FALSE) {
|
||
|
|
||
|
StartedNetInfHandler = TRUE;
|
||
|
InitializeCriticalSection( &NetInfLock );
|
||
|
InitializeListHead(&NetInfGlobalInfList);
|
||
|
}
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
NetInfCloseHandler (
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function just dereferences the block for the 'alive' reference.
|
||
|
This may cause it to be deleted.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pNetCards - A pointer to NETCARD_INF_BLOCK block allocated. Contains all
|
||
|
the persistant info required for the netcards.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Windows Error.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (StartedNetInfHandler) {
|
||
|
|
||
|
EnterCriticalSection( &NetInfLock );
|
||
|
|
||
|
while (IsListEmpty( &NetInfGlobalInfList ) == FALSE) {
|
||
|
|
||
|
PNETCARD_INF_BLOCK pEntry;
|
||
|
PLIST_ENTRY listEntry = RemoveHeadList( &NetInfGlobalInfList );
|
||
|
|
||
|
pEntry = (PNETCARD_INF_BLOCK) CONTAINING_RECORD(
|
||
|
listEntry,
|
||
|
NETCARD_INF_BLOCK,
|
||
|
InfBlockEntry );
|
||
|
NetInfCloseNetcardInfo( pEntry );
|
||
|
}
|
||
|
|
||
|
StartedNetInfHandler = FALSE;
|
||
|
|
||
|
LeaveCriticalSection( &NetInfLock );
|
||
|
|
||
|
DeleteCriticalSection( &NetInfLock );
|
||
|
}
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
NetInfFindNetcardInfo (
|
||
|
PWCHAR InfDirectory,
|
||
|
ULONG Architecture,
|
||
|
ULONG CardInfoVersion,
|
||
|
NET_CARD_INFO UNALIGNED * CardIdentity,
|
||
|
PWCHAR *FullDriverBuffer OPTIONAL,
|
||
|
PNETCARD_RESPONSE_DATABASE *pInfEntry
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function searches the drivers we've found and returns a pointer to
|
||
|
an entry that most closely matches the client's request.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
InfDirectory - directory that is target client's setup directory that
|
||
|
contains all INF files for the client's NT installation.
|
||
|
|
||
|
Architecture - PROCESSOR_ARCHITECTURE_XXXXX
|
||
|
|
||
|
CardInfoVersion - Version of the structure passed by the client.
|
||
|
|
||
|
CardIdentity - has the values the app is looking for. we try our best to
|
||
|
find one that matches.
|
||
|
|
||
|
FullDriverBuffer - where we put the fully qualified file path specification
|
||
|
for the driver we find, if they want it.
|
||
|
|
||
|
pInfEntry - the entry that was found if successful. NULL if in error.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ERROR_SUCCESS, ERROR_NOT_ENOUGH_MEMORY, or ERROR_NOT_SUPPORTED
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG err = ERROR_NOT_SUPPORTED; // start off with not found
|
||
|
LONG result;
|
||
|
PLIST_ENTRY listEntry;
|
||
|
UNICODE_STRING infDirString;
|
||
|
PNETCARD_INF_BLOCK pNetCards = NULL;
|
||
|
WCHAR SetupPath[MAX_PATH];
|
||
|
PWSTR ArchitectureString;
|
||
|
|
||
|
*pInfEntry = NULL;
|
||
|
|
||
|
if (InfDirectory == NULL) {
|
||
|
|
||
|
return ERROR_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we find out what the relative path within the IMIRROR directory is
|
||
|
// for this client's setup files.
|
||
|
//
|
||
|
|
||
|
if ((*InfDirectory != L'\\') ||
|
||
|
(*(InfDirectory+1) != L'\\') ) {
|
||
|
|
||
|
useWholePath:
|
||
|
|
||
|
//
|
||
|
// Make sure there is room for InfDirectory + '\' (1 byte)
|
||
|
// + architecture (MAX_ARCHITECTURE_LENGTH bytes) + '\0' (1 byte).
|
||
|
|
||
|
if (wcslen(InfDirectory) + MAX_ARCHITECTURE_LENGTH + 2 >=
|
||
|
sizeof(SetupPath) / sizeof(SetupPath[0])) {
|
||
|
return ERROR_BAD_PATHNAME;
|
||
|
}
|
||
|
wcscpy( SetupPath, InfDirectory );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
PWCHAR beginRelativePath = InfDirectory + 2; // skip leading slashes
|
||
|
|
||
|
//
|
||
|
// skip computer name
|
||
|
//
|
||
|
|
||
|
while ((*beginRelativePath != L'\0') &&
|
||
|
(*beginRelativePath != L'\\')) {
|
||
|
|
||
|
beginRelativePath++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we should be at the start of the sharename.
|
||
|
//
|
||
|
|
||
|
if (*beginRelativePath != L'\\') {
|
||
|
|
||
|
goto useWholePath;
|
||
|
}
|
||
|
|
||
|
beginRelativePath++;
|
||
|
|
||
|
//
|
||
|
// skip share name
|
||
|
//
|
||
|
|
||
|
while ((*beginRelativePath != L'\0') &&
|
||
|
(*beginRelativePath != L'\\')) {
|
||
|
|
||
|
beginRelativePath++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we should be at the start of the relative directory
|
||
|
//
|
||
|
|
||
|
if (*beginRelativePath != L'\\') {
|
||
|
|
||
|
goto useWholePath;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure there is room for IntelliMirrorPathW +
|
||
|
// beginRelativePath + '\' (1 byte) + architecture
|
||
|
// (MAX_ARCHITECTURE_LENGTH bytes) + '\0' (1 byte).
|
||
|
//
|
||
|
|
||
|
if (wcslen(IntelliMirrorPathW) + wcslen(beginRelativePath) + MAX_ARCHITECTURE_LENGTH + 2 >=
|
||
|
sizeof(SetupPath) / sizeof(SetupPath[0])) {
|
||
|
return ERROR_BAD_PATHNAME;
|
||
|
}
|
||
|
wcscpy( SetupPath, IntelliMirrorPathW );
|
||
|
wcscat( SetupPath, beginRelativePath );
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString( &infDirString, SetupPath );
|
||
|
RtlUpcaseUnicodeString( &infDirString, &infDirString, FALSE );
|
||
|
|
||
|
// convert the path to uppercase to speed our searches
|
||
|
switch (Architecture) {
|
||
|
|
||
|
#if 0
|
||
|
//
|
||
|
// obsoleted architectures.
|
||
|
//
|
||
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||
|
ArchitectureString = L"\\ALPHA";
|
||
|
break;
|
||
|
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
||
|
ArchitectureString = L"\\AXP64";
|
||
|
break;
|
||
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
||
|
ArchitectureString = L"\\MIPS";
|
||
|
break;
|
||
|
case PROCESSOR_ARCHITECTURE_PPC:
|
||
|
ArchitectureString = L"\\PPC";
|
||
|
break;
|
||
|
#endif
|
||
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
||
|
ArchitectureString = L"\\amd64";
|
||
|
break;
|
||
|
case PROCESSOR_ARCHITECTURE_IA64:
|
||
|
ArchitectureString = L"\\IA64";
|
||
|
break;
|
||
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
||
|
default:
|
||
|
ArchitectureString = L"\\I386";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
wcscat( SetupPath, ArchitectureString );
|
||
|
|
||
|
RtlInitUnicodeString( &infDirString, SetupPath );
|
||
|
|
||
|
EnterCriticalSection( &NetInfLock );
|
||
|
|
||
|
//
|
||
|
// Find the NETCARD_INF_BLOCK block for this inf directory. If it
|
||
|
// doesn't exist, try to create the block.
|
||
|
//
|
||
|
|
||
|
listEntry = NetInfGlobalInfList.Flink;
|
||
|
|
||
|
while ( listEntry != &NetInfGlobalInfList ) {
|
||
|
|
||
|
pNetCards = (PNETCARD_INF_BLOCK) CONTAINING_RECORD(
|
||
|
listEntry,
|
||
|
NETCARD_INF_BLOCK,
|
||
|
InfBlockEntry );
|
||
|
|
||
|
err = CompareStringW( LOCALE_INVARIANT,
|
||
|
0,
|
||
|
SetupPath,
|
||
|
infDirString.Length / sizeof(WCHAR),
|
||
|
&pNetCards->InfDirectory[0],
|
||
|
-1
|
||
|
);
|
||
|
if (err == 2) {
|
||
|
|
||
|
break; // a match was found.
|
||
|
}
|
||
|
|
||
|
pNetCards = NULL;
|
||
|
|
||
|
if (err == 3) {
|
||
|
|
||
|
break; // it's greater, add it before listEntry
|
||
|
}
|
||
|
|
||
|
listEntry = listEntry->Flink;
|
||
|
}
|
||
|
|
||
|
if (pNetCards == NULL) {
|
||
|
|
||
|
// we didn't find one. let's create it and parse the INFs.
|
||
|
|
||
|
err = NetInfAllocateNetcardInfo( SetupPath,
|
||
|
Architecture,
|
||
|
&pNetCards );
|
||
|
|
||
|
if (err != ERROR_SUCCESS) {
|
||
|
|
||
|
//
|
||
|
// log an error here that we couldn't get INF file info.
|
||
|
//
|
||
|
|
||
|
PWCHAR strings[2];
|
||
|
|
||
|
strings[0] = SetupPath;
|
||
|
strings[1] = NULL;
|
||
|
|
||
|
BinlReportEventW( ERROR_BINL_ERR_IN_SETUP_PATH,
|
||
|
EVENTLOG_WARNING_TYPE,
|
||
|
1,
|
||
|
sizeof(ULONG),
|
||
|
strings,
|
||
|
&err
|
||
|
);
|
||
|
BinlAssert( pNetCards == NULL );
|
||
|
LeaveCriticalSection( &NetInfLock );
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
BinlAssert( pNetCards != NULL );
|
||
|
|
||
|
//
|
||
|
// Now we plop it in the list right in front of listEntry
|
||
|
//
|
||
|
// Either listEntry is equal to the head of the list or
|
||
|
// it's equal to some entry that is larger (sort wise) than the
|
||
|
// inf path passed in. In either case, we can simply insert
|
||
|
// this new entry onto the tail of listEntry.
|
||
|
//
|
||
|
|
||
|
InsertTailList( listEntry, &pNetCards->InfBlockEntry );
|
||
|
|
||
|
EnterCriticalSection( &pNetCards->Lock );
|
||
|
LeaveCriticalSection( &NetInfLock );
|
||
|
|
||
|
//
|
||
|
// Fill in the list with the list of cards to support
|
||
|
//
|
||
|
|
||
|
err = GetNetCardList( pNetCards );
|
||
|
pNetCards->StatusFromScan = err;
|
||
|
|
||
|
if (err != ERROR_SUCCESS) {
|
||
|
|
||
|
PWCHAR strings[2];
|
||
|
|
||
|
LeaveCriticalSection( &pNetCards->Lock );
|
||
|
NetInfCloseNetcardInfo( pNetCards );
|
||
|
DereferenceNetcardInfo( pNetCards );
|
||
|
|
||
|
strings[0] = SetupPath;
|
||
|
strings[1] = NULL;
|
||
|
|
||
|
BinlReportEventW( ERROR_BINL_ERR_IN_SETUP_PATH,
|
||
|
EVENTLOG_WARNING_TYPE,
|
||
|
1,
|
||
|
sizeof(ULONG),
|
||
|
strings,
|
||
|
&err
|
||
|
);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
BinlAssert( pNetCards->ReferenceCount > 0 );
|
||
|
pNetCards->ReferenceCount++;
|
||
|
|
||
|
LeaveCriticalSection( &NetInfLock );
|
||
|
EnterCriticalSection( &pNetCards->Lock );
|
||
|
|
||
|
err = pNetCards->StatusFromScan;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if the thread that is scanning the INFs hits an error, then all threads
|
||
|
// that were waiting on that directory to be scanned should get the same
|
||
|
// error. we use StatusFromScan to hold this.
|
||
|
//
|
||
|
|
||
|
if (err == ERROR_SUCCESS) {
|
||
|
|
||
|
err = FindNetcardInfo( pNetCards, CardInfoVersion, CardIdentity, pInfEntry );
|
||
|
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection( &pNetCards->Lock );
|
||
|
|
||
|
|
||
|
if ((err == ERROR_SUCCESS) &&
|
||
|
(*pInfEntry != NULL) &&
|
||
|
(FullDriverBuffer != NULL)) {
|
||
|
|
||
|
ULONG sizeToAllocate;
|
||
|
|
||
|
//
|
||
|
// the caller wanted a copy of the fully qualified file name. we
|
||
|
// have all that info here. Allocate what we need plus two, one for
|
||
|
// the null, the other for the backslash.
|
||
|
//
|
||
|
|
||
|
sizeToAllocate = (wcslen( SetupPath ) + 2) * sizeof(WCHAR);
|
||
|
sizeToAllocate += wcslen( (*pInfEntry)->DriverName ) * sizeof(WCHAR);
|
||
|
|
||
|
*FullDriverBuffer = BinlAllocateMemory( sizeToAllocate );
|
||
|
|
||
|
if (*FullDriverBuffer) {
|
||
|
|
||
|
if (_snwprintf( *FullDriverBuffer,
|
||
|
sizeToAllocate/sizeof(WCHAR),
|
||
|
L"%ws\\%ws",
|
||
|
SetupPath,
|
||
|
(*pInfEntry)->DriverName ) < 0) {
|
||
|
BinlFreeMemory( *FullDriverBuffer );
|
||
|
*FullDriverBuffer = NULL;
|
||
|
err = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||
|
} else {
|
||
|
*FullDriverBuffer[sizeToAllocate-1] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
DereferenceNetcardInfo( pNetCards );
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
NetInfEnumFiles (
|
||
|
PWCHAR FlatDirectory,
|
||
|
ULONG Architecture,
|
||
|
LPVOID Context,
|
||
|
PNETINF_CALLBACK CallBack
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function searches the drivers we've found and returns a pointer to
|
||
|
an entry that most closely matches the client's request.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FlatDirectory - directory that is target client's setup directory that
|
||
|
contains all INF files for the client's NT installation.
|
||
|
|
||
|
Architecture - PROCESSOR_ARCHITECTURE_XXXXX
|
||
|
|
||
|
CallBack - function to call with names of files
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ERROR_SUCCESS, ERROR_NOT_ENOUGH_MEMORY, or ERROR_NOT_SUPPORTED
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG err = ERROR_NOT_SUPPORTED; // start off with not found
|
||
|
UNICODE_STRING infDirString;
|
||
|
PNETCARD_INF_BLOCK pNetCards = NULL;
|
||
|
WCHAR SetupPath[MAX_PATH];
|
||
|
|
||
|
//
|
||
|
// this entrypoint can purposely be called from another context than
|
||
|
// BINLSVC. so initialize debugging if that's the case.
|
||
|
//
|
||
|
DebugInitialize();
|
||
|
|
||
|
if (FlatDirectory == NULL) {
|
||
|
|
||
|
err = ERROR_NOT_SUPPORTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if (wcslen(FlatDirectory) > MAX_PATH - 1) {
|
||
|
|
||
|
err = ERROR_INVALID_PARAMETER;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
wcscpy( SetupPath, FlatDirectory );
|
||
|
|
||
|
RtlInitUnicodeString( &infDirString, SetupPath );
|
||
|
RtlUpcaseUnicodeString( &infDirString, &infDirString, FALSE );
|
||
|
|
||
|
if (StartedNetInfHandler == FALSE) {
|
||
|
|
||
|
err = NetInfStartHandler();
|
||
|
|
||
|
if (err != ERROR_SUCCESS) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err = NetInfAllocateNetcardInfo( SetupPath,
|
||
|
Architecture,
|
||
|
&pNetCards );
|
||
|
|
||
|
if (err != ERROR_SUCCESS) {
|
||
|
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
BinlAssert( pNetCards != NULL );
|
||
|
|
||
|
pNetCards->FileListCallbackFunction = CallBack;
|
||
|
pNetCards->FileListCallbackContext = Context;
|
||
|
|
||
|
//
|
||
|
// Fill in the list with the list of cards to support
|
||
|
//
|
||
|
|
||
|
err = GetNetCardList( pNetCards );
|
||
|
|
||
|
DereferenceNetcardInfo( pNetCards ); // one for dereference
|
||
|
DereferenceNetcardInfo( pNetCards ); // and one to delete it.
|
||
|
|
||
|
//
|
||
|
// note that we won't bother to call NetInfCloseHandler here because
|
||
|
// we have no idea if the caller on another thread has setup any
|
||
|
// other NETCARD_INF_BLOCKs. So rather than corrupt the list and AV,
|
||
|
// we'll just leak the lock. Not a big deal in RIPREP since it doesn't
|
||
|
// handle more than one. Not an issue for BINL processing INF files.
|
||
|
//
|
||
|
|
||
|
Exit:
|
||
|
//
|
||
|
// this entrypoint can purposely be called from another context than
|
||
|
// BINLSVC. debugging will be uninitialize in process detach when we're
|
||
|
// done.
|
||
|
//
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
// infdir.c eof
|
||
|
|