Source code of Windows XP (NT5)
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.

2640 lines
75 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. infcache.c
  5. Abstract:
  6. INF Cache management functions
  7. Author:
  8. Jamie Hunter (jamiehun) Jan-27-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define BOUNDSCHECK(base,size,limit) ( \
  14. ((base)<=(limit)) && \
  15. ((size)<=(limit)) && \
  16. ((base+size)<=(limit)) && \
  17. ((base+size)>=(base)))
  18. //
  19. // Macros used to quadword-align Cache blocks.
  20. //
  21. #define CACHE_ALIGNMENT ((DWORD)8)
  22. #define CACHE_ALIGN_MASK (~(DWORD)(CACHE_ALIGNMENT - 1))
  23. #define CACHE_ALIGN_BLOCK(x) ((x & CACHE_ALIGN_MASK) + ((x & ~CACHE_ALIGN_MASK) ? CACHE_ALIGNMENT : 0))
  24. BOOL
  25. AlignForNextBlock(
  26. IN HANDLE hFile,
  27. IN DWORD ByteCount
  28. );
  29. #ifdef UNICODE
  30. VOID InfCacheFreeCache(
  31. IN PINFCACHE pInfCache
  32. )
  33. /*++
  34. Routine Description:
  35. Delete/Release in-memory image of INF CACHE
  36. Arguments:
  37. pInfCache - pointer to Run-Time data
  38. Return Value:
  39. none
  40. --*/
  41. {
  42. if (pInfCache == NULL) {
  43. //
  44. // no cache
  45. //
  46. return;
  47. }
  48. if(pInfCache->bReadOnly && pInfCache->BaseAddress) {
  49. //
  50. // we're looking at memory mapped cache
  51. //
  52. pStringTableDestroy(pInfCache->pMatchTable);
  53. pStringTableDestroy(pInfCache->pInfTable);
  54. pSetupUnmapAndCloseFile(pInfCache->FileHandle, pInfCache->MappingHandle, pInfCache->BaseAddress);
  55. } else {
  56. //
  57. // if cache is writable, this data is transient
  58. //
  59. if(pInfCache->pHeader) {
  60. MyFree(pInfCache->pHeader);
  61. }
  62. if(pInfCache->pMatchTable) {
  63. pStringTableDestroy(pInfCache->pMatchTable);
  64. }
  65. if(pInfCache->pInfTable) {
  66. pStringTableDestroy(pInfCache->pInfTable);
  67. }
  68. if(pInfCache->pListTable) {
  69. MyFree(pInfCache->pListTable);
  70. }
  71. }
  72. //
  73. // transient information
  74. //
  75. if(pInfCache->pSearchTable) {
  76. pStringTableDestroy(pInfCache->pSearchTable);
  77. }
  78. MyFree(pInfCache);
  79. }
  80. #endif
  81. #ifdef UNICODE
  82. PINFCACHE InfCacheCreateNewCache(
  83. IN PSETUP_LOG_CONTEXT LogContext
  84. )
  85. /*++
  86. Routine Description:
  87. Create new empty cache
  88. Arguments:
  89. LogContext - for logging
  90. Return Value:
  91. pointer to Run-Time header if succeeded, NULL if out of memory.
  92. --*/
  93. {
  94. PINFCACHE pInfCache = (PINFCACHE)MyMalloc(sizeof(INFCACHE));
  95. if(pInfCache == NULL) {
  96. return NULL;
  97. }
  98. ZeroMemory(pInfCache,sizeof(INFCACHE));
  99. //
  100. // set initial state
  101. //
  102. pInfCache->BaseAddress = NULL;
  103. pInfCache->bReadOnly = FALSE;
  104. pInfCache->bDirty = TRUE;
  105. pInfCache->bNoWriteBack = FALSE;
  106. //
  107. // create transient data
  108. //
  109. pInfCache->pHeader = (PCACHEHEADER)MyMalloc(sizeof(CACHEHEADER));
  110. if(pInfCache->pHeader == NULL) {
  111. goto cleanup;
  112. }
  113. pInfCache->pMatchTable = pStringTableInitialize(sizeof(CACHEMATCHENTRY));
  114. if(pInfCache->pMatchTable == NULL) {
  115. goto cleanup;
  116. }
  117. pInfCache->pInfTable = pStringTableInitialize(sizeof(CACHEINFENTRY));
  118. if(pInfCache->pInfTable == NULL) {
  119. goto cleanup;
  120. }
  121. pInfCache->pHeader->Version = INFCACHE_VERSION;
  122. pInfCache->pHeader->Locale = GetThreadLocale();
  123. pInfCache->pHeader->Flags = 0;
  124. pInfCache->pHeader->FileSize = 0; // in memory image
  125. pInfCache->pHeader->MatchTableOffset = 0; // in memory image
  126. pInfCache->pHeader->MatchTableSize = 0; // in memory image
  127. pInfCache->pHeader->InfTableOffset = 0; // in memory image
  128. pInfCache->pHeader->InfTableSize = 0; // in memory image
  129. pInfCache->pHeader->ListDataOffset = 0; // in memory image
  130. pInfCache->pHeader->ListDataCount = 1; // initial size (count the free list node)
  131. pInfCache->ListDataAlloc = 32768; // initial size of allocation
  132. pInfCache->pListTable = (PCACHELISTENTRY)MyMalloc(sizeof(CACHELISTENTRY)*pInfCache->ListDataAlloc);
  133. if(pInfCache->pListTable == NULL) {
  134. goto cleanup;
  135. }
  136. //
  137. // initialize free-list to empty (even though we allocated enough space, we don't commit it until needed)
  138. //
  139. pInfCache->pListTable[0].Value = 0; // how many free entries
  140. pInfCache->pListTable[0].Next = 0;
  141. //
  142. // search table
  143. //
  144. pInfCache->pSearchTable = pStringTableInitialize(sizeof(CACHEHITENTRY));
  145. if(pInfCache->pSearchTable == NULL) {
  146. goto cleanup;
  147. }
  148. WriteLogEntry(LogContext,
  149. DRIVER_LOG_VVERBOSE,
  150. MSG_LOG_USING_NEW_INF_CACHE,
  151. NULL
  152. );
  153. return pInfCache;
  154. cleanup:
  155. InfCacheFreeCache(pInfCache);
  156. return NULL;
  157. }
  158. #endif
  159. #ifdef UNICODE
  160. DWORD MarkForDelete(
  161. IN LPCTSTR FilePath
  162. )
  163. /*++
  164. Routine Description:
  165. Special delete operation that will open the file with required access
  166. mark it as needs deleting
  167. and then close it again
  168. Arguments:
  169. FilePath - name of file to delete
  170. Return Value:
  171. Success status
  172. --*/
  173. {
  174. TCHAR TmpFilePath[MAX_PATH*2];
  175. PTSTR FileName;
  176. HANDLE hFile;
  177. int c;
  178. hFile = CreateFile(FilePath,
  179. 0,
  180. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  181. NULL,
  182. OPEN_EXISTING,
  183. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
  184. NULL
  185. );
  186. if(hFile == INVALID_HANDLE_VALUE) {
  187. //
  188. // this can fail for various reasons
  189. //
  190. if(GetLastError() == ERROR_FILE_NOT_FOUND) {
  191. return NO_ERROR;
  192. }
  193. return GetLastError();
  194. }
  195. //
  196. // rename file to a temporary one for period that file remains alive
  197. //
  198. lstrcpyn(TmpFilePath,FilePath,MAX_PATH);
  199. FileName = (PTSTR)pSetupGetFileTitle(TmpFilePath);
  200. for(c=0;c<1000;c++) {
  201. _stprintf(FileName,OLDCACHE_NAME_TEMPLATE,c);
  202. if (MoveFile(FilePath,TmpFilePath)) {
  203. break;
  204. }
  205. if (GetLastError() != ERROR_FILE_EXISTS) {
  206. MYASSERT(GetLastError() == ERROR_FILE_EXISTS);
  207. break;
  208. }
  209. }
  210. MYASSERT(c<1000);
  211. //
  212. // ok, done (file may go away as soon as we close handle)
  213. //
  214. CloseHandle(hFile);
  215. return NO_ERROR;
  216. }
  217. #endif
  218. #ifdef UNICODE
  219. DWORD InfCacheGetFileNames(
  220. IN LPCTSTR InfDirectory,
  221. OUT TCHAR InfPath[3][MAX_PATH]
  222. )
  223. {
  224. TCHAR InfName[MAX_PATH];
  225. int c;
  226. for(c=0;c<3;c++) {
  227. lstrcpyn(InfPath[c],InfDirectory,MAX_PATH);
  228. _stprintf(InfName,INFCACHE_NAME_TEMPLATE,c);
  229. if(!pSetupConcatenatePaths(InfPath[c],InfName,MAX_PATH,NULL)) {
  230. //
  231. // filename too big, fall into default search mode (we'll never be able to save the cache)
  232. //
  233. return ERROR_BAD_PATHNAME;
  234. }
  235. }
  236. return NO_ERROR;
  237. }
  238. #endif
  239. #ifdef UNICODE
  240. PINFCACHE InfCacheLoadCache(
  241. IN LPCTSTR InfDirectory,
  242. IN PSETUP_LOG_CONTEXT LogContext
  243. )
  244. /*++
  245. Routine Description:
  246. Retrieves cache for INF directory, if any.
  247. We'll try
  248. 1) INFCACHE.1 (if it's a bad file, we'll rename to OLDCACHE.xxx)
  249. 2) INFCACHE.2 (ditto)
  250. if we can't open a either of them, we'll skip over. We'll only have
  251. both if something happened during write (such as reboot)
  252. the OLDCACHE.xxx will be deleted when last handle to it is closed
  253. we attempt to return (1) existing cache, (2) empty cache, (3) NULL
  254. Arguments:
  255. InfDirectory - directory to find cache in
  256. LogContext - for logging
  257. Return Value:
  258. pointer to Run-Time header if succeeded, NULL if fatal error (go into default search mode)
  259. --*/
  260. {
  261. //
  262. // currently only support for unicode setupapi
  263. //
  264. TCHAR InfPath[3][MAX_PATH];
  265. int c;
  266. DWORD FileSize;
  267. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  268. HANDLE MappingHandle = NULL;
  269. PVOID BaseAddress = NULL;
  270. PCACHEHEADER pHeader = NULL;
  271. PINFCACHE pInfCache = NULL;
  272. DWORD Err;
  273. MYASSERT(InfDirectory);
  274. if ((Err = InfCacheGetFileNames(InfDirectory,InfPath))!=NO_ERROR) {
  275. return NULL;
  276. }
  277. //
  278. // look at INFCACHE.1 (primary) INFCACHE.2 (backup)
  279. //
  280. for(c=1;c<3;c++) {
  281. //
  282. // try and map this file into memory
  283. //
  284. //
  285. FileHandle = CreateFile(
  286. InfPath[c],
  287. GENERIC_READ,
  288. FILE_SHARE_READ | FILE_SHARE_DELETE, // need delete permission
  289. NULL,
  290. OPEN_EXISTING,
  291. 0,
  292. NULL
  293. );
  294. if(FileHandle == INVALID_HANDLE_VALUE) {
  295. continue; // this file is locked, or doesn't exist
  296. }
  297. if((Err = pSetupMapFileForRead(FileHandle,&FileSize,&MappingHandle,&BaseAddress)) != NO_ERROR) {
  298. //
  299. // shouldn't happen on a good file, so clean it up
  300. //
  301. MarkForDelete(InfPath[c]);
  302. continue;
  303. }
  304. if(FileSize >= sizeof(CACHEHEADER)) {
  305. pHeader = (PCACHEHEADER)BaseAddress;
  306. if(pHeader->Version == INFCACHE_VERSION &&
  307. pHeader->FileSize <= FileSize &&
  308. BOUNDSCHECK(pHeader->MatchTableOffset,pHeader->MatchTableSize,pHeader->FileSize) &&
  309. BOUNDSCHECK(pHeader->InfTableOffset,pHeader->InfTableSize,pHeader->FileSize) &&
  310. BOUNDSCHECK(pHeader->ListDataOffset,(pHeader->ListDataCount*sizeof(CACHELISTENTRY)),pHeader->FileSize) &&
  311. (pHeader->MatchTableOffset >= sizeof(CACHEHEADER)) &&
  312. (pHeader->InfTableOffset >= pHeader->MatchTableOffset+pHeader->MatchTableSize) &&
  313. (pHeader->ListDataOffset >= pHeader->InfTableOffset+pHeader->InfTableSize)) {
  314. //
  315. // we're reasonably happy this file is valid
  316. //
  317. break;
  318. }
  319. }
  320. //
  321. // bad file (we was able to open file for reading, so it wasn't locked for writing)
  322. //
  323. MarkForDelete(InfPath[c]);
  324. pSetupUnmapAndCloseFile(FileHandle, MappingHandle, BaseAddress);
  325. }
  326. switch(c) {
  327. case 0: // obtained primary file
  328. case 1: // obtained secondary file
  329. case 2: // obtained backup file, don't move as secondary may exist as locked
  330. WriteLogEntry(LogContext,
  331. DRIVER_LOG_VVERBOSE,
  332. MSG_LOG_USING_INF_CACHE,
  333. NULL,
  334. InfPath[c]);
  335. break;
  336. case 3: // obtained no file
  337. return InfCacheCreateNewCache(LogContext);
  338. default: // whoops?
  339. MYASSERT(FALSE);
  340. return InfCacheCreateNewCache(LogContext);
  341. }
  342. //
  343. // if we get here, we have a mapped file
  344. //
  345. MYASSERT(BaseAddress);
  346. pInfCache = (PINFCACHE)MyMalloc(sizeof(INFCACHE));
  347. if(pInfCache == NULL) {
  348. pSetupUnmapAndCloseFile(FileHandle, MappingHandle, BaseAddress);
  349. return NULL;
  350. }
  351. ZeroMemory(pInfCache,sizeof(INFCACHE));
  352. //
  353. // set initial state
  354. //
  355. pInfCache->FileHandle = FileHandle;
  356. pInfCache->MappingHandle = MappingHandle;
  357. pInfCache->BaseAddress = BaseAddress;
  358. pInfCache->bReadOnly = TRUE;
  359. pInfCache->bDirty = FALSE;
  360. pInfCache->bNoWriteBack = FALSE;
  361. //
  362. // make Runtime-Data point to relevent data structures
  363. //
  364. pInfCache->pHeader = pHeader;
  365. //
  366. // note that InitializeStringTableFromMemoryMappedFile creates a header that must be
  367. // released by MyFree instead of pSetupStringTableDestroy
  368. //
  369. pInfCache->pMatchTable = InitializeStringTableFromMemoryMappedFile(
  370. (PBYTE)BaseAddress+pHeader->MatchTableOffset,
  371. pInfCache->pHeader->MatchTableSize,
  372. pInfCache->pHeader->Locale,
  373. sizeof(CACHEMATCHENTRY)
  374. );
  375. pInfCache->pInfTable = InitializeStringTableFromMemoryMappedFile(
  376. (PBYTE)BaseAddress+pHeader->InfTableOffset,
  377. pInfCache->pHeader->InfTableSize,
  378. pInfCache->pHeader->Locale,
  379. sizeof(CACHEINFENTRY)
  380. );
  381. pInfCache->pListTable = (PCACHELISTENTRY)((PBYTE)BaseAddress+pHeader->ListDataOffset);
  382. pInfCache->ListDataAlloc = 0; // initial size of allocation (0 since this is static)
  383. //
  384. // search table - transient and empty
  385. //
  386. pInfCache->pSearchTable = pStringTableInitialize(sizeof(CACHEHITENTRY));
  387. //
  388. // ok, now did all memory allocations succeed?
  389. //
  390. if(pInfCache->pMatchTable==NULL || pInfCache->pInfTable==NULL || pInfCache->pSearchTable==NULL) {
  391. InfCacheFreeCache(pInfCache);
  392. return NULL;
  393. }
  394. return pInfCache;
  395. //
  396. // for ANSI version, just use default search mode (for now)
  397. //
  398. return NULL;
  399. }
  400. #endif
  401. #ifdef UNICODE
  402. DWORD InfCacheMakeWritable(
  403. IN OUT PINFCACHE pInfCache
  404. )
  405. /*++
  406. Routine Description:
  407. Modifies InfCache in such a way that it can be written to
  408. This is expensive as all previously memory-mapped data must be copied into memory
  409. Arguments:
  410. pInfCache - the cache we want to make writable
  411. Return Value:
  412. status, typically NO_ERROR
  413. --*/
  414. {
  415. PCACHEHEADER pNewCacheHeader = NULL;
  416. PVOID pNewMatchTable = NULL;
  417. PVOID pNewInfTable = NULL;
  418. PCACHELISTENTRY pNewListTable = NULL;
  419. ULONG ListAllocSize = 0;
  420. if(pInfCache == NULL || !pInfCache->bReadOnly) {
  421. //
  422. // not a cache we can/need to modify
  423. //
  424. return NO_ERROR;
  425. }
  426. if (pInfCache->bNoWriteBack) {
  427. //
  428. // we've already attempted this once, cache now invalid
  429. //
  430. return ERROR_INVALID_DATA;
  431. }
  432. MYASSERT(pInfCache->BaseAddress);
  433. MYASSERT(!pInfCache->bDirty);
  434. //
  435. // allocatable data we need to duplicate is
  436. // CACHEHEADER
  437. // MatchStringTable
  438. // InfStringTable
  439. // DataList
  440. //
  441. pNewCacheHeader = (PCACHEHEADER)MyMalloc(sizeof(CACHEHEADER));
  442. if(pNewCacheHeader == NULL) {
  443. goto cleanup;
  444. }
  445. ZeroMemory(pNewCacheHeader,sizeof(CACHEHEADER));
  446. pNewCacheHeader->FileSize = 0;
  447. pNewCacheHeader->Flags = 0;
  448. pNewCacheHeader->InfTableOffset = 0;
  449. pNewCacheHeader->InfTableSize = 0;
  450. pNewCacheHeader->ListDataCount = pInfCache->pHeader->ListDataCount;
  451. pNewCacheHeader->Locale = pInfCache->pHeader->Locale;
  452. pNewCacheHeader->Version = INFCACHE_VERSION;
  453. pNewMatchTable = pStringTableDuplicate(pInfCache->pMatchTable);
  454. if(pNewMatchTable == NULL) {
  455. goto cleanup;
  456. }
  457. pNewInfTable = pStringTableDuplicate(pInfCache->pInfTable);
  458. if(pNewInfTable == NULL) {
  459. goto cleanup;
  460. }
  461. ListAllocSize = pNewCacheHeader->ListDataCount + 32768;
  462. pNewListTable = (PCACHELISTENTRY)MyMalloc(sizeof(CACHELISTENTRY)*ListAllocSize);
  463. if(pNewListTable == NULL) {
  464. goto cleanup;
  465. }
  466. //
  467. // copy the table
  468. //
  469. CopyMemory(pNewListTable,pInfCache->pListTable,pNewCacheHeader->ListDataCount*sizeof(CACHELISTENTRY));
  470. //
  471. // ok, now commit - delete & replace old data
  472. //
  473. pStringTableDestroy(pInfCache->pMatchTable);
  474. pStringTableDestroy(pInfCache->pInfTable);
  475. pSetupUnmapAndCloseFile(pInfCache->FileHandle, pInfCache->MappingHandle, pInfCache->BaseAddress);
  476. pInfCache->FileHandle = INVALID_HANDLE_VALUE;
  477. pInfCache->MappingHandle = NULL;
  478. pInfCache->BaseAddress = NULL;
  479. pInfCache->bReadOnly = FALSE;
  480. pInfCache->pHeader = pNewCacheHeader;
  481. pInfCache->pMatchTable = pNewMatchTable;
  482. pInfCache->pInfTable = pNewInfTable;
  483. pInfCache->pListTable = pNewListTable;
  484. pInfCache->ListDataAlloc = ListAllocSize;
  485. return NO_ERROR;
  486. cleanup:
  487. //
  488. // we don't have enough memory to duplicate
  489. //
  490. if(pNewCacheHeader) {
  491. MyFree(pNewCacheHeader);
  492. }
  493. if(pNewMatchTable) {
  494. pStringTableDestroy(pNewMatchTable);
  495. }
  496. if(pNewInfTable) {
  497. pStringTableDestroy(pNewInfTable);
  498. }
  499. if(pNewListTable) {
  500. MyFree(pNewListTable);
  501. }
  502. return ERROR_NOT_ENOUGH_MEMORY;
  503. }
  504. #endif
  505. #ifdef UNICODE
  506. DWORD InfCacheWriteCache(
  507. IN LPCTSTR InfDirectory,
  508. IN OUT PINFCACHE pInfCache,
  509. IN PSETUP_LOG_CONTEXT LogContext
  510. )
  511. /*++
  512. Routine Description:
  513. Writes a cache file to the INF directory being searched
  514. Worst case scenario is we abandon the write, possibly leaving
  515. a file turd around (until next inf search)
  516. Typically,
  517. 1) we'll write to INFCACHE.0
  518. 2) we'll rename INFCACHE.2 to OLDCACHE.xxx (only if INFCACHE.1&2 exists)
  519. 3) we'll rename INFCACHE.1 to INFCACHE.2
  520. 4) we'll rename INFCACHE.0 to INFCACHE.1
  521. 5) we'll rename INFCACHE.1 to OLDCACHE.xxx
  522. at stage 4, new callers may fail to open INFCACHE.1 and attempt INFCACHE.2
  523. OLDCACHE.xxx will be deleted when last handle to it is closed
  524. Arguments:
  525. pInfCache - the cache we want to make writable
  526. Return Value:
  527. status, typically NO_ERROR
  528. --*/
  529. {
  530. HANDLE hFile;
  531. HANDLE hFile2;
  532. TCHAR InfPath[3][MAX_PATH];
  533. DWORD Offset;
  534. DWORD BytesWritten;
  535. PVOID MatchTableBlock;
  536. PVOID InfTableBlock;
  537. DWORD Err;
  538. DWORD CacheIndex = 0;
  539. //
  540. // don't bother writing it if we don't have to
  541. //
  542. if(pInfCache->bNoWriteBack) {
  543. return ERROR_INVALID_DATA;
  544. }
  545. if(!pInfCache->bDirty || pInfCache->bReadOnly) {
  546. return NO_ERROR;
  547. }
  548. MYASSERT(InfDirectory);
  549. if ((Err = InfCacheGetFileNames(InfDirectory,InfPath))!=NO_ERROR) {
  550. return Err;
  551. }
  552. //
  553. // attempt to open the temporary file for writing
  554. //
  555. hFile = CreateFile(InfPath[0],
  556. GENERIC_WRITE,
  557. FILE_SHARE_DELETE, // exclusive, but can be deleted/renamed
  558. NULL,
  559. CREATE_ALWAYS,
  560. FILE_ATTRIBUTE_NORMAL,
  561. NULL
  562. );
  563. if(hFile == INVALID_HANDLE_VALUE) {
  564. //
  565. // this will fail if we're non-admin, or we're already writing the cache
  566. //
  567. return GetLastError();
  568. }
  569. //
  570. // align past header
  571. //
  572. Offset = CACHE_ALIGN_BLOCK(sizeof(CACHEHEADER));
  573. MYASSERT(Offset>=sizeof(CACHEHEADER));
  574. //
  575. // get information about MatchTable
  576. //
  577. pInfCache->pHeader->MatchTableOffset = Offset;
  578. pInfCache->pHeader->MatchTableSize = pStringTableGetDataBlock(pInfCache->pMatchTable, &MatchTableBlock);
  579. Offset += CACHE_ALIGN_BLOCK(pInfCache->pHeader->MatchTableSize);
  580. MYASSERT(Offset>=pInfCache->pHeader->MatchTableOffset+pInfCache->pHeader->MatchTableSize);
  581. //
  582. // get information about InfTable
  583. //
  584. pInfCache->pHeader->InfTableOffset = Offset;
  585. pInfCache->pHeader->InfTableSize = pStringTableGetDataBlock(pInfCache->pInfTable, &InfTableBlock);
  586. Offset += CACHE_ALIGN_BLOCK(pInfCache->pHeader->InfTableSize);
  587. MYASSERT(Offset>=pInfCache->pHeader->InfTableOffset+pInfCache->pHeader->InfTableSize);
  588. //
  589. // get information about ListData
  590. //
  591. pInfCache->pHeader->ListDataOffset = Offset;
  592. Offset += CACHE_ALIGN_BLOCK((pInfCache->pHeader->ListDataCount*sizeof(CACHELISTENTRY)));
  593. MYASSERT(Offset>=pInfCache->pHeader->ListDataOffset+pInfCache->pHeader->ListDataCount*sizeof(CACHELISTENTRY));
  594. //
  595. // size of file now computed
  596. //
  597. pInfCache->pHeader->FileSize = Offset;
  598. //
  599. // write the file out
  600. //
  601. Offset = 0;
  602. //
  603. // cache header
  604. //
  605. if(!WriteFile(hFile, pInfCache->pHeader, sizeof(CACHEHEADER), &BytesWritten, NULL)) {
  606. Err = GetLastError();
  607. goto clean;
  608. }
  609. MYASSERT(BytesWritten == sizeof(CACHEHEADER));
  610. Offset += BytesWritten;
  611. //
  612. // MatchTable
  613. //
  614. if(AlignForNextBlock(hFile, pInfCache->pHeader->MatchTableOffset - Offset)) {
  615. Offset = pInfCache->pHeader->MatchTableOffset;
  616. } else {
  617. Err = GetLastError();
  618. goto clean;
  619. }
  620. if(!WriteFile(hFile, MatchTableBlock, pInfCache->pHeader->MatchTableSize, &BytesWritten, NULL)) {
  621. Err = GetLastError();
  622. goto clean;
  623. }
  624. MYASSERT(BytesWritten == pInfCache->pHeader->MatchTableSize);
  625. Offset += BytesWritten;
  626. //
  627. // InfTable
  628. //
  629. if(AlignForNextBlock(hFile, pInfCache->pHeader->InfTableOffset - Offset)) {
  630. Offset = pInfCache->pHeader->InfTableOffset;
  631. } else {
  632. Err = GetLastError();
  633. goto clean;
  634. }
  635. if(!WriteFile(hFile, InfTableBlock, pInfCache->pHeader->InfTableSize, &BytesWritten, NULL)) {
  636. Err = GetLastError();
  637. goto clean;
  638. }
  639. MYASSERT(BytesWritten == pInfCache->pHeader->InfTableSize);
  640. Offset += BytesWritten;
  641. //
  642. // ListData
  643. //
  644. if(AlignForNextBlock(hFile, pInfCache->pHeader->ListDataOffset - Offset)) {
  645. Offset = pInfCache->pHeader->ListDataOffset;
  646. } else {
  647. Err = GetLastError();
  648. goto clean;
  649. }
  650. if(!WriteFile(hFile, pInfCache->pListTable, pInfCache->pHeader->ListDataCount*sizeof(CACHELISTENTRY), &BytesWritten, NULL)) {
  651. Err = GetLastError();
  652. goto clean;
  653. }
  654. MYASSERT(BytesWritten == pInfCache->pHeader->ListDataCount*sizeof(CACHELISTENTRY));
  655. Offset += BytesWritten;
  656. //
  657. // final padding
  658. //
  659. if(AlignForNextBlock(hFile, pInfCache->pHeader->FileSize - Offset)) {
  660. Offset = pInfCache->pHeader->FileSize;
  661. } else {
  662. Err = GetLastError();
  663. goto clean;
  664. }
  665. FlushFileBuffers(hFile);
  666. //
  667. // new cache written, do we need to shuffle primary to backup?
  668. //
  669. hFile2 = CreateFile(InfPath[1],
  670. GENERIC_READ,
  671. FILE_SHARE_READ|FILE_SHARE_DELETE, // lock this file in place
  672. NULL,
  673. OPEN_EXISTING,
  674. FILE_ATTRIBUTE_NORMAL,
  675. NULL
  676. );
  677. if(hFile2 != INVALID_HANDLE_VALUE) {
  678. //
  679. // ok, we have a primary, so back it up
  680. // delete the old backup first
  681. // once in place, any new opens will find it in backup position
  682. // until we move and release new cache
  683. //
  684. MarkForDelete(InfPath[2]);
  685. MoveFile(InfPath[1],InfPath[2]);
  686. CloseHandle(hFile2);
  687. }
  688. //
  689. // now attempt to move our cache
  690. //
  691. if(MoveFile(InfPath[0],InfPath[1])) {
  692. CacheIndex = 1;
  693. }
  694. CloseHandle(hFile);
  695. //
  696. // new cache committed & ready for reading
  697. // try not to leave turds around
  698. //
  699. MarkForDelete(InfPath[2]);
  700. MarkForDelete(InfPath[0]);
  701. pInfCache->bDirty = FALSE;
  702. WriteLogEntry(LogContext,
  703. CacheIndex ? DRIVER_LOG_INFO : DRIVER_LOG_ERROR,
  704. CacheIndex ? MSG_LOG_MODIFIED_INF_CACHE : MSG_LOG_FAILED_MODIFY_INF_CACHE,
  705. NULL,
  706. InfPath[CacheIndex]);
  707. return NO_ERROR;
  708. clean:
  709. //
  710. // abandon the file
  711. // delete first, we can do this since we opened the file shared-delete
  712. // don't close before delete, otherwise we might delete a file someone else is writing
  713. //
  714. DeleteFile(InfPath[0]);
  715. CloseHandle(hFile);
  716. return Err;
  717. }
  718. #endif
  719. #ifdef UNICODE
  720. ULONG InfCacheAllocListEntry(
  721. IN OUT PINFCACHE pInfCache,
  722. IN LONG init
  723. )
  724. /*++
  725. Routine Description:
  726. Allocates a single list entry, initializing the datum to init
  727. Side effect: if pInfCache not writable, it will be made writable
  728. Side effect: if pInfCache not dirty, it will be marked dirty
  729. Arguments:
  730. pInfCache - the cache we're going to modify
  731. init - initial value of datum
  732. Return Value:
  733. index of datum, or 0 on failure. (GetLastError indicates error)
  734. --*/
  735. {
  736. DWORD status;
  737. ULONG entry;
  738. if(pInfCache->bReadOnly) {
  739. status = InfCacheMakeWritable(pInfCache);
  740. if(status != NO_ERROR) {
  741. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  742. SetLastError(status);
  743. return 0;
  744. }
  745. }
  746. //
  747. // query free-list
  748. //
  749. entry = pInfCache->pListTable[0].Next;
  750. if(entry) {
  751. //
  752. // allocate from free list - reuse space
  753. //
  754. pInfCache->pListTable[0].Value--;
  755. pInfCache->pListTable[0].Next = pInfCache->pListTable[entry].Next;
  756. pInfCache->pListTable[entry].Value = init;
  757. pInfCache->pListTable[entry].Next = 0;
  758. pInfCache->bDirty = TRUE;
  759. return entry;
  760. }
  761. if(pInfCache->pHeader->ListDataCount >= pInfCache->ListDataAlloc) {
  762. //
  763. // allocate some extra space
  764. //
  765. ULONG CountNewSpace;
  766. PCACHELISTENTRY pNewSpace;
  767. MYASSERT(pInfCache->ListDataAlloc);
  768. CountNewSpace = pInfCache->ListDataAlloc*2;
  769. pNewSpace = (PCACHELISTENTRY)MyRealloc(pInfCache->pListTable,sizeof(CACHELISTENTRY)*CountNewSpace);
  770. if(pNewSpace == NULL) {
  771. //
  772. // ack!
  773. //
  774. pInfCache->bNoWriteBack = TRUE; // junk this cache at end
  775. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  776. return 0;
  777. }
  778. pInfCache->ListDataAlloc = CountNewSpace;
  779. pInfCache->pListTable = pNewSpace;
  780. }
  781. //
  782. // allocate from extra space
  783. //
  784. entry = pInfCache->pHeader->ListDataCount;
  785. pInfCache->pHeader->ListDataCount++;
  786. pInfCache->pListTable[entry].Value = init;
  787. pInfCache->pListTable[entry].Next = 0;
  788. pInfCache->bDirty = TRUE;
  789. return entry;
  790. }
  791. #endif
  792. #ifdef UNICODE
  793. DWORD InfCacheFreeListEntry(
  794. IN OUT PINFCACHE pInfCache,
  795. IN ULONG entry
  796. )
  797. /*++
  798. Routine Description:
  799. Releases a single list entry (no modifications to prev/next links made)
  800. Side effect: if pInfCache not writable, it will be made writable
  801. Side effect: if pInfCache not dirty, it will be marked dirty
  802. Arguments:
  803. pInfCache - the cache we're going to modify
  804. entry - list entry to add to free list
  805. Return Value:
  806. status, typically NO_ERROR
  807. --*/
  808. {
  809. DWORD status;
  810. if(entry == 0 || pInfCache == NULL || entry >= pInfCache->pHeader->ListDataCount) {
  811. return ERROR_INVALID_DATA;
  812. }
  813. if(pInfCache->bReadOnly) {
  814. status = InfCacheMakeWritable(pInfCache);
  815. if(status != NO_ERROR) {
  816. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  817. return status;
  818. }
  819. }
  820. pInfCache->pListTable[entry].Value = -1;
  821. pInfCache->pListTable[entry].Next = pInfCache->pListTable[0].Next;
  822. pInfCache->pListTable[0].Next = entry;
  823. pInfCache->pListTable[0].Value++;
  824. pInfCache->bDirty = TRUE;
  825. return NO_ERROR;
  826. }
  827. #endif
  828. #ifdef UNICODE
  829. DWORD InfCacheRemoveMatchRefToInf(
  830. IN OUT PINFCACHE pInfCache,
  831. IN LONG MatchEntry,
  832. IN LONG InfEntry
  833. )
  834. /*++
  835. Routine Description:
  836. Removes details about a specific INF from specific HWID entry
  837. assumptions: pInfCache already writable
  838. Arguments:
  839. pInfCache - the cache we're going to modify
  840. MatchEntry - the Match list we need to remove INF from
  841. InfEntry - the INF we need to remove from Match list
  842. Return Value:
  843. status, typically NO_ERROR
  844. --*/
  845. {
  846. DWORD status;
  847. CACHEMATCHENTRY matchdata;
  848. ULONG parent_index;
  849. ULONG index;
  850. ULONG newindex;
  851. BOOL head;
  852. MYASSERT(pInfCache);
  853. MYASSERT(!pInfCache->bReadOnly);
  854. MYASSERT(MatchEntry);
  855. MYASSERT(InfEntry);
  856. if(!pStringTableGetExtraData(pInfCache->pMatchTable,MatchEntry,&matchdata,sizeof(matchdata))) {
  857. MYASSERT(FALSE); // should not fail
  858. }
  859. parent_index = 0;
  860. index = matchdata.InfList;
  861. head = FALSE;
  862. while (index) {
  863. newindex = pInfCache->pListTable[index].Next;
  864. if (pInfCache->pListTable[index].Value == InfEntry) {
  865. //
  866. // remove
  867. //
  868. pInfCache->bDirty = TRUE;
  869. if(parent_index) {
  870. pInfCache->pListTable[parent_index].Next = newindex;
  871. } else {
  872. matchdata.InfList = newindex;
  873. head = TRUE;
  874. }
  875. status = InfCacheFreeListEntry(pInfCache,index);
  876. if(status != NO_ERROR) {
  877. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  878. return status;
  879. }
  880. } else {
  881. parent_index = index;
  882. }
  883. index = newindex;
  884. }
  885. if (head) {
  886. //
  887. // we modified the head item
  888. //
  889. if(!pStringTableSetExtraData(pInfCache->pMatchTable,MatchEntry,&matchdata,sizeof(matchdata))) {
  890. MYASSERT(FALSE); // should not fail
  891. }
  892. }
  893. return NO_ERROR;
  894. }
  895. #endif
  896. #ifdef UNICODE
  897. DWORD InfCacheRemoveInf(
  898. IN OUT PINFCACHE pInfCache,
  899. IN LONG nHitEntry,
  900. IN PCACHEINFENTRY inf_entry
  901. )
  902. /*++
  903. Routine Description:
  904. Removes details about a specific INF from cache
  905. Side effect: if pInfCache not writable, it will be made writable
  906. Side effect: if pInfCache not dirty, it will be marked dirty
  907. Arguments:
  908. pInfCache - the cache we're going to modify
  909. nHitEntry - string id in Inf StringTable
  910. inf_entry - structure obtained from Inf StringTable
  911. Return Value:
  912. status, typically NO_ERROR
  913. --*/
  914. {
  915. DWORD status;
  916. DWORD hwstatus;
  917. ULONG parent_index;
  918. CACHEINFENTRY dummy_entry;
  919. MYASSERT(inf_entry); // later we may make this optional
  920. MYASSERT(nHitEntry);
  921. if(inf_entry->MatchList == CIE_INF_INVALID) {
  922. //
  923. // already showing as deleted
  924. //
  925. return NO_ERROR;
  926. }
  927. if(pInfCache == NULL || pInfCache->bNoWriteBack) {
  928. return ERROR_INVALID_DATA;
  929. }
  930. if(pInfCache->bReadOnly) {
  931. status = InfCacheMakeWritable(pInfCache);
  932. if(status != NO_ERROR) {
  933. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  934. return status;
  935. }
  936. }
  937. pInfCache->bDirty = TRUE;
  938. parent_index = inf_entry->MatchList;
  939. //
  940. // invalidate inf_entry
  941. //
  942. dummy_entry.MatchList = CIE_INF_INVALID;
  943. dummy_entry.FileTime.dwLowDateTime = 0;
  944. dummy_entry.FileTime.dwHighDateTime = 0;
  945. dummy_entry.MatchFlags = CIEF_INF_NOTINF;
  946. if(!pStringTableSetExtraData(pInfCache->pInfTable,nHitEntry,&dummy_entry,sizeof(dummy_entry))) {
  947. MYASSERT(FALSE); // should not fail
  948. }
  949. //
  950. // parse through and delete list of match ID's
  951. //
  952. hwstatus = NO_ERROR;
  953. while(parent_index>0 && parent_index<pInfCache->pHeader->ListDataCount) {
  954. LONG value = pInfCache->pListTable[parent_index].Value;
  955. ULONG next = pInfCache->pListTable[parent_index].Next;
  956. //
  957. // free the list entry for re-use
  958. //
  959. status = InfCacheFreeListEntry(pInfCache,parent_index);
  960. if(status != NO_ERROR) {
  961. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  962. hwstatus = status;
  963. }
  964. parent_index = next;
  965. //
  966. // for each Match ID, delete all references to the INF
  967. //
  968. status = InfCacheRemoveMatchRefToInf(pInfCache,value,nHitEntry);
  969. if(hwstatus == NO_ERROR) {
  970. hwstatus = status;
  971. }
  972. }
  973. return hwstatus;
  974. }
  975. #endif
  976. #ifdef UNICODE
  977. LONG InfCacheLookupInf(
  978. IN OUT PINFCACHE pInfCache,
  979. IN LPWIN32_FIND_DATA FindFileData,
  980. OUT PCACHEINFENTRY inf_entry
  981. )
  982. /*++
  983. Routine Description:
  984. looks up the file as given by FindFileData to see if it's in the cache
  985. If it's in the cache marked valid, and the date-stamp in cache is same as date-stamp of INF
  986. then it's a 'HIT'
  987. If it's in the cache marked valid, but date-stamp is wrong, then it's deleted and considered
  988. a "MISS'
  989. All other cases, consider it a 'MISS'
  990. Arguments:
  991. pInfCache - the cache we're using
  992. FindFileData - information about a specific file we're looking at
  993. inf_entry - structure obtained from Inf StringTable
  994. Return Value:
  995. -1 for a 'MISS'. StringID of INF for a 'HIT'
  996. inf_entry filled out with MatchList == CIE_INF_INVALID for a miss.
  997. --*/
  998. {
  999. LONG i;
  1000. DWORD StringLength;
  1001. MYASSERT(pInfCache);
  1002. //
  1003. // determine if the cache entry of pInfCache is considered valid
  1004. //
  1005. i = pStringTableLookUpString(pInfCache->pInfTable,
  1006. FindFileData->cFileName,
  1007. &StringLength,
  1008. NULL, // hash value
  1009. NULL, // find context
  1010. STRTAB_CASE_INSENSITIVE,
  1011. inf_entry,
  1012. sizeof(CACHEINFENTRY));
  1013. if(i>=0 && inf_entry->MatchList != CIE_INF_INVALID) {
  1014. //
  1015. // cache hit (and matchlist is valid)
  1016. //
  1017. if(CompareFileTime(&inf_entry->FileTime,&FindFileData->ftLastWriteTime)==0) {
  1018. //
  1019. // valid cache hit
  1020. //
  1021. return i;
  1022. }
  1023. //
  1024. // cache out of date miss
  1025. // although we'll rebuild it later, let's use this opportunity to delete the entry
  1026. //
  1027. InfCacheRemoveInf(pInfCache,i,inf_entry);
  1028. }
  1029. //
  1030. // we're here because we have a miss, however fill in a new (empty) inf_entry
  1031. // MatchList set to CIE_INF_INVALID to indicate list is invalid and inf must be searched
  1032. //
  1033. inf_entry->FileTime = FindFileData->ftLastWriteTime;
  1034. inf_entry->MatchList = CIE_INF_INVALID;
  1035. inf_entry->MatchFlags = CIEF_INF_NOTINF;
  1036. return -1;
  1037. }
  1038. #endif
  1039. #ifdef UNICODE
  1040. ULONG InfCacheAddListTail(
  1041. IN OUT PINFCACHE pInfCache,
  1042. IN OUT PULONG head,
  1043. IN OUT PULONG tail,
  1044. IN LONG value
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Adds value to tail of a list where *tail is an entry in the list
  1049. Arguments:
  1050. pInfCache - cache to modify
  1051. head - head of list
  1052. tail - DataList entry
  1053. value - data to add
  1054. Return Value:
  1055. new entry position, 0 on error (GetLastError() returns error)
  1056. --*/
  1057. {
  1058. ULONG next;
  1059. ULONG first;
  1060. MYASSERT(pInfCache);
  1061. MYASSERT(head == NULL || head != tail);
  1062. if (tail) {
  1063. first = *tail;
  1064. } else if (head) {
  1065. first = *head;
  1066. } else {
  1067. MYASSERT(head || tail);
  1068. }
  1069. if (!first) {
  1070. next = InfCacheAllocListEntry(pInfCache,value);
  1071. if (!next) {
  1072. return 0;
  1073. }
  1074. if (head) {
  1075. *head = next;
  1076. }
  1077. } else {
  1078. //
  1079. // move head to last item in list
  1080. //
  1081. while(pInfCache->pListTable[first].Next) {
  1082. first = pInfCache->pListTable[first].Next;
  1083. }
  1084. next = InfCacheAllocListEntry(pInfCache,value);
  1085. if(!next) {
  1086. return 0;
  1087. }
  1088. pInfCache->pListTable[first].Next = next;
  1089. }
  1090. if(tail) {
  1091. *tail = next;
  1092. }
  1093. return next;
  1094. }
  1095. #endif
  1096. #ifdef UNICODE
  1097. LONG InfCacheAddMatchItem(
  1098. IN OUT PINFCACHE pInfCache,
  1099. IN LPCTSTR key,
  1100. IN LONG InfEntry
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. Given an INF StringID (InfEntry) and match key,
  1105. obtain (and return) Match StringID
  1106. while also adding InfEntry to head of Match's INF list
  1107. (if not already at head)
  1108. Order is not particularly important, however adding to head is
  1109. quicker to do, and easier to reduce number of times we add inf
  1110. if match id is referenced multiple times
  1111. Arguments:
  1112. pInfCache - cache to modify
  1113. key - match string (buffer must be writable)
  1114. InfEntry - StringID
  1115. Return Value:
  1116. new entry in match table, -1 on error (GetLastError() returns error)
  1117. --*/
  1118. {
  1119. LONG MatchIndex;
  1120. CACHEMATCHENTRY matchentry;
  1121. DWORD StringLength;
  1122. MYASSERT(pInfCache);
  1123. MYASSERT(key);
  1124. MYASSERT(InfEntry>=0);
  1125. //
  1126. // if cache is invalid, we'll skip this as optimization
  1127. //
  1128. if(pInfCache->bNoWriteBack) {
  1129. SetLastError(ERROR_INVALID_DATA);
  1130. return -1;
  1131. }
  1132. MatchIndex = pStringTableLookUpString(pInfCache->pMatchTable,
  1133. (LPTSTR)key, // will not be modified
  1134. &StringLength,
  1135. NULL, // hash value
  1136. NULL, // find context
  1137. STRTAB_CASE_INSENSITIVE,
  1138. &matchentry,
  1139. sizeof(matchentry));
  1140. if(MatchIndex < 0) {
  1141. //
  1142. // entirely new entry
  1143. //
  1144. matchentry.InfList = InfCacheAllocListEntry(pInfCache,InfEntry);
  1145. if(matchentry.InfList == 0) {
  1146. return -1;
  1147. }
  1148. MatchIndex = pStringTableAddString(pInfCache->pMatchTable,
  1149. (LPTSTR)key, // will not be modified
  1150. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1151. &matchentry,
  1152. sizeof(matchentry));
  1153. if(MatchIndex<0) {
  1154. pInfCache->bNoWriteBack = TRUE;
  1155. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1156. return -1;
  1157. }
  1158. } else {
  1159. MYASSERT(matchentry.InfList<pInfCache->pHeader->ListDataCount);
  1160. //
  1161. // if we came across this same match earlier for this inf,
  1162. // the inf should still be at head of list
  1163. // the world doesn't come to an end though if we end up adding
  1164. // the inf twice - we check for this when deleting the inf
  1165. //
  1166. if (pInfCache->pListTable[matchentry.InfList].Value != InfEntry) {
  1167. ULONG newentry = InfCacheAllocListEntry(pInfCache,InfEntry);
  1168. if(newentry == 0) {
  1169. return -1;
  1170. }
  1171. pInfCache->pListTable[newentry].Next = matchentry.InfList;
  1172. matchentry.InfList = newentry;
  1173. if(!pStringTableSetExtraData(pInfCache->pMatchTable,MatchIndex,&matchentry,sizeof(matchentry))) {
  1174. MYASSERT(FALSE); // should not fail
  1175. }
  1176. }
  1177. }
  1178. return MatchIndex;
  1179. }
  1180. #endif
  1181. #ifdef UNICODE
  1182. LONG InfCacheAddInf(
  1183. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1184. IN OUT PINFCACHE pInfCache,
  1185. IN LPWIN32_FIND_DATA FindFileData,
  1186. OUT PCACHEINFENTRY inf_entry,
  1187. IN PLOADED_INF pInf
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. Called to add a newly discovered INF to the cache
  1192. If hINF is "bad", then we'll mark the INF as an exclusion
  1193. so we don't waste time with it in future
  1194. If we return with an error, caller knows that the INF
  1195. must be searched if it can be searched
  1196. Arguments:
  1197. LogContext - logging context for errors
  1198. pInfCache - cache to modify
  1199. FindFileData - contains name of INF and date-stamp
  1200. inf_entry - returns list of match ID's associated with INF
  1201. pINF - opened INF to add information about. NOTE: Either this INF must
  1202. be locked by the caller, or the INF cannot be accessed by any other
  1203. thread. THIS ROUTINE DOES NOT DO LOCKING ON THE INF.
  1204. Return Value:
  1205. InfEntry - -1 if error (GetLastError returns status)
  1206. --*/
  1207. {
  1208. //
  1209. // FindFileData contains name & date-stamp of INF
  1210. // we need to process all search information out of the INF
  1211. //
  1212. LONG nInfIndex = -1;
  1213. LONG nMatchId = -1;
  1214. ULONG last_list_entry = 0;
  1215. ULONG head_list_entry = 0;
  1216. DWORD Err = NO_ERROR;
  1217. PCTSTR MatchString;
  1218. GUID guid;
  1219. PINF_SECTION MfgListSection;
  1220. PINF_LINE MfgListLine;
  1221. UINT MfgListLineIndex;
  1222. PTSTR CurMfgSecName;
  1223. TCHAR CurMfgSecWithExt[MAX_SECT_NAME_LEN];
  1224. MYASSERT(pInfCache);
  1225. MYASSERT(FindFileData);
  1226. MYASSERT(inf_entry);
  1227. if (pInfCache->bNoWriteBack) {
  1228. //
  1229. // cache is already bad, so don't waste time updating it
  1230. // note though that the INF should be searched
  1231. //
  1232. return ERROR_INVALID_DATA;
  1233. }
  1234. if(pInfCache->bReadOnly) {
  1235. Err = InfCacheMakeWritable(pInfCache);
  1236. if(Err != NO_ERROR) {
  1237. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  1238. return Err;
  1239. }
  1240. }
  1241. //
  1242. // this stuff should be set up earlier
  1243. //
  1244. MYASSERT(inf_entry->MatchList == CIE_INF_INVALID);
  1245. MYASSERT(inf_entry->MatchFlags == CIEF_INF_NOTINF);
  1246. MYASSERT(inf_entry->FileTime.dwHighDateTime = FindFileData->ftLastWriteTime.dwHighDateTime);
  1247. MYASSERT(inf_entry->FileTime.dwLowDateTime = FindFileData->ftLastWriteTime.dwLowDateTime);
  1248. MYASSERT(!pInfCache->bReadOnly);
  1249. //
  1250. // we need the InfIndex before we start (also mark this as file physically exist)
  1251. //
  1252. inf_entry->MatchList = 0;
  1253. nInfIndex = pStringTableAddString(pInfCache->pInfTable,
  1254. FindFileData->cFileName,
  1255. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1256. inf_entry,
  1257. sizeof(CACHEINFENTRY));
  1258. if (nInfIndex<0) {
  1259. //
  1260. // ack, out of memory
  1261. //
  1262. Err = ERROR_NOT_ENOUGH_MEMORY;
  1263. goto cleanup;
  1264. }
  1265. if(pInf) {
  1266. if(pInf->Style == INF_STYLE_WIN4) {
  1267. inf_entry->MatchFlags |= CIEF_INF_WIN4;
  1268. if(pInf->InfSourceMediaType == SPOST_URL) {
  1269. inf_entry->MatchFlags |= CIEF_INF_URL;
  1270. }
  1271. //
  1272. // for a Win4 style INF, we're going to add Class GUID & Class Name to the
  1273. // pool of ID's we can match on
  1274. // note that if one or the other is missing, we don't lookup here as registry
  1275. // information could change
  1276. // we do the cross-lookups at the time of the INF search
  1277. //
  1278. if((MatchString = pSetupGetVersionDatum(&pInf->VersionBlock, pszClassGuid))!=NULL) {
  1279. //
  1280. // we found a class GUID
  1281. //
  1282. inf_entry->MatchFlags |= CIEF_INF_CLASSGUID;
  1283. nMatchId = InfCacheAddMatchItem(pInfCache,MatchString,nInfIndex);
  1284. if (nMatchId<0) {
  1285. Err = GetLastError();
  1286. goto cleanup;
  1287. }
  1288. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1289. Err = GetLastError();
  1290. goto cleanup;
  1291. }
  1292. //
  1293. // check out a special case {0}
  1294. //
  1295. if(pSetupGuidFromString(MatchString, &guid) == NO_ERROR && pSetupIsGuidNull(&guid)) {
  1296. inf_entry->MatchFlags |= CIEF_INF_NULLGUID;
  1297. }
  1298. }
  1299. if((MatchString = pSetupGetVersionDatum(&pInf->VersionBlock, pszClass))!=NULL) {
  1300. //
  1301. // we found a class name
  1302. //
  1303. inf_entry->MatchFlags |= CIEF_INF_CLASSNAME;
  1304. nMatchId = InfCacheAddMatchItem(pInfCache,MatchString,nInfIndex);
  1305. if (nMatchId<0) {
  1306. Err = GetLastError();
  1307. goto cleanup;
  1308. }
  1309. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1310. Err = GetLastError();
  1311. goto cleanup;
  1312. }
  1313. }
  1314. //
  1315. // enumerate all manufacturers
  1316. //
  1317. if((MfgListSection = InfLocateSection(pInf, pszManufacturer, NULL)) &&
  1318. MfgListSection->LineCount) {
  1319. //
  1320. // We have a [Manufacturer] section and there is at least one
  1321. // line within it.
  1322. //
  1323. inf_entry->MatchFlags |= CIEF_INF_MANUFACTURER;
  1324. for(MfgListLineIndex = 0;
  1325. InfLocateLine(pInf, MfgListSection, NULL, &MfgListLineIndex, &MfgListLine);
  1326. MfgListLineIndex++) {
  1327. //
  1328. // Make sure the current line is one of these valid forms:
  1329. //
  1330. // MfgDisplayNameAndModelsSection
  1331. // MfgDisplayName = MfgModelsSection [,TargetDecoration...]
  1332. //
  1333. if(!ISSEARCHABLE(MfgListLine)) {
  1334. //
  1335. // We have a line with multiple fields but no key--skip
  1336. // it.
  1337. //
  1338. continue;
  1339. }
  1340. if(CurMfgSecName = InfGetField(pInf, MfgListLine, 1, NULL)) {
  1341. INFCONTEXT device;
  1342. //
  1343. // Check to see if there is an applicable
  1344. // TargetDecoration entry for this manufacturer's
  1345. // models section (if so, the models section name will
  1346. // be appended with that decoration).
  1347. //
  1348. if(GetDecoratedModelsSection(LogContext,
  1349. pInf,
  1350. MfgListLine,
  1351. NULL,
  1352. CurMfgSecWithExt)) {
  1353. //
  1354. // From here on, use the decorated models section...
  1355. //
  1356. CurMfgSecName = CurMfgSecWithExt;
  1357. }
  1358. if(SetupFindFirstLine(pInf, CurMfgSecName, NULL, &device)) {
  1359. do {
  1360. TCHAR devname[LINE_LEN];
  1361. DWORD devindex;
  1362. DWORD fields = SetupGetFieldCount(&device);
  1363. //
  1364. // for a device line, field 1 = section, field 2+ = match keys
  1365. //
  1366. for(devindex=2;devindex<=fields;devindex++) {
  1367. if(SetupGetStringField(&device,devindex,devname,LINE_LEN,NULL)) {
  1368. //
  1369. // finally, a hit key to add
  1370. //
  1371. nMatchId = InfCacheAddMatchItem(pInfCache,devname,nInfIndex);
  1372. if(nMatchId<0) {
  1373. Err = GetLastError();
  1374. goto cleanup;
  1375. }
  1376. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1377. Err = GetLastError();
  1378. goto cleanup;
  1379. }
  1380. }
  1381. }
  1382. } while(SetupFindNextLine(&device,&device));
  1383. }
  1384. }
  1385. }
  1386. }
  1387. } else if (pInf->Style == INF_STYLE_OLDNT) {
  1388. //
  1389. // for an OLDNT style INF, we'll add Legacy class name to the pool of ID's
  1390. // we can match on
  1391. //
  1392. inf_entry->MatchFlags |= CIEF_INF_OLDNT;
  1393. if((MatchString = pSetupGetVersionDatum(&pInf->VersionBlock, pszClass))!=NULL) {
  1394. //
  1395. // we found a (legacy) class name
  1396. //
  1397. inf_entry->MatchFlags |= CIEF_INF_CLASSNAME;
  1398. nMatchId = InfCacheAddMatchItem(pInfCache,MatchString,nInfIndex);
  1399. if (nMatchId<0) {
  1400. Err = GetLastError();
  1401. goto cleanup;
  1402. }
  1403. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1404. Err = GetLastError();
  1405. goto cleanup;
  1406. }
  1407. }
  1408. } else {
  1409. MYASSERT(FALSE);
  1410. }
  1411. }
  1412. //
  1413. // now re-write the inf data with new flags & match patterns
  1414. //
  1415. inf_entry->MatchList = head_list_entry;
  1416. if(!pStringTableSetExtraData(pInfCache->pInfTable,nInfIndex,inf_entry,sizeof(CACHEINFENTRY))) {
  1417. MYASSERT(FALSE); // should not fail
  1418. }
  1419. return nInfIndex;
  1420. cleanup:
  1421. pInfCache->bNoWriteBack = TRUE;
  1422. MYASSERT(Err);
  1423. SetLastError(Err);
  1424. return -1;
  1425. }
  1426. #endif
  1427. #ifdef UNICODE
  1428. LONG InfCacheSearchTableLookup(
  1429. IN OUT PINFCACHE pInfCache,
  1430. IN PCTSTR filename,
  1431. IN OUT PCACHEHITENTRY hitstats)
  1432. /*++
  1433. Routine Description:
  1434. Looks up filename in the search table, returning search information
  1435. if filename was not already in search table, it's added
  1436. Arguments:
  1437. pInfCache - cache to modify
  1438. filename - file to obtain hit-entry information for
  1439. hitstats - information obtained (such as if this files been processed etc)
  1440. Return Value:
  1441. index in search table (-1 if error)
  1442. --*/
  1443. {
  1444. LONG nHitIndex;
  1445. DWORD StringLength;
  1446. MYASSERT(pInfCache);
  1447. MYASSERT(filename);
  1448. MYASSERT(hitstats);
  1449. nHitIndex = pStringTableLookUpString(pInfCache->pSearchTable,
  1450. (PTSTR)filename, // filename wont be changed
  1451. &StringLength,
  1452. NULL, // hash value
  1453. NULL, // find context
  1454. STRTAB_CASE_INSENSITIVE,
  1455. hitstats,
  1456. sizeof(CACHEHITENTRY));
  1457. if(nHitIndex < 0) {
  1458. //
  1459. // entirely new entry (hitstats expected to have a value)
  1460. //
  1461. nHitIndex = pStringTableAddString(pInfCache->pSearchTable,
  1462. (PTSTR)filename, // filename wont be changed
  1463. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1464. hitstats,
  1465. sizeof(CACHEHITENTRY));
  1466. if (nHitIndex<0) {
  1467. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1468. return -1;
  1469. }
  1470. }
  1471. return nHitIndex;
  1472. }
  1473. #endif
  1474. #ifdef UNICODE
  1475. ULONG InfCacheSearchTableSetFlags(
  1476. IN OUT PINFCACHE pInfCache,
  1477. IN PCTSTR filename,
  1478. IN ULONG setflags,
  1479. IN ULONG clrflags
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. Modifies flags associated with a filename
  1484. Arguments:
  1485. pInfCache - cache to modify
  1486. filename - file to obtain hit-entry information for
  1487. setflags - flags to set
  1488. clrflags - flags to clear
  1489. Return Value:
  1490. combined flags, or (ULONG)(-1) on error.
  1491. --*/
  1492. {
  1493. CACHEHITENTRY searchentry;
  1494. LONG nHitIndex;
  1495. ULONG flags;
  1496. MYASSERT(pInfCache);
  1497. MYASSERT(filename);
  1498. searchentry.Flags = setflags; // prime in case of new entry
  1499. nHitIndex = InfCacheSearchTableLookup(pInfCache,filename,&searchentry);
  1500. if(nHitIndex<0) {
  1501. return (ULONG)(-1);
  1502. }
  1503. flags = (searchentry.Flags&~clrflags) | setflags;
  1504. if (flags != searchentry.Flags) {
  1505. searchentry.Flags = flags;
  1506. if(!pStringTableSetExtraData(pInfCache->pSearchTable,nHitIndex,&searchentry,sizeof(searchentry))) {
  1507. MYASSERT(FALSE); // should not fail
  1508. }
  1509. }
  1510. return searchentry.Flags;
  1511. }
  1512. #endif
  1513. #ifdef UNICODE
  1514. DWORD InfCacheMarkMatchInfs(
  1515. IN OUT PINFCACHE pInfCache,
  1516. IN PCTSTR MatchString,
  1517. IN ULONG MatchFlag
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. Called to iterate through the INF's associated with MatchString
  1522. and flag them using MatchFlag
  1523. Arguments:
  1524. pInfCache - cache to check (may modify search data)
  1525. MatchString - match string to include
  1526. MatchFlag - flag to set in all INF's associated with match string
  1527. Return Value:
  1528. status - typically NO_ERROR
  1529. --*/
  1530. {
  1531. LONG MatchIndex;
  1532. DWORD StringLength;
  1533. CACHEMATCHENTRY matchentry;
  1534. ULONG entry;
  1535. PTSTR InfName;
  1536. ULONG SearchFlags;
  1537. MYASSERT(pInfCache);
  1538. MYASSERT(MatchString);
  1539. MYASSERT(MatchFlag);
  1540. //
  1541. // find list of Inf's associated with match string
  1542. //
  1543. MatchIndex = pStringTableLookUpString(pInfCache->pMatchTable,
  1544. (PTSTR)MatchString, // it will not be modified
  1545. &StringLength,
  1546. NULL, // hash value
  1547. NULL, // find context
  1548. STRTAB_CASE_INSENSITIVE,
  1549. &matchentry,
  1550. sizeof(matchentry));
  1551. if(MatchIndex < 0) {
  1552. //
  1553. // no match
  1554. //
  1555. return NO_ERROR;
  1556. }
  1557. for(entry = matchentry.InfList ; entry > 0 && entry < pInfCache->pHeader->ListDataCount ; entry = pInfCache->pListTable[entry].Next) {
  1558. LONG InfEntry = pInfCache->pListTable[entry].Value;
  1559. //
  1560. // obtain name of Inf
  1561. //
  1562. InfName = pStringTableStringFromId(pInfCache->pInfTable,InfEntry);
  1563. SearchFlags = InfCacheSearchTableSetFlags(pInfCache,InfName,MatchFlag,0);
  1564. if(SearchFlags == (ULONG)(-1)) {
  1565. //
  1566. // failed - huh?
  1567. // abort into fail-safe pass
  1568. //
  1569. MYASSERT(SearchFlags != (ULONG)(-1));
  1570. return GetLastError();
  1571. }
  1572. }
  1573. return NO_ERROR;
  1574. }
  1575. #endif
  1576. #ifdef UNICODE
  1577. BOOL
  1578. InfCacheSearchEnum(
  1579. IN PVOID StringTable,
  1580. IN LONG StringId,
  1581. IN PCTSTR String,
  1582. IN PVOID ExtraData,
  1583. IN UINT ExtraDataSize,
  1584. IN LPARAM lParam
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. Callback for Phase-3 of InfCacheSearchDirectory
  1589. Arguments:
  1590. StringTable - unused
  1591. StringId - unused
  1592. String - used to form INF name
  1593. ExtraData - points to flags
  1594. ExtraDataSize - unused
  1595. lParam - points to InfCacheEnumData
  1596. Return Value:
  1597. always TRUE unless out of memory condition
  1598. --*/
  1599. {
  1600. PINFCACHE_ENUMDATA enum_data = (PINFCACHE_ENUMDATA)lParam;
  1601. CACHEHITENTRY *hit_stats = (CACHEHITENTRY *)ExtraData;
  1602. PTSTR InfFullPath = NULL;
  1603. DWORD InfFullPathSize;
  1604. BOOL b;
  1605. WIN32_FIND_DATA FindData;
  1606. PLOADED_INF pInf = NULL;
  1607. UINT ErrorLineNumber;
  1608. BOOL PnfWasUsed;
  1609. BOOL cont = TRUE;
  1610. MYASSERT(ExtraDataSize == sizeof(CACHEHITENTRY));
  1611. MYASSERT(String);
  1612. MYASSERT(enum_data);
  1613. MYASSERT(hit_stats);
  1614. MYASSERT(enum_data->Requirement);
  1615. MYASSERT(enum_data->Callback);
  1616. //
  1617. // see if this is an INF of interest
  1618. //
  1619. if((hit_stats->Flags & enum_data->Requirement) == enum_data->Requirement) {
  1620. //
  1621. // this is a HIT
  1622. // we need to open HINF
  1623. //
  1624. InfFullPathSize = lstrlen(enum_data->InfDir)+MAX_PATH+2;
  1625. InfFullPath = MyMalloc(InfFullPathSize*sizeof(TCHAR));
  1626. if (!InfFullPath) {
  1627. return TRUE; // out of memory (does not abort search)
  1628. }
  1629. lstrcpy(InfFullPath,enum_data->InfDir);
  1630. pSetupConcatenatePaths(InfFullPath,String,InfFullPathSize,NULL);
  1631. if(b = FileExists(InfFullPath, &FindData)) {
  1632. if(LoadInfFile(InfFullPath,
  1633. &FindData,
  1634. INF_STYLE_WIN4 | INF_STYLE_OLDNT, // we've filtered this ourselves
  1635. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | LDINF_FLAG_ALWAYS_TRY_PNF,
  1636. NULL,
  1637. NULL,
  1638. NULL,
  1639. NULL,
  1640. enum_data->LogContext,
  1641. &pInf,
  1642. &ErrorLineNumber,
  1643. &PnfWasUsed) != NO_ERROR) {
  1644. pInf = NULL;
  1645. WriteLogEntry(
  1646. enum_data->LogContext,
  1647. DRIVER_LOG_VVERBOSE,
  1648. MSG_LOG_COULD_NOT_LOAD_HIT_INF,
  1649. NULL,
  1650. InfFullPath);
  1651. }
  1652. } else {
  1653. pInf = NULL;
  1654. }
  1655. if (pInf) {
  1656. cont = enum_data->Callback(enum_data->LogContext,InfFullPath,pInf,PnfWasUsed,enum_data->Context);
  1657. if(!cont) {
  1658. enum_data->ExitStatus = GetLastError();
  1659. MYASSERT(enum_data->ExitStatus);
  1660. }
  1661. FreeInfFile(pInf);
  1662. }
  1663. }
  1664. if (InfFullPath) {
  1665. MyFree(InfFullPath);
  1666. }
  1667. return cont;
  1668. }
  1669. #endif
  1670. DWORD InfCacheSearchDirectory(
  1671. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1672. IN DWORD Action,
  1673. IN PCTSTR InfDir,
  1674. IN InfCacheCallback Callback, OPTIONAL
  1675. IN PVOID Context, OPTIONAL
  1676. IN PCTSTR ClassIdList, OPTIONAL
  1677. IN PCTSTR HwIdList OPTIONAL
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. Main workhorse of the InfCache
  1682. Search a single specified directory
  1683. calling Callback(hInf,Context) for each inf that has a likelyhood of matching
  1684. note that Action flags, ClassId and HwIdList are hints, and Callback may get
  1685. called for any/all INF's Callback must re-check for all search criteria.
  1686. Searching is done in 3 phases
  1687. Phase 1: Parse all INF's in directory. If an INF is not in cache, *almost always* call
  1688. callback. If special inclusions (OLD INF's INF's with no Class GUID's) specified, then
  1689. INF's that match the special criteria are processed here (since they can't be processed
  1690. in Phase 2). All INF's that exist, haven't been processed and haven't been excluded get
  1691. marked with CHE_FLAGS_PENDING ready for phase-2
  1692. Phase 2: Process ClassId and HwIdList matching, setting CHE_FLAGS_GUIDMATCH and
  1693. CHE_FLAGS_IDMATCH apropriately in matching INF's and search criteria flags. Search
  1694. criteria will either be:
  1695. CHE_FLAGS_PENDING - callback on all Win4 style INF's
  1696. CHE_FLAGS_PENDING | CHE_FLAGS_GUIDMATCH - callback on all Win4 INF's that have matching class
  1697. CHE_FLAGS_PENDING | CHE_FLAGS_IDMATCH - wildcard class, matching hardware ID's
  1698. CHE_FLAGS_PENDING | CHE_FLAGS_GUIDMATCH | CHE_FLAGS_IDMATCH - most specific match
  1699. Phase 3: enumerate through all INF's that we've marked with exact same flags as
  1700. search criteria, and call callback on those INF's
  1701. Using this search method, Win4 INF's that are in the cache are always processed last.
  1702. Arguments:
  1703. LogContext - for logging
  1704. InfDir - single directory to search
  1705. Callback - function to call on a likely match
  1706. Context - parameter to pass to function
  1707. ClassIdList (optional) - multi-sz list of class id's (typically guid, name and legacy name)
  1708. HwIdList (optional)- multi-sz list of hardware id's
  1709. Return Value:
  1710. status, typically NO_ERROR
  1711. --*/
  1712. {
  1713. PINFCACHE pInfCache = NULL;
  1714. PTSTR InfPath = NULL;
  1715. UINT PathSize;
  1716. DWORD Err = NO_ERROR;
  1717. WIN32_FIND_DATA FindFileData;
  1718. HANDLE FindHandle = INVALID_HANDLE_VALUE;
  1719. BOOL bNoWriteBack = FALSE;
  1720. LONG InfId;
  1721. LONG SearchId;
  1722. ULONG SearchFlags;
  1723. CACHEINFENTRY inf_entry;
  1724. CACHEHITENTRY hit_stats;
  1725. ULONG ReqFlags;
  1726. INFCACHE_ENUMDATA enum_data;
  1727. PSETUP_LOG_CONTEXT LocalLogContext = NULL;
  1728. BOOL TryPnf = FALSE;
  1729. BOOL TryCache = FALSE;
  1730. MYASSERT(InfDir);
  1731. //
  1732. // obtain cache for directory of interest
  1733. // we should be able to handle a NULL return
  1734. // note that caller can either treat these two bits
  1735. // as an operation (0-3) or as bitmaps
  1736. // the result would be the same
  1737. //
  1738. if(!LogContext) {
  1739. if(CreateLogContext(NULL,TRUE,&LocalLogContext)==NO_ERROR) {
  1740. LogContext = LocalLogContext;
  1741. } else {
  1742. LocalLogContext = NULL;
  1743. Err = ERROR_NOT_ENOUGH_MEMORY;
  1744. goto cleanup;
  1745. }
  1746. }
  1747. WriteLogEntry(
  1748. LogContext,
  1749. DRIVER_LOG_VVERBOSE,
  1750. MSG_LOG_ENUMERATING_FILES,
  1751. NULL,
  1752. InfDir);
  1753. PathSize = lstrlen(InfDir)+10;
  1754. InfPath = MyMalloc(PathSize*sizeof(TCHAR));
  1755. if(!InfPath) {
  1756. Err = ERROR_NOT_ENOUGH_MEMORY;
  1757. goto cleanup;
  1758. }
  1759. lstrcpy(InfPath,InfDir);
  1760. pSetupConcatenatePaths(InfPath,INFCACHE_INF_WILDCARD,PathSize,NULL);
  1761. #ifdef UNICODE
  1762. if (pSetupInfIsFromOemLocation(InfPath,FALSE)) {
  1763. if (Action & INFCACHE_FORCE_CACHE) {
  1764. TryCache = TRUE;
  1765. }
  1766. if (Action & INFCACHE_FORCE_PNF) {
  1767. TryPnf = TRUE;
  1768. }
  1769. } else {
  1770. TryPnf = TRUE;
  1771. //
  1772. // Try using INF cache unless we're doing an INFCACHE_ENUMALL
  1773. //
  1774. if((Action & INFCACHE_ACTIONBITS) != INFCACHE_ENUMALL) {
  1775. TryCache = TRUE;
  1776. }
  1777. }
  1778. if (!TryCache) {
  1779. //
  1780. // directory is not in our default search path
  1781. // treat as INFCACHE_ENUMALL
  1782. //
  1783. pInfCache = NULL;
  1784. } else {
  1785. switch(Action & INFCACHE_ACTIONBITS) {
  1786. case INFCACHE_NOWRITE:
  1787. pInfCache = InfCacheLoadCache(InfDir,LogContext);
  1788. bNoWriteBack = TRUE;
  1789. break;
  1790. case INFCACHE_DEFAULT:
  1791. pInfCache = InfCacheLoadCache(InfDir,LogContext);
  1792. break;
  1793. case INFCACHE_REBUILD:
  1794. pInfCache = InfCacheCreateNewCache(LogContext);
  1795. break;
  1796. case INFCACHE_ENUMALL:
  1797. pInfCache = NULL;
  1798. break;
  1799. default:
  1800. MYASSERT(FALSE);
  1801. }
  1802. }
  1803. #else
  1804. pInfCache = NULL;
  1805. #endif
  1806. //
  1807. // first phase - enumerate the INF directory
  1808. //
  1809. FindHandle = FindFirstFile(InfPath,&FindFileData);
  1810. if(FindHandle != INVALID_HANDLE_VALUE) {
  1811. do {
  1812. BOOL NewInf = FALSE;
  1813. BOOL bCallCallback = FALSE;
  1814. PLOADED_INF pInf = NULL;
  1815. UINT ErrorLineNumber;
  1816. BOOL PnfWasUsed;
  1817. #ifdef UNICODE
  1818. if(!pInfCache || pInfCache->bNoWriteBack) {
  1819. //
  1820. // fallen into failsafe mode
  1821. //
  1822. bCallCallback = TRUE;
  1823. } else {
  1824. //
  1825. // mark this INF as existing
  1826. //
  1827. SearchFlags = InfCacheSearchTableSetFlags(pInfCache,
  1828. FindFileData.cFileName,
  1829. CHE_FLAGS_PENDING, // start off expecting this INF to be processed later
  1830. 0);
  1831. if(SearchFlags == (ULONG)(-1)) {
  1832. //
  1833. // failed - handle here
  1834. //
  1835. bCallCallback = TRUE;
  1836. }
  1837. InfId = InfCacheLookupInf(pInfCache,&FindFileData,&inf_entry);
  1838. if (InfId<0) {
  1839. NewInf = TRUE;
  1840. } else {
  1841. #if 0
  1842. //
  1843. // handle special inclusions (we can't handle these in Phase 2)
  1844. //
  1845. if (((Action&INFCACHE_INC_OLDINFS) && (inf_entry.MatchFlags&CIEF_INF_OLDINF)) ||
  1846. ((Action&INFCACHE_INC_NOCLASS) && (inf_entry.MatchFlags&CIEF_INF_NOCLASS))) {
  1847. bCallCallback = TRUE;
  1848. }
  1849. #endif
  1850. //
  1851. // handle exclusions (so that they will get excluded in Phase 2)
  1852. // exclusions are different for OLDNT and WIN4
  1853. //
  1854. if (inf_entry.MatchFlags & CIEF_INF_WIN4) {
  1855. //
  1856. // WIN4 INF
  1857. //
  1858. if(((Action & INFCACHE_EXC_URL) && (inf_entry.MatchFlags & CIEF_INF_URL)) ||
  1859. ((Action & INFCACHE_EXC_NULLCLASS) && (inf_entry.MatchFlags & CIEF_INF_NULLGUID)) ||
  1860. ((Action & INFCACHE_EXC_NOMANU) && !(inf_entry.MatchFlags & CIEF_INF_MANUFACTURER)) ||
  1861. ((Action & INFCACHE_EXC_NOCLASS) && !(inf_entry.MatchFlags & CIEF_INF_CLASSINFO))) {
  1862. //
  1863. // exclude this INF
  1864. //
  1865. InfCacheSearchTableSetFlags(pInfCache,
  1866. FindFileData.cFileName,
  1867. 0,
  1868. CHE_FLAGS_PENDING);
  1869. WriteLogEntry(
  1870. LogContext,
  1871. DRIVER_LOG_VVERBOSE,
  1872. MSG_LOG_EXCLUDE_WIN4_INF,
  1873. NULL,
  1874. FindFileData.cFileName);
  1875. }
  1876. } else if (inf_entry.MatchList & CIEF_INF_OLDNT) {
  1877. if((Action & INFCACHE_EXC_OLDINFS) ||
  1878. ((Action & INFCACHE_EXC_NOCLASS) && !(inf_entry.MatchList & CIEF_INF_CLASSINFO))) {
  1879. //
  1880. // exclude this INF
  1881. //
  1882. InfCacheSearchTableSetFlags(pInfCache,
  1883. FindFileData.cFileName,
  1884. 0,
  1885. CHE_FLAGS_PENDING);
  1886. WriteLogEntry(
  1887. LogContext,
  1888. DRIVER_LOG_VVERBOSE,
  1889. MSG_LOG_EXCLUDE_OLDNT_INF,
  1890. NULL,
  1891. FindFileData.cFileName);
  1892. } else {
  1893. //
  1894. // allow old INF's to match with any HwId's
  1895. // by considering it already matched
  1896. //
  1897. InfCacheSearchTableSetFlags(pInfCache,
  1898. FindFileData.cFileName,
  1899. CHE_FLAGS_IDMATCH,
  1900. 0);
  1901. }
  1902. } else {
  1903. //
  1904. // always exclude non-inf's
  1905. //
  1906. InfCacheSearchTableSetFlags(pInfCache,
  1907. FindFileData.cFileName,
  1908. 0,
  1909. CHE_FLAGS_PENDING);
  1910. }
  1911. }
  1912. }
  1913. #else
  1914. bCallCallback = TRUE; // Win9x
  1915. #endif
  1916. if (!Callback) {
  1917. //
  1918. // we were only called to re-build the cache
  1919. //
  1920. bCallCallback = FALSE;
  1921. }
  1922. if (NewInf || bCallCallback) {
  1923. PTSTR InfFullPath = NULL;
  1924. DWORD InfFullPathSize = lstrlen(InfDir)+MAX_PATH+2;
  1925. //
  1926. // we need to open HINF in either case
  1927. //
  1928. InfFullPath = MyMalloc(InfFullPathSize*sizeof(TCHAR));
  1929. if(InfFullPath == NULL) {
  1930. //
  1931. // carry on with other files, even if out of memory
  1932. // not the best thing to do, but consistant with
  1933. // what we did before.
  1934. //
  1935. continue;
  1936. }
  1937. lstrcpy(InfFullPath,InfDir);
  1938. pSetupConcatenatePaths(InfFullPath,FindFileData.cFileName,InfFullPathSize,NULL);
  1939. if((Err=LoadInfFile(InfFullPath,
  1940. &FindFileData,
  1941. INF_STYLE_WIN4 | INF_STYLE_OLDNT, // we'll filter this ourselves
  1942. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | (TryPnf?LDINF_FLAG_ALWAYS_TRY_PNF:0),
  1943. NULL,
  1944. NULL,
  1945. NULL,
  1946. NULL,
  1947. LogContext,
  1948. &pInf,
  1949. &ErrorLineNumber,
  1950. &PnfWasUsed)) != NO_ERROR) {
  1951. pInf = NULL;
  1952. WriteLogEntry(
  1953. LogContext,
  1954. DRIVER_LOG_VVERBOSE,
  1955. MSG_LOG_COULD_NOT_LOAD_NEW_INF,
  1956. NULL,
  1957. InfFullPath);
  1958. }
  1959. #ifdef UNICODE
  1960. if(NewInf) {
  1961. //
  1962. // if opening the INF failed, we still want to record this fact
  1963. // in the cache so we don't try to re-open next time round
  1964. //
  1965. InfId = InfCacheAddInf(LogContext,pInfCache,&FindFileData,&inf_entry,pInf);
  1966. if(Callback) {
  1967. bCallCallback = TRUE;
  1968. }
  1969. }
  1970. #endif
  1971. if (pInf) {
  1972. if (bCallCallback && Callback) {
  1973. //
  1974. // we're processing the INF now
  1975. // clear pending flag (if we can) so we don't try and process INF a 2nd time
  1976. // the only time this can fail is if we haven't already added the INF
  1977. // so either way we wont callback twice
  1978. //
  1979. #ifdef UNICODE
  1980. if (pInfCache) {
  1981. //
  1982. // only set flags in the cache
  1983. // if we have a cache :-)
  1984. //
  1985. InfCacheSearchTableSetFlags(pInfCache,FindFileData.cFileName,0,CHE_FLAGS_PENDING);
  1986. }
  1987. #endif
  1988. if(!Callback(LogContext,InfFullPath,pInf,PnfWasUsed,Context)) {
  1989. Err = GetLastError();
  1990. MYASSERT(Err);
  1991. FreeInfFile(pInf);
  1992. MyFree(InfFullPath);
  1993. goto cleanup;
  1994. }
  1995. }
  1996. FreeInfFile(pInf);
  1997. }
  1998. MyFree(InfFullPath);
  1999. }
  2000. } while (FindNextFile(FindHandle,&FindFileData));
  2001. FindClose(FindHandle);
  2002. }
  2003. if (!pInfCache) {
  2004. //
  2005. // we have processed all files already
  2006. // skip cache search code, since we don't
  2007. // have a cache to search
  2008. //
  2009. Err = NO_ERROR;
  2010. goto cleanup;
  2011. }
  2012. #ifdef UNICODE
  2013. //
  2014. // at this point we can commit cache
  2015. //
  2016. WriteLogEntry(
  2017. LogContext,
  2018. DRIVER_LOG_TIME,
  2019. MSG_LOG_END_CACHE_1,
  2020. NULL);
  2021. if(pInfCache && !bNoWriteBack) {
  2022. InfCacheWriteCache(InfDir,pInfCache,LogContext);
  2023. }
  2024. if (!Callback) {
  2025. //
  2026. // optimization: no callback
  2027. // (we were only called, eg, to update cache)
  2028. // leave early
  2029. //
  2030. Err = NO_ERROR;
  2031. goto cleanup;
  2032. }
  2033. //
  2034. // Phase 2 - determine all other INF's to process via Cache
  2035. //
  2036. // will want INFs that exist, haven't yet been processed
  2037. // and haven't been excluded
  2038. //
  2039. ReqFlags = CHE_FLAGS_PENDING;
  2040. if (ClassIdList && ClassIdList[0]) {
  2041. PCTSTR ClassId;
  2042. //
  2043. // Primary list (typically Class GUID, Class Name and Legacy Class Name)
  2044. //
  2045. Err = NO_ERROR;
  2046. for(ClassId = ClassIdList;*ClassId;ClassId += lstrlen(ClassId)+1) {
  2047. Err = InfCacheMarkMatchInfs(pInfCache,ClassId,CHE_FLAGS_GUIDMATCH);
  2048. if (Err != NO_ERROR) {
  2049. break;
  2050. }
  2051. }
  2052. if (Err == NO_ERROR) {
  2053. //
  2054. // succeeded, restrict requirement
  2055. //
  2056. ReqFlags |= CHE_FLAGS_GUIDMATCH;
  2057. }
  2058. }
  2059. if (HwIdList && HwIdList[0]) {
  2060. PCTSTR HwId;
  2061. //
  2062. // Secondary list
  2063. // if a list of hardware Id's specified, we only want hits that include
  2064. // any of the hardware Id's
  2065. //
  2066. Err = NO_ERROR;
  2067. for(HwId = HwIdList;*HwId;HwId += lstrlen(HwId)+1) {
  2068. Err = InfCacheMarkMatchInfs(pInfCache,HwId,CHE_FLAGS_IDMATCH);
  2069. if(Err != NO_ERROR) {
  2070. break;
  2071. }
  2072. }
  2073. if (Err == NO_ERROR) {
  2074. //
  2075. // succeeded, restrict requirement
  2076. //
  2077. ReqFlags |= CHE_FLAGS_IDMATCH;
  2078. }
  2079. }
  2080. //
  2081. // Phase 3 - process all INF's that meet requirements
  2082. // do this by simply enumerating the search string table
  2083. //
  2084. enum_data.LogContext = LogContext;
  2085. enum_data.Callback = Callback;
  2086. enum_data.Context = Context;
  2087. enum_data.InfDir = InfDir;
  2088. enum_data.Requirement = ReqFlags;
  2089. enum_data.ExitStatus = NO_ERROR;
  2090. Err = NO_ERROR;
  2091. if(!pStringTableEnum(pInfCache->pSearchTable,
  2092. &hit_stats,
  2093. sizeof(hit_stats),
  2094. InfCacheSearchEnum,
  2095. (LPARAM)&enum_data)) {
  2096. //
  2097. // we'll only fail for error condition
  2098. //
  2099. Err = enum_data.ExitStatus;
  2100. }
  2101. WriteLogEntry(
  2102. LogContext,
  2103. DRIVER_LOG_TIME,
  2104. MSG_LOG_END_CACHE_2,
  2105. NULL);
  2106. #else
  2107. Err = NO_ERROR;
  2108. #endif
  2109. cleanup:
  2110. #ifdef UNICODE
  2111. if (pInfCache) {
  2112. InfCacheFreeCache(pInfCache);
  2113. }
  2114. #endif
  2115. if (InfPath) {
  2116. MyFree(InfPath);
  2117. }
  2118. if (LogContext && LocalLogContext) {
  2119. DeleteLogContext(LocalLogContext);
  2120. }
  2121. return Err;
  2122. }
  2123. DWORD InfCacheSearchPath(
  2124. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  2125. IN DWORD Action,
  2126. IN PCTSTR InfDirPath, OPTIONAL
  2127. IN InfCacheCallback Callback, OPTIONAL
  2128. IN PVOID Context, OPTIONAL
  2129. IN PCTSTR ClassIdList, OPTIONAL
  2130. IN PCTSTR HwIdList OPTIONAL
  2131. )
  2132. /*++
  2133. Routine Description:
  2134. Iterates InfDirPath calling InfCacheSearchDirectory for each entry
  2135. Arguments:
  2136. LogContext - for logging
  2137. InfDir - single directory to search - if not specified, uses driver path
  2138. Callback - function to call on a likely match
  2139. Context - parameter to pass to function
  2140. ClassIdList (optional) - multi-sz list of class id's (typically guid, name and legacy name)
  2141. HwIdList (optional)- multi-sz list of hardware id's
  2142. Return Value:
  2143. status, typically NO_ERROR
  2144. --*/
  2145. {
  2146. PSETUP_LOG_CONTEXT LocalLogContext = NULL;
  2147. DWORD Err = NO_ERROR;
  2148. PCTSTR InfDir;
  2149. if (!InfDirPath) {
  2150. InfDirPath = InfSearchPaths;
  2151. }
  2152. if(!LogContext) {
  2153. if(CreateLogContext(NULL,TRUE,&LocalLogContext)==NO_ERROR) {
  2154. LogContext = LocalLogContext;
  2155. } else {
  2156. return ERROR_NOT_ENOUGH_MEMORY;
  2157. }
  2158. }
  2159. for (InfDir = InfDirPath; *InfDir; InfDir+=lstrlen(InfDir)+1) {
  2160. Err = InfCacheSearchDirectory(LogContext,Action,InfDir,Callback,Context,ClassIdList,HwIdList);
  2161. if(Err != NO_ERROR) {
  2162. break;
  2163. }
  2164. }
  2165. if (LogContext && LocalLogContext) {
  2166. DeleteLogContext(LocalLogContext);
  2167. }
  2168. return Err;
  2169. }
  2170. #ifdef UNICODE
  2171. BOOL WINAPI pSetupInfCacheBuild(
  2172. IN DWORD Action
  2173. )
  2174. /*++
  2175. Routine Description:
  2176. Privately exported, called from (eg) syssetup to reset cache(s)
  2177. Arguments:
  2178. Action - one of:
  2179. INFCACHEBUILD_UPDATE
  2180. INFCACHEBUILD_REBUILD
  2181. Return Value:
  2182. TRUE if success, FALSE on Error (GetLastError indicates error)
  2183. --*/
  2184. {
  2185. DWORD RealAction;
  2186. DWORD Err;
  2187. switch(Action) {
  2188. case INFCACHEBUILD_UPDATE:
  2189. RealAction = INFCACHE_DEFAULT;
  2190. break;
  2191. case INFCACHEBUILD_REBUILD:
  2192. RealAction = INFCACHE_REBUILD;
  2193. break;
  2194. default:
  2195. SetLastError(ERROR_INVALID_PARAMETER);
  2196. return FALSE;
  2197. }
  2198. RealAction |= INFCACHE_FORCE_CACHE|INFCACHE_FORCE_PNF;
  2199. try {
  2200. Err = InfCacheSearchPath(NULL,
  2201. RealAction,
  2202. NULL,
  2203. NULL,
  2204. NULL,
  2205. NULL,
  2206. NULL
  2207. );
  2208. } except(EXCEPTION_EXECUTE_HANDLER) {
  2209. Err = ERROR_INVALID_DATA;
  2210. }
  2211. SetLastError(Err);
  2212. return Err==NO_ERROR;
  2213. }
  2214. #endif