Leaked source code of windows server 2003
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.

2731 lines
81 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 (if NULL, delete)
  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. MYASSERT(FindFileData);
  1003. MYASSERT(inf_entry);
  1004. //
  1005. // determine if the cache entry of pInfCache is considered valid
  1006. //
  1007. i = pStringTableLookUpString(pInfCache->pInfTable,
  1008. FindFileData->cFileName,
  1009. &StringLength,
  1010. NULL, // hash value
  1011. NULL, // find context
  1012. STRTAB_CASE_INSENSITIVE,
  1013. inf_entry,
  1014. sizeof(CACHEINFENTRY));
  1015. if(i>=0 && inf_entry->MatchList != CIE_INF_INVALID) {
  1016. //
  1017. // cache hit (and matchlist is valid)
  1018. //
  1019. if(CompareFileTime(&inf_entry->FileTime,&FindFileData->ftLastWriteTime)==0) {
  1020. //
  1021. // valid cache hit
  1022. //
  1023. return i;
  1024. }
  1025. //
  1026. // cache out of date miss
  1027. // although we'll rebuild it later, let's use this opportunity to delete the entry
  1028. //
  1029. InfCacheRemoveInf(pInfCache,i,inf_entry);
  1030. }
  1031. //
  1032. // we're here because we have a miss, however fill in a new (empty) inf_entry
  1033. // MatchList set to CIE_INF_INVALID to indicate list is invalid and inf must be searched
  1034. //
  1035. inf_entry->FileTime = FindFileData->ftLastWriteTime;
  1036. inf_entry->MatchList = CIE_INF_INVALID;
  1037. inf_entry->MatchFlags = CIEF_INF_NOTINF;
  1038. return -1;
  1039. }
  1040. #endif
  1041. #ifdef UNICODE
  1042. ULONG InfCacheAddListTail(
  1043. IN OUT PINFCACHE pInfCache,
  1044. IN OUT PULONG head,
  1045. IN OUT PULONG tail,
  1046. IN LONG value
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. Adds value to tail of a list where *tail is an entry in the list
  1051. Arguments:
  1052. pInfCache - cache to modify
  1053. head - head of list
  1054. tail - DataList entry
  1055. value - data to add
  1056. Return Value:
  1057. new entry position, 0 on error (GetLastError() returns error)
  1058. --*/
  1059. {
  1060. ULONG next;
  1061. ULONG first;
  1062. MYASSERT(pInfCache);
  1063. MYASSERT(head == NULL || head != tail);
  1064. if (tail) {
  1065. first = *tail;
  1066. } else if (head) {
  1067. first = *head;
  1068. } else {
  1069. MYASSERT(head || tail);
  1070. }
  1071. if (!first) {
  1072. next = InfCacheAllocListEntry(pInfCache,value);
  1073. if (!next) {
  1074. return 0;
  1075. }
  1076. if (head) {
  1077. *head = next;
  1078. }
  1079. } else {
  1080. //
  1081. // move head to last item in list
  1082. //
  1083. while(pInfCache->pListTable[first].Next) {
  1084. first = pInfCache->pListTable[first].Next;
  1085. }
  1086. next = InfCacheAllocListEntry(pInfCache,value);
  1087. if(!next) {
  1088. return 0;
  1089. }
  1090. pInfCache->pListTable[first].Next = next;
  1091. }
  1092. if(tail) {
  1093. *tail = next;
  1094. }
  1095. return next;
  1096. }
  1097. #endif
  1098. #ifdef UNICODE
  1099. LONG InfCacheAddMatchItem(
  1100. IN OUT PINFCACHE pInfCache,
  1101. IN LPCTSTR key,
  1102. IN LONG InfEntry
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. Given an INF StringID (InfEntry) and match key,
  1107. obtain (and return) Match StringID
  1108. while also adding InfEntry to head of Match's INF list
  1109. (if not already at head)
  1110. Order is not particularly important, however adding to head is
  1111. quicker to do, and easier to reduce number of times we add inf
  1112. if match id is referenced multiple times
  1113. Arguments:
  1114. pInfCache - cache to modify
  1115. key - match string (buffer must be writable)
  1116. InfEntry - StringID
  1117. Return Value:
  1118. new entry in match table, -1 on error (GetLastError() returns error)
  1119. --*/
  1120. {
  1121. LONG MatchIndex;
  1122. CACHEMATCHENTRY matchentry;
  1123. DWORD StringLength;
  1124. MYASSERT(pInfCache);
  1125. MYASSERT(key);
  1126. MYASSERT(InfEntry>=0);
  1127. //
  1128. // if cache is invalid, we'll skip this as optimization
  1129. //
  1130. if(pInfCache->bNoWriteBack) {
  1131. SetLastError(ERROR_INVALID_DATA);
  1132. return -1;
  1133. }
  1134. MatchIndex = pStringTableLookUpString(pInfCache->pMatchTable,
  1135. (LPTSTR)key, // will not be modified
  1136. &StringLength,
  1137. NULL, // hash value
  1138. NULL, // find context
  1139. STRTAB_CASE_INSENSITIVE,
  1140. &matchentry,
  1141. sizeof(matchentry));
  1142. if(MatchIndex < 0) {
  1143. //
  1144. // entirely new entry
  1145. //
  1146. matchentry.InfList = InfCacheAllocListEntry(pInfCache,InfEntry);
  1147. if(matchentry.InfList == 0) {
  1148. return -1;
  1149. }
  1150. MatchIndex = pStringTableAddString(pInfCache->pMatchTable,
  1151. (LPTSTR)key, // will not be modified
  1152. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1153. &matchentry,
  1154. sizeof(matchentry));
  1155. if(MatchIndex<0) {
  1156. pInfCache->bNoWriteBack = TRUE;
  1157. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1158. return -1;
  1159. }
  1160. } else {
  1161. MYASSERT(matchentry.InfList<pInfCache->pHeader->ListDataCount);
  1162. //
  1163. // if we came across this same match earlier for this inf,
  1164. // the inf should still be at head of list
  1165. // the world doesn't come to an end though if we end up adding
  1166. // the inf twice - we check for this when deleting the inf
  1167. //
  1168. if (pInfCache->pListTable[matchentry.InfList].Value != InfEntry) {
  1169. ULONG newentry = InfCacheAllocListEntry(pInfCache,InfEntry);
  1170. if(newentry == 0) {
  1171. return -1;
  1172. }
  1173. pInfCache->pListTable[newentry].Next = matchentry.InfList;
  1174. matchentry.InfList = newentry;
  1175. if(!pStringTableSetExtraData(pInfCache->pMatchTable,MatchIndex,&matchentry,sizeof(matchentry))) {
  1176. MYASSERT(FALSE); // should not fail
  1177. }
  1178. }
  1179. }
  1180. return MatchIndex;
  1181. }
  1182. #endif
  1183. #ifdef UNICODE
  1184. LONG InfCacheAddInf(
  1185. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1186. IN OUT PINFCACHE pInfCache,
  1187. IN LPWIN32_FIND_DATA FindFileData,
  1188. OUT PCACHEINFENTRY inf_entry,
  1189. IN PLOADED_INF pInf
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. Called to add a newly discovered INF to the cache
  1194. If hINF is "bad", then we'll mark the INF as an exclusion
  1195. so we don't waste time with it in future
  1196. If we return with an error, caller knows that the INF
  1197. must be searched if it can be searched
  1198. Arguments:
  1199. LogContext - logging context for errors
  1200. pInfCache - cache to modify
  1201. FindFileData - contains name of INF and date-stamp
  1202. inf_entry - returns list of match ID's associated with INF
  1203. pINF - opened INF to add information about. NOTE: Either this INF must
  1204. be locked by the caller, or the INF cannot be accessed by any other
  1205. thread. THIS ROUTINE DOES NOT DO LOCKING ON THE INF.
  1206. Return Value:
  1207. InfEntry - -1 if error (GetLastError returns status)
  1208. --*/
  1209. {
  1210. //
  1211. // FindFileData contains name & date-stamp of INF
  1212. // we need to process all search information out of the INF
  1213. //
  1214. LONG nInfIndex = -1;
  1215. LONG nMatchId = -1;
  1216. ULONG last_list_entry = 0;
  1217. ULONG head_list_entry = 0;
  1218. DWORD Err = NO_ERROR;
  1219. PCTSTR MatchString;
  1220. GUID guid;
  1221. PINF_SECTION MfgListSection;
  1222. PINF_LINE MfgListLine;
  1223. UINT MfgListLineIndex;
  1224. PTSTR CurMfgSecName;
  1225. TCHAR CurMfgSecWithExt[MAX_SECT_NAME_LEN];
  1226. MYASSERT(pInfCache);
  1227. MYASSERT(FindFileData);
  1228. MYASSERT(inf_entry);
  1229. if (pInfCache->bNoWriteBack) {
  1230. //
  1231. // cache is already bad, so don't waste time updating it
  1232. // note though that the INF should be searched
  1233. //
  1234. return ERROR_INVALID_DATA;
  1235. }
  1236. if(pInfCache->bReadOnly) {
  1237. Err = InfCacheMakeWritable(pInfCache);
  1238. if(Err != NO_ERROR) {
  1239. pInfCache->bNoWriteBack = TRUE; // cache now invalid
  1240. return Err;
  1241. }
  1242. pInfCache->bDirty = TRUE;
  1243. }
  1244. //
  1245. // this stuff should be set up earlier
  1246. //
  1247. MYASSERT(inf_entry->MatchList == CIE_INF_INVALID);
  1248. MYASSERT(inf_entry->MatchFlags == CIEF_INF_NOTINF);
  1249. MYASSERT(inf_entry->FileTime.dwHighDateTime = FindFileData->ftLastWriteTime.dwHighDateTime);
  1250. MYASSERT(inf_entry->FileTime.dwLowDateTime = FindFileData->ftLastWriteTime.dwLowDateTime);
  1251. MYASSERT(!pInfCache->bReadOnly);
  1252. //
  1253. // we need the InfIndex before we start (also mark this as file physically exist)
  1254. //
  1255. inf_entry->MatchList = 0;
  1256. nInfIndex = pStringTableAddString(pInfCache->pInfTable,
  1257. FindFileData->cFileName,
  1258. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1259. inf_entry,
  1260. sizeof(CACHEINFENTRY));
  1261. if (nInfIndex<0) {
  1262. //
  1263. // ack, out of memory
  1264. //
  1265. Err = ERROR_NOT_ENOUGH_MEMORY;
  1266. goto cleanup;
  1267. }
  1268. if(pInf) {
  1269. if(pInf->Style == INF_STYLE_WIN4) {
  1270. inf_entry->MatchFlags |= CIEF_INF_WIN4;
  1271. if(pInf->InfSourceMediaType == SPOST_URL) {
  1272. inf_entry->MatchFlags |= CIEF_INF_URL;
  1273. }
  1274. //
  1275. // for a Win4 style INF, we're going to add Class GUID & Class Name to the
  1276. // pool of ID's we can match on
  1277. // note that if one or the other is missing, we don't lookup here as registry
  1278. // information could change
  1279. // we do the cross-lookups at the time of the INF search
  1280. //
  1281. if((MatchString = pSetupGetVersionDatum(&pInf->VersionBlock, pszClassGuid))!=NULL) {
  1282. //
  1283. // we found a class GUID
  1284. //
  1285. inf_entry->MatchFlags |= CIEF_INF_CLASSGUID;
  1286. nMatchId = InfCacheAddMatchItem(pInfCache,MatchString,nInfIndex);
  1287. if (nMatchId<0) {
  1288. Err = GetLastError();
  1289. goto cleanup;
  1290. }
  1291. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1292. Err = GetLastError();
  1293. goto cleanup;
  1294. }
  1295. //
  1296. // check out a special case {0}
  1297. //
  1298. if(pSetupGuidFromString(MatchString, &guid) == NO_ERROR && pSetupIsGuidNull(&guid)) {
  1299. inf_entry->MatchFlags |= CIEF_INF_NULLGUID;
  1300. }
  1301. }
  1302. if((MatchString = pSetupGetVersionDatum(&pInf->VersionBlock, pszClass))!=NULL) {
  1303. //
  1304. // we found a class name
  1305. //
  1306. inf_entry->MatchFlags |= CIEF_INF_CLASSNAME;
  1307. nMatchId = InfCacheAddMatchItem(pInfCache,MatchString,nInfIndex);
  1308. if (nMatchId<0) {
  1309. Err = GetLastError();
  1310. goto cleanup;
  1311. }
  1312. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1313. Err = GetLastError();
  1314. goto cleanup;
  1315. }
  1316. }
  1317. //
  1318. // enumerate all manufacturers
  1319. //
  1320. if((MfgListSection = InfLocateSection(pInf, pszManufacturer, NULL)) &&
  1321. MfgListSection->LineCount) {
  1322. //
  1323. // We have a [Manufacturer] section and there is at least one
  1324. // line within it.
  1325. //
  1326. inf_entry->MatchFlags |= CIEF_INF_MANUFACTURER;
  1327. for(MfgListLineIndex = 0;
  1328. InfLocateLine(pInf, MfgListSection, NULL, &MfgListLineIndex, &MfgListLine);
  1329. MfgListLineIndex++) {
  1330. //
  1331. // Make sure the current line is one of these valid forms:
  1332. //
  1333. // MfgDisplayNameAndModelsSection
  1334. // MfgDisplayName = MfgModelsSection [,TargetDecoration...]
  1335. //
  1336. if(!ISSEARCHABLE(MfgListLine)) {
  1337. //
  1338. // We have a line with multiple fields but no key--skip
  1339. // it.
  1340. //
  1341. continue;
  1342. }
  1343. if(CurMfgSecName = InfGetField(pInf, MfgListLine, 1, NULL)) {
  1344. INFCONTEXT device;
  1345. //
  1346. // Check to see if there is an applicable
  1347. // TargetDecoration entry for this manufacturer's
  1348. // models section (if so, the models section name will
  1349. // be appended with that decoration).
  1350. //
  1351. if(GetDecoratedModelsSection(LogContext,
  1352. pInf,
  1353. MfgListLine,
  1354. NULL,
  1355. CurMfgSecWithExt)) {
  1356. //
  1357. // From here on, use the decorated models section...
  1358. //
  1359. CurMfgSecName = CurMfgSecWithExt;
  1360. }
  1361. if(SetupFindFirstLine(pInf, CurMfgSecName, NULL, &device)) {
  1362. do {
  1363. TCHAR devname[LINE_LEN];
  1364. DWORD devindex;
  1365. DWORD fields = SetupGetFieldCount(&device);
  1366. //
  1367. // for a device line, field 1 = section, field 2+ = match keys
  1368. //
  1369. for(devindex=2;devindex<=fields;devindex++) {
  1370. if(SetupGetStringField(&device,devindex,devname,LINE_LEN,NULL)) {
  1371. //
  1372. // finally, a hit key to add
  1373. //
  1374. nMatchId = InfCacheAddMatchItem(pInfCache,devname,nInfIndex);
  1375. if(nMatchId<0) {
  1376. Err = GetLastError();
  1377. goto cleanup;
  1378. }
  1379. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1380. Err = GetLastError();
  1381. goto cleanup;
  1382. }
  1383. }
  1384. }
  1385. } while(SetupFindNextLine(&device,&device));
  1386. }
  1387. }
  1388. }
  1389. }
  1390. } else if (pInf->Style == INF_STYLE_OLDNT) {
  1391. //
  1392. // for an OLDNT style INF, we'll add Legacy class name to the pool of ID's
  1393. // we can match on
  1394. //
  1395. inf_entry->MatchFlags |= CIEF_INF_OLDNT;
  1396. if((MatchString = pSetupGetVersionDatum(&pInf->VersionBlock, pszClass))!=NULL) {
  1397. //
  1398. // we found a (legacy) class name
  1399. //
  1400. inf_entry->MatchFlags |= CIEF_INF_CLASSNAME;
  1401. nMatchId = InfCacheAddMatchItem(pInfCache,MatchString,nInfIndex);
  1402. if (nMatchId<0) {
  1403. Err = GetLastError();
  1404. goto cleanup;
  1405. }
  1406. if (!InfCacheAddListTail(pInfCache,&head_list_entry,&last_list_entry,nMatchId)) {
  1407. Err = GetLastError();
  1408. goto cleanup;
  1409. }
  1410. }
  1411. } else {
  1412. MYASSERT(FALSE);
  1413. }
  1414. }
  1415. //
  1416. // now re-write the inf data with new flags & match patterns
  1417. //
  1418. inf_entry->MatchList = head_list_entry;
  1419. if(!pStringTableSetExtraData(pInfCache->pInfTable,nInfIndex,inf_entry,sizeof(CACHEINFENTRY))) {
  1420. MYASSERT(FALSE); // should not fail
  1421. }
  1422. return nInfIndex;
  1423. cleanup:
  1424. pInfCache->bNoWriteBack = TRUE;
  1425. MYASSERT(Err);
  1426. SetLastError(Err);
  1427. return -1;
  1428. }
  1429. #endif
  1430. #ifdef UNICODE
  1431. LONG InfCacheSearchTableLookup(
  1432. IN OUT PINFCACHE pInfCache,
  1433. IN PCTSTR filename,
  1434. IN OUT PCACHEHITENTRY hitstats)
  1435. /*++
  1436. Routine Description:
  1437. Looks up filename in the search table, returning search information
  1438. if filename was not already in search table, it's added
  1439. Arguments:
  1440. pInfCache - cache to modify
  1441. filename - file to obtain hit-entry information for
  1442. hitstats - information obtained (such as if this files been processed etc)
  1443. Return Value:
  1444. index in search table (-1 if error)
  1445. --*/
  1446. {
  1447. LONG nHitIndex;
  1448. DWORD StringLength;
  1449. MYASSERT(pInfCache);
  1450. MYASSERT(filename);
  1451. MYASSERT(hitstats);
  1452. nHitIndex = pStringTableLookUpString(pInfCache->pSearchTable,
  1453. (PTSTR)filename, // filename wont be changed
  1454. &StringLength,
  1455. NULL, // hash value
  1456. NULL, // find context
  1457. STRTAB_CASE_INSENSITIVE,
  1458. hitstats,
  1459. sizeof(CACHEHITENTRY));
  1460. if(nHitIndex < 0) {
  1461. //
  1462. // entirely new entry (hitstats expected to have a value)
  1463. //
  1464. nHitIndex = pStringTableAddString(pInfCache->pSearchTable,
  1465. (PTSTR)filename, // filename wont be changed
  1466. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1467. hitstats,
  1468. sizeof(CACHEHITENTRY));
  1469. if (nHitIndex<0) {
  1470. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1471. return -1;
  1472. }
  1473. }
  1474. return nHitIndex;
  1475. }
  1476. #endif
  1477. #ifdef UNICODE
  1478. ULONG InfCacheSearchTableSetFlags(
  1479. IN OUT PINFCACHE pInfCache,
  1480. IN PCTSTR filename,
  1481. IN ULONG setflags,
  1482. IN ULONG clrflags
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. Modifies flags associated with a filename
  1487. Arguments:
  1488. pInfCache - cache to modify
  1489. filename - file to obtain hit-entry information for
  1490. setflags - flags to set
  1491. clrflags - flags to clear
  1492. Return Value:
  1493. combined flags, or (ULONG)(-1) on error.
  1494. --*/
  1495. {
  1496. CACHEHITENTRY searchentry;
  1497. LONG nHitIndex;
  1498. ULONG flags;
  1499. MYASSERT(pInfCache);
  1500. MYASSERT(filename);
  1501. searchentry.Flags = setflags; // prime in case of new entry
  1502. nHitIndex = InfCacheSearchTableLookup(pInfCache,filename,&searchentry);
  1503. if(nHitIndex<0) {
  1504. return (ULONG)(-1);
  1505. }
  1506. flags = (searchentry.Flags&~clrflags) | setflags;
  1507. if (flags != searchentry.Flags) {
  1508. searchentry.Flags = flags;
  1509. if(!pStringTableSetExtraData(pInfCache->pSearchTable,nHitIndex,&searchentry,sizeof(searchentry))) {
  1510. MYASSERT(FALSE); // should not fail
  1511. }
  1512. }
  1513. return searchentry.Flags;
  1514. }
  1515. #endif
  1516. #ifdef UNICODE
  1517. DWORD InfCacheMarkMatchInfs(
  1518. IN OUT PINFCACHE pInfCache,
  1519. IN PCTSTR MatchString,
  1520. IN ULONG MatchFlag
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. Called to iterate through the INF's associated with MatchString
  1525. and flag them using MatchFlag
  1526. Arguments:
  1527. pInfCache - cache to check (may modify search data)
  1528. MatchString - match string to include
  1529. MatchFlag - flag to set in all INF's associated with match string
  1530. Return Value:
  1531. status - typically NO_ERROR
  1532. --*/
  1533. {
  1534. LONG MatchIndex;
  1535. DWORD StringLength;
  1536. CACHEMATCHENTRY matchentry;
  1537. ULONG entry;
  1538. PTSTR InfName;
  1539. ULONG SearchFlags;
  1540. MYASSERT(pInfCache);
  1541. MYASSERT(MatchString);
  1542. MYASSERT(MatchFlag);
  1543. //
  1544. // find list of Inf's associated with match string
  1545. //
  1546. MatchIndex = pStringTableLookUpString(pInfCache->pMatchTable,
  1547. (PTSTR)MatchString, // it will not be modified
  1548. &StringLength,
  1549. NULL, // hash value
  1550. NULL, // find context
  1551. STRTAB_CASE_INSENSITIVE,
  1552. &matchentry,
  1553. sizeof(matchentry));
  1554. if(MatchIndex < 0) {
  1555. //
  1556. // no match
  1557. //
  1558. return NO_ERROR;
  1559. }
  1560. for(entry = matchentry.InfList ; entry > 0 && entry < pInfCache->pHeader->ListDataCount ; entry = pInfCache->pListTable[entry].Next) {
  1561. LONG InfEntry = pInfCache->pListTable[entry].Value;
  1562. //
  1563. // obtain name of Inf
  1564. //
  1565. InfName = pStringTableStringFromId(pInfCache->pInfTable,InfEntry);
  1566. SearchFlags = InfCacheSearchTableSetFlags(pInfCache,InfName,MatchFlag,0);
  1567. if(SearchFlags == (ULONG)(-1)) {
  1568. //
  1569. // failed - huh?
  1570. // abort into fail-safe pass
  1571. //
  1572. MYASSERT(SearchFlags != (ULONG)(-1));
  1573. return GetLastError();
  1574. }
  1575. }
  1576. return NO_ERROR;
  1577. }
  1578. #endif
  1579. #ifdef UNICODE
  1580. BOOL
  1581. InfCacheSearchEnum(
  1582. IN PVOID StringTable,
  1583. IN LONG StringId,
  1584. IN PCTSTR String,
  1585. IN PVOID ExtraData,
  1586. IN UINT ExtraDataSize,
  1587. IN LPARAM lParam
  1588. )
  1589. /*++
  1590. Routine Description:
  1591. Callback for Phase-3 of InfCacheSearchDirectory
  1592. Arguments:
  1593. StringTable - unused
  1594. StringId - unused
  1595. String - used to form INF name
  1596. ExtraData - points to flags
  1597. ExtraDataSize - unused
  1598. lParam - points to InfCacheEnumData
  1599. Return Value:
  1600. always TRUE unless out of memory condition
  1601. --*/
  1602. {
  1603. PINFCACHE_ENUMDATA enum_data = (PINFCACHE_ENUMDATA)lParam;
  1604. CACHEHITENTRY *hit_stats = (CACHEHITENTRY *)ExtraData;
  1605. PTSTR InfFullPath = NULL;
  1606. DWORD InfFullPathSize;
  1607. BOOL b;
  1608. WIN32_FIND_DATA FindData;
  1609. PLOADED_INF pInf = NULL;
  1610. UINT ErrorLineNumber;
  1611. BOOL PnfWasUsed;
  1612. BOOL cont = TRUE;
  1613. MYASSERT(ExtraDataSize == sizeof(CACHEHITENTRY));
  1614. MYASSERT(String);
  1615. MYASSERT(enum_data);
  1616. MYASSERT(hit_stats);
  1617. MYASSERT(enum_data->Requirement);
  1618. MYASSERT(enum_data->Callback);
  1619. //
  1620. // see if this is an INF of interest
  1621. //
  1622. if((hit_stats->Flags & enum_data->Requirement) == enum_data->Requirement) {
  1623. //
  1624. // this is a HIT
  1625. // we need to open HINF
  1626. //
  1627. InfFullPathSize = lstrlen(enum_data->InfDir)+MAX_PATH+2;
  1628. InfFullPath = MyMalloc(InfFullPathSize*sizeof(TCHAR));
  1629. if (!InfFullPath) {
  1630. return TRUE; // out of memory (does not abort search)
  1631. }
  1632. lstrcpy(InfFullPath,enum_data->InfDir);
  1633. pSetupConcatenatePaths(InfFullPath,String,InfFullPathSize,NULL);
  1634. if(b = FileExists(InfFullPath, &FindData)) {
  1635. if(LoadInfFile(InfFullPath,
  1636. &FindData,
  1637. INF_STYLE_WIN4 | INF_STYLE_OLDNT, // we've filtered this ourselves
  1638. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | LDINF_FLAG_ALWAYS_TRY_PNF,
  1639. NULL,
  1640. NULL,
  1641. NULL,
  1642. NULL,
  1643. enum_data->LogContext,
  1644. &pInf,
  1645. &ErrorLineNumber,
  1646. &PnfWasUsed) != NO_ERROR) {
  1647. pInf = NULL;
  1648. WriteLogEntry(
  1649. enum_data->LogContext,
  1650. DRIVER_LOG_VVERBOSE,
  1651. MSG_LOG_COULD_NOT_LOAD_HIT_INF,
  1652. NULL,
  1653. InfFullPath);
  1654. }
  1655. } else {
  1656. pInf = NULL;
  1657. }
  1658. if (pInf) {
  1659. cont = enum_data->Callback(enum_data->LogContext,InfFullPath,pInf,PnfWasUsed,enum_data->Context);
  1660. if(!cont) {
  1661. enum_data->ExitStatus = GetLastError();
  1662. MYASSERT(enum_data->ExitStatus);
  1663. }
  1664. FreeInfFile(pInf);
  1665. }
  1666. }
  1667. if (InfFullPath) {
  1668. MyFree(InfFullPath);
  1669. }
  1670. return cont;
  1671. }
  1672. #endif
  1673. DWORD InfCacheSearchDirectory(
  1674. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  1675. IN DWORD Action,
  1676. IN PCTSTR InfDir,
  1677. IN InfCacheCallback Callback, OPTIONAL
  1678. IN PVOID Context, OPTIONAL
  1679. IN PCTSTR ClassIdList, OPTIONAL
  1680. IN PCTSTR HwIdList OPTIONAL
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. Main workhorse of the InfCache
  1685. Search a single specified directory
  1686. calling Callback(hInf,Context) for each inf that has a likelyhood of matching
  1687. note that Action flags, ClassId and HwIdList are hints, and Callback may get
  1688. called for any/all INF's Callback must re-check for all search criteria.
  1689. Searching is done in 3 phases
  1690. Phase 1: Parse all INF's in directory. If an INF is not in cache, *almost always* call
  1691. callback. If special inclusions (OLD INF's INF's with no Class GUID's) specified, then
  1692. INF's that match the special criteria are processed here (since they can't be processed
  1693. in Phase 2). All INF's that exist, haven't been processed and haven't been excluded get
  1694. marked with CHE_FLAGS_PENDING ready for phase-2
  1695. Phase 2: Process ClassId and HwIdList matching, setting CHE_FLAGS_GUIDMATCH and
  1696. CHE_FLAGS_IDMATCH apropriately in matching INF's and search criteria flags. Search
  1697. criteria will either be:
  1698. CHE_FLAGS_PENDING - callback on all Win4 style INF's
  1699. CHE_FLAGS_PENDING | CHE_FLAGS_GUIDMATCH - callback on all Win4 INF's that have matching class
  1700. CHE_FLAGS_PENDING | CHE_FLAGS_IDMATCH - wildcard class, matching hardware ID's
  1701. CHE_FLAGS_PENDING | CHE_FLAGS_GUIDMATCH | CHE_FLAGS_IDMATCH - most specific match
  1702. Phase 3: enumerate through all INF's that we've marked with exact same flags as
  1703. search criteria, and call callback on those INF's
  1704. Using this search method, Win4 INF's that are in the cache are always processed last.
  1705. Arguments:
  1706. LogContext - for logging
  1707. InfDir - single directory to search
  1708. Callback - function to call on a likely match
  1709. Context - parameter to pass to function
  1710. ClassIdList (optional) - multi-sz list of class id's (typically guid, name and legacy name)
  1711. HwIdList (optional)- multi-sz list of hardware id's
  1712. Return Value:
  1713. status, typically NO_ERROR
  1714. --*/
  1715. {
  1716. PINFCACHE pInfCache = NULL;
  1717. PTSTR InfPath = NULL;
  1718. UINT PathSize;
  1719. DWORD Err = NO_ERROR;
  1720. WIN32_FIND_DATA FindFileData;
  1721. HANDLE FindHandle = INVALID_HANDLE_VALUE;
  1722. BOOL bNoWriteBack = FALSE;
  1723. LONG InfId;
  1724. LONG SearchId;
  1725. ULONG SearchFlags;
  1726. CACHEINFENTRY inf_entry;
  1727. CACHEHITENTRY hit_stats;
  1728. ULONG ReqFlags;
  1729. INFCACHE_ENUMDATA enum_data;
  1730. PSETUP_LOG_CONTEXT LocalLogContext = NULL;
  1731. BOOL TryPnf = FALSE;
  1732. BOOL TryCache = FALSE;
  1733. FILETIME FileTimeNow;
  1734. FILETIME FileTimeBefore;
  1735. FILETIME FileTimeAfter;
  1736. MYASSERT(InfDir);
  1737. //
  1738. // obtain cache for directory of interest
  1739. // we should be able to handle a NULL return
  1740. // note that caller can either treat these two bits
  1741. // as an operation (0-3) or as bitmaps
  1742. // the result would be the same
  1743. //
  1744. if(!LogContext) {
  1745. if(CreateLogContext(NULL,TRUE,&LocalLogContext)==NO_ERROR) {
  1746. LogContext = LocalLogContext;
  1747. } else {
  1748. LocalLogContext = NULL;
  1749. Err = ERROR_NOT_ENOUGH_MEMORY;
  1750. goto cleanup;
  1751. }
  1752. }
  1753. WriteLogEntry(
  1754. LogContext,
  1755. DRIVER_LOG_VVERBOSE,
  1756. MSG_LOG_ENUMERATING_FILES,
  1757. NULL,
  1758. InfDir);
  1759. PathSize = lstrlen(InfDir)+10;
  1760. InfPath = MyMalloc(PathSize*sizeof(TCHAR));
  1761. if(!InfPath) {
  1762. Err = ERROR_NOT_ENOUGH_MEMORY;
  1763. goto cleanup;
  1764. }
  1765. lstrcpy(InfPath,InfDir);
  1766. pSetupConcatenatePaths(InfPath,INFCACHE_INF_WILDCARD,PathSize,NULL);
  1767. #ifdef UNICODE
  1768. if (pSetupInfIsFromOemLocation(InfPath,FALSE)) {
  1769. if (Action & INFCACHE_FORCE_CACHE) {
  1770. TryCache = TRUE;
  1771. }
  1772. if (Action & INFCACHE_FORCE_PNF) {
  1773. TryPnf = TRUE;
  1774. }
  1775. } else {
  1776. TryPnf = TRUE;
  1777. //
  1778. // Try using INF cache unless we're doing an INFCACHE_ENUMALL
  1779. //
  1780. if((Action & INFCACHE_ACTIONBITS) != INFCACHE_ENUMALL) {
  1781. TryCache = TRUE;
  1782. }
  1783. }
  1784. if (!TryCache) {
  1785. //
  1786. // directory is not in our default search path
  1787. // treat as INFCACHE_ENUMALL
  1788. //
  1789. pInfCache = NULL;
  1790. } else {
  1791. switch(Action & INFCACHE_ACTIONBITS) {
  1792. case INFCACHE_NOWRITE:
  1793. pInfCache = InfCacheLoadCache(InfDir,LogContext);
  1794. bNoWriteBack = TRUE;
  1795. break;
  1796. case INFCACHE_DEFAULT:
  1797. pInfCache = InfCacheLoadCache(InfDir,LogContext);
  1798. break;
  1799. case INFCACHE_REBUILD:
  1800. pInfCache = InfCacheCreateNewCache(LogContext);
  1801. break;
  1802. case INFCACHE_ENUMALL:
  1803. pInfCache = NULL;
  1804. break;
  1805. default:
  1806. MYASSERT(FALSE);
  1807. }
  1808. }
  1809. #else
  1810. pInfCache = NULL;
  1811. #endif
  1812. //
  1813. // if an INF is changed, we will withhold writing back within 5 seconds
  1814. // this ensures that a file stamped by InfCacheAwareCopyFile can get
  1815. // modified again within the 2 second or so window where it may get
  1816. // the same timestamp, but without us "freezing" any changes
  1817. //
  1818. GetSystemTimeAsFileTime(&FileTimeNow);
  1819. AddFileTimeSeconds(&FileTimeNow,&FileTimeBefore,-5);
  1820. AddFileTimeSeconds(&FileTimeNow,&FileTimeAfter,5);
  1821. //
  1822. // first phase - enumerate the INF directory
  1823. //
  1824. FindHandle = FindFirstFile(InfPath,&FindFileData);
  1825. if(FindHandle != INVALID_HANDLE_VALUE) {
  1826. do {
  1827. BOOL NewInf = FALSE;
  1828. BOOL bCallCallback = FALSE;
  1829. PLOADED_INF pInf = NULL;
  1830. UINT ErrorLineNumber;
  1831. BOOL PnfWasUsed;
  1832. #ifdef UNICODE
  1833. if(!pInfCache || pInfCache->bNoWriteBack) {
  1834. //
  1835. // fallen into failsafe mode
  1836. //
  1837. bCallCallback = TRUE;
  1838. } else if((CompareFileTime(&FindFileData.ftLastWriteTime,&FileTimeBefore)>0)
  1839. && (CompareFileTime(&FindFileData.ftLastWriteTime,&FileTimeAfter)<0)) {
  1840. //
  1841. // if actual file time falls close to now, then
  1842. // we don't trust it
  1843. // force it to be deleted out of the cache
  1844. // and make sure we do a callback
  1845. //
  1846. // if there's an entry in the cache, we want to invalidate it
  1847. // - this is particularly important if we're being called to
  1848. // recreate the cache
  1849. //
  1850. InfId = InfCacheLookupInf(pInfCache,&FindFileData,&inf_entry);
  1851. if(InfId>=0) {
  1852. //
  1853. // there was a match
  1854. //
  1855. InfCacheRemoveInf(pInfCache,InfId,&inf_entry);
  1856. InfId = -1;
  1857. }
  1858. bCallCallback = TRUE;
  1859. NewInf = FALSE;
  1860. WriteLogEntry(
  1861. LogContext,
  1862. DRIVER_LOG_VERBOSE,
  1863. MSG_LOG_CACHE_TIMEFRAME,
  1864. NULL,
  1865. FindFileData.cFileName);
  1866. } else {
  1867. //
  1868. // mark this INF as existing
  1869. //
  1870. SearchFlags = InfCacheSearchTableSetFlags(pInfCache,
  1871. FindFileData.cFileName,
  1872. CHE_FLAGS_PENDING, // start off expecting this INF to be processed later
  1873. 0);
  1874. if(SearchFlags == (ULONG)(-1)) {
  1875. //
  1876. // failed - handle here
  1877. //
  1878. bCallCallback = TRUE;
  1879. }
  1880. InfId = InfCacheLookupInf(pInfCache,&FindFileData,&inf_entry);
  1881. if (InfId<0) {
  1882. NewInf = TRUE;
  1883. } else {
  1884. #if 0
  1885. //
  1886. // handle special inclusions (we can't handle these in Phase 2)
  1887. //
  1888. if (((Action&INFCACHE_INC_OLDINFS) && (inf_entry.MatchFlags&CIEF_INF_OLDINF)) ||
  1889. ((Action&INFCACHE_INC_NOCLASS) && (inf_entry.MatchFlags&CIEF_INF_NOCLASS))) {
  1890. bCallCallback = TRUE;
  1891. }
  1892. #endif
  1893. //
  1894. // handle exclusions (so that they will get excluded in Phase 2)
  1895. // exclusions are different for OLDNT and WIN4
  1896. //
  1897. if (inf_entry.MatchFlags & CIEF_INF_WIN4) {
  1898. //
  1899. // WIN4 INF
  1900. //
  1901. if(((Action & INFCACHE_EXC_URL) && (inf_entry.MatchFlags & CIEF_INF_URL)) ||
  1902. ((Action & INFCACHE_EXC_NULLCLASS) && (inf_entry.MatchFlags & CIEF_INF_NULLGUID)) ||
  1903. ((Action & INFCACHE_EXC_NOMANU) && !(inf_entry.MatchFlags & CIEF_INF_MANUFACTURER)) ||
  1904. ((Action & INFCACHE_EXC_NOCLASS) && !(inf_entry.MatchFlags & CIEF_INF_CLASSINFO))) {
  1905. //
  1906. // exclude this INF
  1907. //
  1908. InfCacheSearchTableSetFlags(pInfCache,
  1909. FindFileData.cFileName,
  1910. 0,
  1911. CHE_FLAGS_PENDING);
  1912. WriteLogEntry(
  1913. LogContext,
  1914. DRIVER_LOG_VVERBOSE,
  1915. MSG_LOG_EXCLUDE_WIN4_INF,
  1916. NULL,
  1917. FindFileData.cFileName);
  1918. }
  1919. } else if (inf_entry.MatchList & CIEF_INF_OLDNT) {
  1920. if((Action & INFCACHE_EXC_OLDINFS) ||
  1921. ((Action & INFCACHE_EXC_NOCLASS) && !(inf_entry.MatchList & CIEF_INF_CLASSINFO))) {
  1922. //
  1923. // exclude this INF
  1924. //
  1925. InfCacheSearchTableSetFlags(pInfCache,
  1926. FindFileData.cFileName,
  1927. 0,
  1928. CHE_FLAGS_PENDING);
  1929. WriteLogEntry(
  1930. LogContext,
  1931. DRIVER_LOG_VVERBOSE,
  1932. MSG_LOG_EXCLUDE_OLDNT_INF,
  1933. NULL,
  1934. FindFileData.cFileName);
  1935. } else {
  1936. //
  1937. // allow old INF's to match with any HwId's
  1938. // by considering it already matched
  1939. //
  1940. InfCacheSearchTableSetFlags(pInfCache,
  1941. FindFileData.cFileName,
  1942. CHE_FLAGS_IDMATCH,
  1943. 0);
  1944. }
  1945. } else {
  1946. //
  1947. // always exclude non-inf's
  1948. //
  1949. InfCacheSearchTableSetFlags(pInfCache,
  1950. FindFileData.cFileName,
  1951. 0,
  1952. CHE_FLAGS_PENDING);
  1953. }
  1954. }
  1955. }
  1956. #else
  1957. bCallCallback = TRUE; // Win9x
  1958. #endif
  1959. if (!Callback) {
  1960. //
  1961. // we were only called to re-build the cache
  1962. //
  1963. bCallCallback = FALSE;
  1964. }
  1965. if (NewInf || bCallCallback) {
  1966. PTSTR InfFullPath = NULL;
  1967. DWORD InfFullPathSize = lstrlen(InfDir)+MAX_PATH+2;
  1968. //
  1969. // we need to open HINF in either case
  1970. //
  1971. InfFullPath = MyMalloc(InfFullPathSize*sizeof(TCHAR));
  1972. if(InfFullPath == NULL) {
  1973. //
  1974. // carry on with other files, even if out of memory
  1975. // not the best thing to do, but consistant with
  1976. // what we did before.
  1977. //
  1978. continue;
  1979. }
  1980. lstrcpy(InfFullPath,InfDir);
  1981. pSetupConcatenatePaths(InfFullPath,FindFileData.cFileName,InfFullPathSize,NULL);
  1982. if((Err=LoadInfFile(InfFullPath,
  1983. &FindFileData,
  1984. INF_STYLE_WIN4 | INF_STYLE_OLDNT, // we'll filter this ourselves
  1985. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | (TryPnf?LDINF_FLAG_ALWAYS_TRY_PNF:0),
  1986. NULL,
  1987. NULL,
  1988. NULL,
  1989. NULL,
  1990. LogContext,
  1991. &pInf,
  1992. &ErrorLineNumber,
  1993. &PnfWasUsed)) != NO_ERROR) {
  1994. pInf = NULL;
  1995. WriteLogEntry(
  1996. LogContext,
  1997. DRIVER_LOG_VVERBOSE,
  1998. MSG_LOG_COULD_NOT_LOAD_NEW_INF,
  1999. NULL,
  2000. InfFullPath);
  2001. }
  2002. #ifdef UNICODE
  2003. if(NewInf) {
  2004. //
  2005. // if opening the INF failed, we still want to record this fact
  2006. // in the cache so we don't try to re-open next time round
  2007. //
  2008. InfId = InfCacheAddInf(LogContext,pInfCache,&FindFileData,&inf_entry,pInf);
  2009. if(Callback) {
  2010. bCallCallback = TRUE;
  2011. }
  2012. }
  2013. #endif
  2014. if (pInf) {
  2015. if (bCallCallback && Callback) {
  2016. //
  2017. // we're processing the INF now
  2018. // clear pending flag (if we can) so we don't try and process INF a 2nd time
  2019. // the only time this can fail is if we haven't already added the INF
  2020. // so either way we wont callback twice
  2021. //
  2022. #ifdef UNICODE
  2023. if (pInfCache) {
  2024. //
  2025. // only set flags in the cache
  2026. // if we have a cache :-)
  2027. //
  2028. InfCacheSearchTableSetFlags(pInfCache,FindFileData.cFileName,0,CHE_FLAGS_PENDING);
  2029. }
  2030. #endif
  2031. if(!Callback(LogContext,InfFullPath,pInf,PnfWasUsed,Context)) {
  2032. Err = GetLastError();
  2033. MYASSERT(Err);
  2034. FreeInfFile(pInf);
  2035. MyFree(InfFullPath);
  2036. goto cleanup;
  2037. }
  2038. }
  2039. FreeInfFile(pInf);
  2040. }
  2041. MyFree(InfFullPath);
  2042. }
  2043. } while (FindNextFile(FindHandle,&FindFileData));
  2044. FindClose(FindHandle);
  2045. }
  2046. if (!pInfCache) {
  2047. //
  2048. // we have processed all files already
  2049. // skip cache search code, since we don't
  2050. // have a cache to search
  2051. //
  2052. Err = NO_ERROR;
  2053. goto cleanup;
  2054. }
  2055. #ifdef UNICODE
  2056. //
  2057. // at this point we can commit cache
  2058. //
  2059. WriteLogEntry(
  2060. LogContext,
  2061. DRIVER_LOG_TIME,
  2062. MSG_LOG_END_CACHE_1,
  2063. NULL);
  2064. if(pInfCache && !bNoWriteBack) {
  2065. InfCacheWriteCache(InfDir,pInfCache,LogContext);
  2066. }
  2067. if (!Callback) {
  2068. //
  2069. // optimization: no callback
  2070. // (we were only called, eg, to update cache)
  2071. // leave early
  2072. //
  2073. Err = NO_ERROR;
  2074. goto cleanup;
  2075. }
  2076. //
  2077. // Phase 2 - determine all other INF's to process via Cache
  2078. //
  2079. // will want INFs that exist, haven't yet been processed
  2080. // and haven't been excluded
  2081. //
  2082. ReqFlags = CHE_FLAGS_PENDING;
  2083. if (ClassIdList && ClassIdList[0]) {
  2084. PCTSTR ClassId;
  2085. //
  2086. // Primary list (typically Class GUID, Class Name and Legacy Class Name)
  2087. //
  2088. Err = NO_ERROR;
  2089. for(ClassId = ClassIdList;*ClassId;ClassId += lstrlen(ClassId)+1) {
  2090. Err = InfCacheMarkMatchInfs(pInfCache,ClassId,CHE_FLAGS_GUIDMATCH);
  2091. if (Err != NO_ERROR) {
  2092. break;
  2093. }
  2094. }
  2095. if (Err == NO_ERROR) {
  2096. //
  2097. // succeeded, restrict requirement
  2098. //
  2099. ReqFlags |= CHE_FLAGS_GUIDMATCH;
  2100. }
  2101. }
  2102. if (HwIdList && HwIdList[0]) {
  2103. PCTSTR HwId;
  2104. //
  2105. // Secondary list
  2106. // if a list of hardware Id's specified, we only want hits that include
  2107. // any of the hardware Id's
  2108. //
  2109. Err = NO_ERROR;
  2110. for(HwId = HwIdList;*HwId;HwId += lstrlen(HwId)+1) {
  2111. Err = InfCacheMarkMatchInfs(pInfCache,HwId,CHE_FLAGS_IDMATCH);
  2112. if(Err != NO_ERROR) {
  2113. break;
  2114. }
  2115. }
  2116. if (Err == NO_ERROR) {
  2117. //
  2118. // succeeded, restrict requirement
  2119. //
  2120. ReqFlags |= CHE_FLAGS_IDMATCH;
  2121. }
  2122. }
  2123. //
  2124. // Phase 3 - process all INF's that meet requirements
  2125. // do this by simply enumerating the search string table
  2126. //
  2127. enum_data.LogContext = LogContext;
  2128. enum_data.Callback = Callback;
  2129. enum_data.Context = Context;
  2130. enum_data.InfDir = InfDir;
  2131. enum_data.Requirement = ReqFlags;
  2132. enum_data.ExitStatus = NO_ERROR;
  2133. Err = NO_ERROR;
  2134. if(!pStringTableEnum(pInfCache->pSearchTable,
  2135. &hit_stats,
  2136. sizeof(hit_stats),
  2137. InfCacheSearchEnum,
  2138. (LPARAM)&enum_data)) {
  2139. //
  2140. // we'll only fail for error condition
  2141. //
  2142. Err = enum_data.ExitStatus;
  2143. }
  2144. WriteLogEntry(
  2145. LogContext,
  2146. DRIVER_LOG_TIME,
  2147. MSG_LOG_END_CACHE_2,
  2148. NULL);
  2149. #else
  2150. Err = NO_ERROR;
  2151. #endif
  2152. cleanup:
  2153. #ifdef UNICODE
  2154. if (pInfCache) {
  2155. InfCacheFreeCache(pInfCache);
  2156. }
  2157. #endif
  2158. if (InfPath) {
  2159. MyFree(InfPath);
  2160. }
  2161. if (LogContext && LocalLogContext) {
  2162. DeleteLogContext(LocalLogContext);
  2163. }
  2164. return Err;
  2165. }
  2166. DWORD InfCacheSearchPath(
  2167. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  2168. IN DWORD Action,
  2169. IN PCTSTR InfDirPath, OPTIONAL
  2170. IN InfCacheCallback Callback, OPTIONAL
  2171. IN PVOID Context, OPTIONAL
  2172. IN PCTSTR ClassIdList, OPTIONAL
  2173. IN PCTSTR HwIdList OPTIONAL
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. Iterates InfDirPath calling InfCacheSearchDirectory for each entry
  2178. Arguments:
  2179. LogContext - for logging
  2180. InfDir - single directory to search - if not specified, uses driver path
  2181. Callback - function to call on a likely match
  2182. Context - parameter to pass to function
  2183. ClassIdList (optional) - multi-sz list of class id's (typically guid, name and legacy name)
  2184. HwIdList (optional)- multi-sz list of hardware id's
  2185. Return Value:
  2186. status, typically NO_ERROR
  2187. --*/
  2188. {
  2189. PSETUP_LOG_CONTEXT LocalLogContext = NULL;
  2190. DWORD Err = NO_ERROR;
  2191. PCTSTR InfDir;
  2192. if (!InfDirPath) {
  2193. InfDirPath = InfSearchPaths;
  2194. }
  2195. if(!LogContext) {
  2196. if(CreateLogContext(NULL,TRUE,&LocalLogContext)==NO_ERROR) {
  2197. LogContext = LocalLogContext;
  2198. } else {
  2199. return ERROR_NOT_ENOUGH_MEMORY;
  2200. }
  2201. }
  2202. for (InfDir = InfDirPath; *InfDir; InfDir+=lstrlen(InfDir)+1) {
  2203. Err = InfCacheSearchDirectory(LogContext,Action,InfDir,Callback,Context,ClassIdList,HwIdList);
  2204. if(Err != NO_ERROR) {
  2205. break;
  2206. }
  2207. }
  2208. if (LogContext && LocalLogContext) {
  2209. DeleteLogContext(LocalLogContext);
  2210. }
  2211. return Err;
  2212. }
  2213. #ifdef UNICODE
  2214. BOOL WINAPI pSetupInfCacheBuild(
  2215. IN DWORD Action
  2216. )
  2217. /*++
  2218. Routine Description:
  2219. Privately exported, called from (eg) syssetup to reset cache(s)
  2220. Arguments:
  2221. Action - one of:
  2222. INFCACHEBUILD_UPDATE
  2223. INFCACHEBUILD_REBUILD
  2224. Return Value:
  2225. TRUE if success, FALSE on Error (GetLastError indicates error)
  2226. --*/
  2227. {
  2228. DWORD RealAction;
  2229. DWORD Err;
  2230. switch(Action) {
  2231. case INFCACHEBUILD_UPDATE:
  2232. RealAction = INFCACHE_DEFAULT;
  2233. break;
  2234. case INFCACHEBUILD_REBUILD:
  2235. RealAction = INFCACHE_REBUILD;
  2236. break;
  2237. default:
  2238. SetLastError(ERROR_INVALID_PARAMETER);
  2239. return FALSE;
  2240. }
  2241. RealAction |= INFCACHE_FORCE_CACHE|INFCACHE_FORCE_PNF;
  2242. try {
  2243. Err = InfCacheSearchPath(NULL,
  2244. RealAction,
  2245. NULL,
  2246. NULL,
  2247. NULL,
  2248. NULL,
  2249. NULL
  2250. );
  2251. } except(EXCEPTION_EXECUTE_HANDLER) {
  2252. Err = ERROR_INVALID_DATA;
  2253. }
  2254. SetLastError(Err);
  2255. return Err==NO_ERROR;
  2256. }
  2257. #endif
  2258. BOOL
  2259. InfCacheAwareCopyFile(
  2260. IN LPCTSTR Source,
  2261. IN LPCTSTR Target
  2262. )
  2263. {
  2264. #ifdef UNICODE
  2265. FILETIME FileTimeNow;
  2266. //
  2267. // we use the uniqueness of the timestamp on the INF to
  2268. // know if an INF has been modified
  2269. // it appears that some vendors decide to "touch" the timestamp
  2270. // on related INF's that throws INFCACHE
  2271. //
  2272. // it's possible that InfCacheAwareCopyFile might get called for the same
  2273. // filename (different file) multiple times over a 2 second interval
  2274. // the InfCache code above will not trust a file to be stable until
  2275. // 5 seconds has elapsed, in which case modifications will have new
  2276. // timestamps
  2277. //
  2278. //
  2279. // what's our current time?
  2280. //
  2281. if(!CopyFile(Source, Target, FALSE)) {
  2282. return FALSE;
  2283. }
  2284. GetSystemTimeAsFileTime(&FileTimeNow);
  2285. //
  2286. // update time-stamp effectively invalidates the entry in INFCACHE
  2287. // this file will not be 'comitted' to cache for at least another 5
  2288. // seconds
  2289. //
  2290. GetSetFileTimestamp(Target,NULL,NULL,&FileTimeNow,TRUE);
  2291. return TRUE;
  2292. #else
  2293. return CopyFile(Source,Target,FALSE);
  2294. #endif
  2295. }