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.

1450 lines
38 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. For Internal use only!
  4. Module Name:
  5. INFSCAN
  6. infscan.cpp
  7. Abstract:
  8. Individual INF scanner class
  9. entry point InfScan::Run
  10. is invoked to parse an INF specified by InfScan::FullInfName
  11. WARNING! WARNING!
  12. SetupAPI implementation specific information is used
  13. to do the parsing
  14. History:
  15. Created July 2001 - JamieHun
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. int PnfGen::Run()
  20. /*++
  21. Routine Description:
  22. Job entry point: invoke GeneratePnf for context INF
  23. Arguments:
  24. NONE
  25. Return Value:
  26. 0 on success
  27. --*/
  28. {
  29. return GeneratePnf(InfName);
  30. }
  31. InfScan::InfScan(GlobalScan *globalScan,const SafeString & infName)
  32. /*++
  33. Routine Description:
  34. Initialization
  35. --*/
  36. {
  37. pGlobalScan = globalScan;
  38. FullInfName = infName;
  39. HasErrors = false;
  40. ThisIsLayoutInf = false;
  41. HasDependentFileChanged = false;
  42. ScanDevices = false;
  43. }
  44. InfScan::~InfScan()
  45. /*++
  46. Routine Description:
  47. Cleanup any dynamic data/handles
  48. --*/
  49. {
  50. }
  51. int
  52. InfScan::Run()
  53. /*++
  54. Routine Description:
  55. Job entry point: Parse a given Inf
  56. Arguments:
  57. NONE
  58. Return Value:
  59. 0 on success
  60. --*/
  61. {
  62. int res;
  63. //
  64. // see if this INF can be ignored
  65. //
  66. FileNameOnly = GetFileNamePart(FullInfName);
  67. FileDisposition & disp = pGlobalScan->GetFileDisposition(FileNameOnly);
  68. if((disp.FilterAction == ACTION_IGNOREINF) && (pGlobalScan->NewFilter == INVALID_HANDLE_VALUE)) {
  69. //
  70. // return here if the only flag set is ACTION_IGNOREINF
  71. // if any other flags are set, we must at least load the inf
  72. //
  73. return 0;
  74. }
  75. FilterAction = disp.FilterAction;
  76. FilterSection = disp.FilterErrorSection;
  77. FilterGuid = disp.FileGuid;
  78. if(pGlobalScan->BuildChangedDevices
  79. || (pGlobalScan->DeviceFilterList != INVALID_HANDLE_VALUE)
  80. || !pGlobalScan->IgnoreErrors) {
  81. //
  82. // maintain this flag so that we only scan devices if we need to
  83. //
  84. ScanDevices = true;
  85. }
  86. if((pGlobalScan->BuildChangedDevices & BUILD_CHANGED_DEVICES_INFCHANGED) &&
  87. pGlobalScan->IsFileChanged(FullInfName)) {
  88. HasDependentFileChanged = true;
  89. }
  90. PrimaryInf = Include(FullInfName,false);
  91. if(PrimaryInf->InfHandle == INVALID_HANDLE_VALUE) {
  92. FilterAction |= ACTION_IGNOREINF; // used when generating filters
  93. if(Pedantic() && !HasErrors) {
  94. Fail(MSG_INF_STYLE_WIN4);
  95. }
  96. return 0;
  97. }
  98. //
  99. // obviously there must be [Version] information
  100. // now see what kind of INF this is
  101. //
  102. res = CheckClassGuid();
  103. if(res != 0) {
  104. return res;
  105. }
  106. if(FilterAction & ACTION_IGNOREINF) {
  107. return 0;
  108. }
  109. //
  110. // if we haven't been filtered out, go on as if this is a driver INF
  111. //
  112. if(pGlobalScan->DetermineCopySections) {
  113. res = GetCopySections();
  114. if(res != 0) {
  115. return res;
  116. }
  117. }
  118. res = CheckDriverInf();
  119. if(res != 0) {
  120. return res;
  121. }
  122. res = ProcessCopySections();
  123. if(res != 0) {
  124. return res;
  125. }
  126. return res;
  127. }
  128. void
  129. InfScan::Fail(int err,const StringList & errors)
  130. /*++
  131. Routine Description:
  132. Handle an error while processing this INF
  133. Arguments:
  134. err = MSGID of error
  135. errors = list of string parameters
  136. Return Value:
  137. NONE
  138. --*/
  139. {
  140. if(pGlobalScan->IgnoreErrors) {
  141. //
  142. // not interested in errors, bail now
  143. //
  144. return;
  145. }
  146. //
  147. // prep the entry we want to add
  148. //
  149. ReportEntry ent(errors);
  150. ent.FilterAction = ACTION_FAILEDMATCH;
  151. if(!HasErrors) {
  152. //
  153. // on first error determine what errors we'll allow or not
  154. // (saves us processing filters for Good INF's)
  155. //
  156. if((pGlobalScan->InfFilter != INVALID_HANDLE_VALUE) &&
  157. (pGlobalScan->NewFilter == INVALID_HANDLE_VALUE)) {
  158. //
  159. // per-file filters has precedence over per-guid filters
  160. //
  161. LocalErrorFilters.LoadFromInfSection(pGlobalScan->InfFilter,FilterSection);
  162. LocalErrorFilters.LoadFromInfSection(pGlobalScan->InfFilter,GuidFilterSection);
  163. }
  164. HasErrors = true;
  165. }
  166. //
  167. // If the global action doesn't tell us to ignore, we want to add
  168. //
  169. int action = LocalErrorFilters.FindReport(err,ent);
  170. if(action & ACTION_NOMATCH) {
  171. action = pGlobalScan->GlobalErrorFilters.FindReport(err,ent);
  172. }
  173. if (action & (ACTION_IGNOREINF|ACTION_IGNOREMATCH)) {
  174. //
  175. // whichever filter we used, indicated to ignore
  176. //
  177. return;
  178. }
  179. //
  180. // add to our error table
  181. //
  182. action = LocalErrors.FindReport(err,ent,true);
  183. }
  184. int
  185. InfScan::CheckClassGuid()
  186. /*++
  187. Routine Description:
  188. Check to see if INF's ClassGUID is valid
  189. Arguments:
  190. NONE
  191. Return Value:
  192. 0 on success
  193. --*/
  194. {
  195. INFCONTEXT targetContext;
  196. SafeString guid;
  197. if(!SetupFindFirstLine(PrimaryInf->InfHandle,TEXT("Version"),TEXT("ClassGUID"),&targetContext)) {
  198. if(SetupFindFirstLine(PrimaryInf->InfHandle,TEXT("Version"),TEXT("Class"),&targetContext)) {
  199. //
  200. // if Class is specified, ClassGUID needs to be too
  201. //
  202. Fail(MSG_NO_CLASS_GUID);
  203. guid = INVALID_GUID;
  204. } else {
  205. //
  206. // this is a file way to specify no guid
  207. //
  208. guid = NULL_GUID;
  209. }
  210. } else {
  211. if(!MyGetStringField(&targetContext,1,guid)) {
  212. Fail(MSG_INVALID_CLASS_GUID);
  213. guid = INVALID_GUID;
  214. }
  215. if(guid.length() != 38) {
  216. Fail(MSG_INVALID_CLASS_GUID);
  217. guid = INVALID_GUID;
  218. }
  219. if(FilterGuid.length() != 0) {
  220. if(FilterGuid != guid) {
  221. Fail(MSG_INCORRECT_CLASS_GUID,FilterGuid);
  222. FilterGuid = guid;
  223. }
  224. } else {
  225. if((guid[0] != TEXT('{')) ||
  226. (guid[37] != TEXT('}'))) {
  227. Fail(MSG_INVALID_CLASS_GUID);
  228. guid = INVALID_GUID;
  229. }
  230. }
  231. }
  232. if(FilterGuid.empty()) {
  233. FilterGuid = guid;
  234. }
  235. //
  236. // see if any global handling to be done with this GUID
  237. //
  238. FileDisposition & disp = pGlobalScan->GetGuidDisposition(guid);
  239. FilterAction |= disp.FilterAction;
  240. GuidFilterSection = disp.FilterErrorSection;
  241. return 0;
  242. }
  243. int
  244. InfScan::CheckSameInfInstallConflict(const SafeString & desc, const SafeString & sect, bool & f)
  245. /*++
  246. Routine Description:
  247. Check to see if description appears twice in one INF for a different section
  248. Arguments:
  249. desc - description (lower-case)
  250. sect - section being checked (lower-case)
  251. f - returned true/false indicating duplicate
  252. Return Value:
  253. 0
  254. --*/
  255. {
  256. StringToString::iterator i;
  257. i = LocalInfDescriptions.find(desc);
  258. if(i != LocalInfDescriptions.end()) {
  259. //
  260. // already exists
  261. //
  262. if(i->second.compare(sect)==0) {
  263. //
  264. // but same section
  265. //
  266. f = false;
  267. } else {
  268. //
  269. // different section
  270. //
  271. f = true;
  272. Fail(MSG_LOCAL_DUPLICATE_DESC,sect,i->second,desc);
  273. }
  274. return 0;
  275. }
  276. //
  277. // first time
  278. //
  279. LocalInfDescriptions[desc] = sect;
  280. f = false;
  281. return 0;
  282. }
  283. int
  284. InfScan::CheckSameInfDeviceConflict(const SafeString & hwid, const SafeString & sect, bool & f)
  285. /*++
  286. Routine Description:
  287. Check to see if hwid appears twice in one INF for a different section
  288. (Ok for now)
  289. Arguments:
  290. hwid - hardware ID (lower-case)
  291. sect - section being checked (lower-case)
  292. f - returned true/false indicating duplicate
  293. Return Value:
  294. 0
  295. --*/
  296. {
  297. StringToString::iterator i;
  298. i = LocalInfHardwareIds.find(hwid);
  299. if(i != LocalInfHardwareIds.end()) {
  300. //
  301. // already exists
  302. //
  303. if(i->second.compare(sect)==0) {
  304. //
  305. // but same section
  306. //
  307. f = false;
  308. } else {
  309. //
  310. // different section
  311. //
  312. f = true;
  313. //Fail(MSG_LOCAL_DUPLICATE_DESC,sect,i->second,desc);
  314. }
  315. return 0;
  316. }
  317. //
  318. // first time
  319. //
  320. LocalInfHardwareIds[hwid] = sect;
  321. f = false;
  322. return 0;
  323. }
  324. int
  325. InfScan::PrepareCrossInfDeviceCheck()
  326. /*++
  327. Routine Description:
  328. Invoke pGlobalScan::SaveForCrossInfInstallCheck
  329. to prime table for later checks by CheckCrossInfInstallConflict
  330. Arguments:
  331. NONE
  332. Return Value:
  333. 0
  334. --*/
  335. {
  336. StringToString::iterator i;
  337. for(i = LocalInfHardwareIds.begin(); i != LocalInfHardwareIds.end(); i++) {
  338. if(pGlobalScan->BuildChangedDevices && !HasDependentFileChanged) {
  339. //
  340. // filter (only do this if !HasDependentFileChanged
  341. // otherwise we'll get wrong results. We optimize
  342. // writing stuff back)
  343. //
  344. if(ModifiedHardwareIds.find(i->first) == ModifiedHardwareIds.end()) {
  345. continue;
  346. }
  347. }
  348. pGlobalScan->SaveForCrossInfDeviceCheck(i->first,FileNameOnly);
  349. }
  350. return 0;
  351. }
  352. int
  353. InfScan::PrepareCrossInfInstallCheck()
  354. /*++
  355. Routine Description:
  356. Invoke pGlobalScan::SaveForCrossInfInstallCheck
  357. to prime table for later checks by CheckCrossInfInstallConflict
  358. Arguments:
  359. NONE
  360. Return Value:
  361. 0
  362. --*/
  363. {
  364. StringToString::iterator i;
  365. for(i = LocalInfDescriptions.begin(); i != LocalInfDescriptions.end(); i++) {
  366. pGlobalScan->SaveForCrossInfInstallCheck(i->first,FileNameOnly);
  367. }
  368. return 0;
  369. }
  370. int
  371. InfScan::CheckCrossInfDeviceConflicts()
  372. /*++
  373. Routine Description:
  374. Invoke pGlobalScan::CheckCrossInfDeviceConflict
  375. for each device in this INF to see if device is used in another INF
  376. this is done during Results phase
  377. Arguments:
  378. desc - description (lower-case)
  379. f - returned true/false indicating duplicate
  380. Return Value:
  381. 0
  382. --*/
  383. {
  384. StringToString::iterator i;
  385. for(i = LocalInfHardwareIds.begin(); i != LocalInfHardwareIds.end(); i++) {
  386. bool f;
  387. const SafeString & hwid = i->first;
  388. SafeString & sect = i->second;
  389. SafeString other;
  390. int res;
  391. res = pGlobalScan->CheckCrossInfDeviceConflict(hwid,FileNameOnly,f,other);
  392. if(res==0 && f) {
  393. Fail(MSG_GLOBAL_DUPLICATE_HWID,sect,other,hwid);
  394. }
  395. }
  396. return 0;
  397. }
  398. int
  399. InfScan::CheckCrossInfInstallConflicts()
  400. /*++
  401. Routine Description:
  402. Invoke pGlobalScan::CheckCrossInfInstallConflict
  403. for each description in this INF to see if description is used in another INF
  404. this is done during Results phase
  405. Arguments:
  406. desc - description (lower-case)
  407. f - returned true/false indicating duplicate
  408. Return Value:
  409. 0
  410. --*/
  411. {
  412. StringToString::iterator i;
  413. for(i = LocalInfDescriptions.begin(); i != LocalInfDescriptions.end(); i++) {
  414. bool f;
  415. const SafeString & desc = i->first;
  416. SafeString & sect = i->second;
  417. SafeString other;
  418. int res;
  419. res = pGlobalScan->CheckCrossInfInstallConflict(desc,FileNameOnly,f,other);
  420. if(res==0 && f) {
  421. Fail(MSG_GLOBAL_DUPLICATE_DESC,sect,other,desc);
  422. }
  423. }
  424. return 0;
  425. }
  426. int
  427. InfScan::CheckModelsSection(const SafeString & section,const StringList & shadowDecorations,DWORD platformMask,bool CopyElimination)
  428. /*++
  429. Routine Description:
  430. Process a given models section
  431. WARNING! may need to change if SetupAPI install behavior changes
  432. MAINTAINANCE: This function expects [Models] to follow
  433. <desc> = <sect>[,id....]
  434. MAINTAINANCE: Must keep all possible decorations up to date
  435. MAINTAINANCE: Must keep all shadow install sections up to date
  436. Arguments:
  437. section - name of models section
  438. shadowDecorations - decorations to append (passed into CheckInstallSections)
  439. PlatformMask - limit of platforms being processed
  440. sections - returned list of decorated sections to be processed
  441. CopyElimination - true if processing to eliminate from potential non-driver sections
  442. Return Value:
  443. 0 on success
  444. --*/
  445. {
  446. int res;
  447. bool f;
  448. INFCONTEXT context;
  449. SafeString desc;
  450. SafeString installsect;
  451. HINF inf = PrimaryInf->InfHandle;
  452. if(!SetupFindFirstLine(inf,section.c_str(),NULL,&context)) {
  453. if(SetupGetLineCount(inf, section.c_str()) == -1) {
  454. if(!CopyElimination) {
  455. Fail(MSG_NO_LISTED_MODEL,section);
  456. }
  457. }
  458. return 0;
  459. }
  460. //
  461. // enumerate through each <desc> = <install>[,hwid...]
  462. //
  463. do {
  464. if(CopyElimination) {
  465. //
  466. // CopyElimination pass
  467. //
  468. if(!MyGetStringField(&context,1,installsect) || installsect.empty()) {
  469. continue;
  470. }
  471. //
  472. // check for all possible install sections
  473. //
  474. InstallSectionBlobList sections;
  475. res = CheckInstallSections(installsect,platformMask,shadowDecorations,sections,true,CopyElimination);
  476. } else {
  477. //
  478. // Driver processing pass
  479. //
  480. if(!MyGetStringField(&context,0,desc) || desc.empty()) {
  481. Fail(MSG_EXPECTED_DESCRIPTION,section);
  482. continue;
  483. }
  484. if(!MyGetStringField(&context,1,installsect) || installsect.empty()) {
  485. Fail(MSG_EXPECTED_INSTALL_SECTION,section,desc);
  486. continue;
  487. }
  488. if(!pGlobalScan->IgnoreErrors) {
  489. //
  490. // only check for conflicts if we're going
  491. // to report errors
  492. //
  493. res = CheckSameInfInstallConflict(desc,installsect,f);
  494. if(res != 0) {
  495. return res;
  496. }
  497. }
  498. InstallSectionBlobList sections;
  499. //
  500. // check for all possible install sections
  501. //
  502. res = CheckInstallSections(installsect,platformMask,shadowDecorations,sections,true,CopyElimination);
  503. if(ScanDevices) {
  504. StringSet hwids;
  505. //
  506. // extract all hardware ID's handled
  507. //
  508. int hwidIter = 2;
  509. SafeString hwid;
  510. //
  511. // inf-centric hardware ID's
  512. // and fill in hwid for hardware ID's specific to this install line
  513. //
  514. while(MyGetStringField(&context,hwidIter++,hwid)) {
  515. if(hwid.length()) {
  516. hwids.insert(hwid);
  517. res = CheckSameInfDeviceConflict(hwid,installsect,f);
  518. if(res != 0) {
  519. return res;
  520. }
  521. }
  522. }
  523. //
  524. // install-section centric hardware ID's
  525. //
  526. InstallSectionBlobList::iterator isli;
  527. for(isli = sections.begin(); isli != sections.end(); isli++) {
  528. (*isli)->AddHWIDs(hwids);
  529. }
  530. }
  531. }
  532. } while (SetupFindNextLine(&context,&context));
  533. return 0;
  534. }
  535. InstallSectionBlob InfScan::GetInstallSection(const SafeString & section)
  536. /*++
  537. Routine Description:
  538. Obtain an install section (might already exist)
  539. Arguments:
  540. section - name of install section
  541. Return Value:
  542. InstallSection object related to the named install section
  543. --*/
  544. {
  545. //
  546. // see if we have one cached away
  547. //
  548. StringToInstallSectionBlob::iterator srch;
  549. srch = UsedInstallSections.find(section);
  550. if(srch != UsedInstallSections.end()) {
  551. return srch->second;
  552. }
  553. //
  554. // nope, so add one
  555. //
  556. InstallSectionBlob sect;
  557. sect.create();
  558. sect->pGlobalScan = pGlobalScan;
  559. sect->pInfScan = this;
  560. sect->Section = section;
  561. UsedInstallSections[section] = sect;
  562. return sect;
  563. }
  564. int
  565. InfScan::CheckInstallSections(
  566. const SafeString & namedSection,
  567. DWORD platformMask,
  568. const StringList & shadowDecorations,
  569. InstallSectionBlobList & sections,
  570. bool required,
  571. bool CopyElimination)
  572. /*++
  573. Routine Description:
  574. Given a section name
  575. determine list of decorated sections to parse
  576. Arguments:
  577. namedSection - 'undecorated' section
  578. shadowDecorations - sub-decorations appended to platform decorated section get complete list of install sections
  579. sections - list of sections determined (CopyElimination = false)
  580. warn - true if section is required
  581. CopyElimination - true if processing to eliminate sections
  582. Return Value:
  583. 0 on success
  584. --*/
  585. {
  586. static StringProdPair decorations[] = {
  587. //
  588. // listed from most specific to most generic
  589. // all lower-case
  590. //
  591. { TEXT(".ntx86"), PLATFORM_MASK_NTX86 },
  592. { TEXT(".ntia64"), PLATFORM_MASK_NTIA64 },
  593. { TEXT(".ntamd64"), PLATFORM_MASK_NTAMD64 },
  594. { TEXT(".nt"), PLATFORM_MASK_NT },
  595. { TEXT(""), PLATFORM_MASK_ALL_ARCHITECTS },
  596. { NULL, 0 }
  597. };
  598. int i;
  599. StringList::iterator ii;
  600. SafeString sectFull;
  601. SafeString sectFullDec;
  602. if(CopyElimination) {
  603. //
  604. // copy elimination pass
  605. //
  606. for(i=0;decorations[i].String;i++) {
  607. sectFull = namedSection + decorations[i].String;
  608. PotentialInstallSections.erase(sectFull);
  609. for(ii = shadowDecorations.begin(); ii != shadowDecorations.end(); ii++) {
  610. sectFullDec = sectFull+*ii;
  611. PotentialInstallSections.erase(sectFullDec);
  612. }
  613. }
  614. return 0;
  615. }
  616. bool f = false;
  617. DWORD platforms = platformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN);
  618. HINF inf = PrimaryInf->InfHandle;
  619. for(i=0;decorations[i].String;i++) {
  620. DWORD plat = platforms & decorations[i].ProductMask;
  621. if(plat) {
  622. sectFull = namedSection + decorations[i].String;
  623. //
  624. // see if this section exists
  625. //
  626. if(SetupGetLineCount(inf, sectFull.c_str()) == -1) {
  627. //
  628. // nope, look for another one
  629. //
  630. continue;
  631. }
  632. f = true;
  633. //
  634. // return list of all sections potentially used
  635. // over all platforms of interest
  636. //
  637. InstallSectionBlob sectInfo = GetInstallSection(sectFull);
  638. sectInfo->PlatformMask |= plat;
  639. sections.push_back(sectInfo);
  640. //
  641. // these sections are processed in parallel with primary section
  642. //
  643. for(ii = shadowDecorations.begin(); ii != shadowDecorations.end(); ii++) {
  644. sectFullDec = sectFull+*ii;
  645. PotentialInstallSections.erase(sectFullDec);
  646. sectInfo = GetInstallSection(sectFullDec);
  647. sectInfo->PlatformMask |= plat;
  648. sections.push_back(sectInfo);
  649. }
  650. platforms &= ~plat;
  651. }
  652. }
  653. if(!f) {
  654. //
  655. // no install section found at all
  656. //
  657. if(required) {
  658. Fail(MSG_NO_ACTUAL_INSTALL_SECTION,namedSection);
  659. }
  660. } else if(Pedantic()) {
  661. if(platforms) {
  662. //
  663. // an install section found but not all platforms covered
  664. //
  665. Fail(MSG_NO_GENERIC_INSTALL_SECTION,namedSection);
  666. }
  667. }
  668. return 0;
  669. }
  670. int
  671. InfScan::GetCopySections()
  672. /*++
  673. Routine Description:
  674. Get initial list of sections (place into set for modification)
  675. don't do anything that takes time yet
  676. Arguments:
  677. NONE
  678. Return Value:
  679. 0 on success
  680. --*/
  681. {
  682. StringList sections;
  683. INFCONTEXT context;
  684. pGlobalScan->SetupAPI.GetInfSections(PrimaryInf->InfHandle,sections);
  685. StringList::iterator i;
  686. for(i = sections.begin(); i != sections.end(); i++) {
  687. PotentialInstallSections.insert(*i);
  688. }
  689. if(sections.empty()) {
  690. return 0;
  691. }
  692. //
  693. // get rid of some special cases
  694. //
  695. PotentialInstallSections.erase(TEXT("sourcedisksfiles"));
  696. PotentialInstallSections.erase(TEXT("sourcedisksnames"));
  697. PotentialInstallSections.erase(TEXT("version"));
  698. PotentialInstallSections.erase(TEXT("strings"));
  699. PotentialInstallSections.erase(TEXT("classinstall"));
  700. PotentialInstallSections.erase(TEXT("manufacturer"));
  701. //
  702. // special pass of driver files
  703. //
  704. int res = CheckDriverInf(true);
  705. if(res != 0) {
  706. return res;
  707. }
  708. //
  709. // now enumerate what we have left
  710. //
  711. StringSet::iterator ii;
  712. for(ii = PotentialInstallSections.begin(); ii != PotentialInstallSections.end() ; ii++) {
  713. const SafeString & str = *ii;
  714. if(str.empty()) {
  715. continue;
  716. }
  717. if(str[0] == TEXT('s')) {
  718. if((_tcsncmp(str.c_str(),TEXT("sourcedisksfiles."),17)==0) ||
  719. (_tcsncmp(str.c_str(),TEXT("sourcedisksnames."),17)==0) ||
  720. (_tcsncmp(str.c_str(),TEXT("strings."),8)==0)) {
  721. continue;
  722. }
  723. }
  724. //
  725. // for this section to be valid, it must have at least one
  726. // CopyFiles = directive
  727. //
  728. if(!SetupFindFirstLine(PrimaryInf->InfHandle,str.c_str(),TEXT("copyfiles"),&context)) {
  729. continue;
  730. }
  731. //
  732. // ok, consider this
  733. //
  734. OtherInstallSections.insert(str);
  735. }
  736. return 0;
  737. }
  738. int
  739. InfScan::ProcessCopySections()
  740. /*++
  741. Routine Description:
  742. Process final list of copy sections
  743. Arguments:
  744. NONE
  745. Return Value:
  746. 0 on success
  747. --*/
  748. {
  749. int res = pGlobalScan->GetCopySections(FileNameOnly,OtherInstallSections);
  750. if(res != 0) {
  751. return res;
  752. }
  753. if(OtherInstallSections.empty()) {
  754. return 0;
  755. }
  756. //
  757. // make sure we haven't set IGNOREINF anywhere in our pass
  758. //
  759. FilterAction &= ~ ACTION_IGNOREINF;
  760. //
  761. // for each install section...
  762. //
  763. StringSet::iterator i;
  764. DWORD platforms = pGlobalScan->Version.PlatformMask & (PLATFORM_MASK_NT|PLATFORM_MASK_WIN);
  765. for(i = OtherInstallSections.begin(); i != OtherInstallSections.end(); i++) {
  766. InstallScan s;
  767. s.pGlobalScan = pGlobalScan;
  768. s.pInfScan = this;
  769. s.PlatformMask = platforms;
  770. s.Section = *i;
  771. s.NotDeviceInstall = true;
  772. res =s.ScanInstallSection();
  773. if(res != 0) {
  774. return res;
  775. }
  776. }
  777. return 0;
  778. }
  779. int
  780. InfScan::CheckClassInstall(bool CopyElimination)
  781. /*++
  782. Routine Description:
  783. Process one of the [classinstall32.*] sections
  784. WARNING! may need to change if SetupAPI install behavior changes
  785. Arguments:
  786. sections - returned list of classinstall32 section variations
  787. CopyElimination - true if just doing copy elimination
  788. Return Value:
  789. 0 on success
  790. --*/
  791. {
  792. StringList shadows; // currently none
  793. InstallSectionBlobList sections;
  794. return CheckInstallSections(TEXT("classinstall32"),
  795. pGlobalScan->Version.PlatformMask,
  796. shadows,
  797. sections,
  798. false,
  799. CopyElimination);
  800. }
  801. int
  802. InfScan::CheckDriverInf(bool CopyElimination)
  803. /*++
  804. Routine Description:
  805. Process the [manufacturer] section
  806. WARNING! may need to change if SetupAPI install behavior changes
  807. MAINTAINANCE: This function expects [Manufacturer] to follow
  808. <desc> = <sect>[,dec....]
  809. MAINTAINANCE: Modify NodeVerInfo class if decr syntax changes
  810. Arguments:
  811. CopyElimination - true if just doing copy elimination
  812. Return Value:
  813. 0 on success
  814. --*/
  815. {
  816. INFCONTEXT context;
  817. int res;
  818. SafeString ModelSection;
  819. SafeString DecSection;
  820. SafeString ActualSection;
  821. StringList shadows;
  822. int dec;
  823. HINF inf = PrimaryInf->InfHandle;
  824. bool hasModels;
  825. res = CheckClassInstall(CopyElimination);
  826. if(res > 0) {
  827. return res;
  828. }
  829. if(SetupFindFirstLine(inf,TEXT("manufacturer"),NULL,&context)) {
  830. hasModels = true;
  831. } else {
  832. hasModels = false;
  833. if(Pedantic()) {
  834. Fail(MSG_NO_MANUFACTURER);
  835. }
  836. FilterAction |= ACTION_IGNOREINF;
  837. if(UsedInstallSections.empty()) {
  838. //
  839. // no classinstall32 sections either, can return
  840. //
  841. return 0;
  842. }
  843. }
  844. if(hasModels) {
  845. //
  846. // for a given DDInstall, also need to process these decorations
  847. //
  848. shadows.push_back(TEXT(".coinstallers"));
  849. shadows.push_back(TEXT(".interfaces"));
  850. //
  851. // obtain list of all installation sections to parse
  852. //
  853. do {
  854. //
  855. // Model section entry
  856. // expect <desc> = <section> [, dec [, dec ... ]]
  857. //
  858. if(!MyGetStringField(&context,1,ModelSection) || !ModelSection.length()) {
  859. Fail(MSG_EXPECTED_MODEL_SECTION);
  860. continue;
  861. }
  862. if(CopyElimination) {
  863. PotentialInstallSections.erase(ModelSection);
  864. }
  865. //
  866. // process all the model decorations
  867. //
  868. NodeVerInfoList nodes;
  869. NodeVerInfoList::iterator i;
  870. NodeVerInfo node;
  871. //
  872. // first entry is the default node (no decoration)
  873. //
  874. nodes.push_back(node);
  875. //
  876. // determine interesting decorations
  877. //
  878. for(dec = 2;MyGetStringField(&context,dec,DecSection);dec++) {
  879. if(DecSection.length()) {
  880. if(DecSection[0]==TEXT('.')) {
  881. //
  882. // cannot start with '.'
  883. //
  884. res = 4;
  885. } else {
  886. res = node.Parse(DecSection);
  887. }
  888. if(res == 4) {
  889. Fail(MSG_MODEL_DECORATION_BAD,ModelSection,DecSection);
  890. continue;
  891. }
  892. }
  893. if(CopyElimination) {
  894. //
  895. // processing for copy sections
  896. // can't do at same time as driver install processing
  897. //
  898. nodes.push_back(node);
  899. } else if(node.IsCompatibleWith(pGlobalScan->Version)) {
  900. //
  901. // this is something to be considered
  902. // see if this is better than anything
  903. // we have so far based on the version
  904. // criterias we're checking against
  905. //
  906. for(i = nodes.begin(); i != nodes.end(); i++) {
  907. int test = node.IsBetter(*i,pGlobalScan->Version);
  908. switch(test) {
  909. case 1:
  910. //
  911. // *i is better
  912. //
  913. node.Rejected = true;
  914. break;
  915. case 0:
  916. //
  917. // node & *i are equally valid
  918. //
  919. break;
  920. case -1:
  921. //
  922. // node & *i are the same
  923. //
  924. node.Rejected = true;
  925. break;
  926. case -2:
  927. //
  928. // node is better
  929. //
  930. (*i).Rejected = true;
  931. break;
  932. }
  933. }
  934. nodes.push_back(node);
  935. }
  936. }
  937. //
  938. // now look at each decorated models section in turn
  939. // (that we've decided are interesting)
  940. // adding any install sections to 'sections'
  941. // for later processing
  942. //
  943. for(i = nodes.begin(); i != nodes.end(); i++) {
  944. if((*i).Rejected) {
  945. continue;
  946. }
  947. ActualSection = ModelSection;
  948. if((*i).Decoration.length()) {
  949. ActualSection+=(TEXT("."));
  950. ActualSection+=((*i).Decoration);
  951. if(CopyElimination) {
  952. PotentialInstallSections.erase(ActualSection);
  953. }
  954. }
  955. DWORD platforms = (*i).PlatformMask & pGlobalScan->Version.PlatformMask &
  956. PLATFORM_MASK_ALL_ARCHITECTS;
  957. res = CheckModelsSection(ModelSection,shadows,platforms,CopyElimination);
  958. if(res != 0) {
  959. return res;
  960. }
  961. }
  962. } while (SetupFindNextLine(&context,&context));
  963. }
  964. if(CopyElimination || UsedInstallSections.empty()) {
  965. //
  966. // no sections to process
  967. //
  968. return 0;
  969. }
  970. //
  971. // now parse all the device install sections
  972. //
  973. StringToInstallSectionBlob::iterator s;
  974. for(s = UsedInstallSections.begin() ; s != UsedInstallSections.end(); s++) {
  975. res = s->second->ScanInstallSection();
  976. if(res != 0) {
  977. return res;
  978. }
  979. if(s->second->HasDependentFileChanged) {
  980. //
  981. // merge hardware ID's back
  982. // (optimization for now to do this only when needed)
  983. //
  984. s->second->GetHWIDs(ModifiedHardwareIds);
  985. }
  986. }
  987. return 0;
  988. }
  989. ParseInfContextBlob & InfScan::Include(const SafeString & val,bool expandPath)
  990. /*++
  991. Routine Description:
  992. Called to add an INF to our list of INF's required to process the
  993. primary INF in question.
  994. If 'expandPath' is false, this is the primary INF and we don't
  995. need to determine the path of the INF
  996. If 'expandPath' is true, this is an included INF.
  997. Arguments:
  998. val - name of INF
  999. expandPath - true if we need to determine location of INF
  1000. Return Value:
  1001. Modifiable ParseInfContextBlob entry
  1002. --*/
  1003. {
  1004. SafeString infpath;
  1005. SafeString infname;
  1006. ParseInfContextMap::iterator i;
  1007. int res = 0;
  1008. if(expandPath) {
  1009. //
  1010. // we are being supplied (supposedly) only the name
  1011. //
  1012. infname = val;
  1013. } else {
  1014. //
  1015. // we are being supplied full pathname
  1016. //
  1017. infpath = val;
  1018. infname = GetFileNamePart(infpath.c_str());
  1019. }
  1020. i = Infs.find(infname);
  1021. if(i != Infs.end()) {
  1022. //
  1023. // already have it
  1024. //
  1025. return i->second;
  1026. }
  1027. if(expandPath) {
  1028. //
  1029. // we need to obtain full pathname
  1030. //
  1031. res = pGlobalScan->ExpandFullPathWithOverride(val,infpath);
  1032. }
  1033. ParseInfContextBlob & ThisInf = Infs[infname];
  1034. ThisInf.create();
  1035. ThisInf->InfName = infname;
  1036. ThisInf->pGlobalScan = pGlobalScan;
  1037. ThisInf->pInfScan = this;
  1038. if(res == 0) {
  1039. ThisInf->InfHandle = SetupOpenInfFile(infpath.c_str(),NULL,INF_STYLE_WIN4,NULL);
  1040. }
  1041. if(ThisInf->InfHandle == INVALID_HANDLE_VALUE) {
  1042. DWORD Err = GetLastError();
  1043. if(Err != ERROR_WRONG_INF_STYLE) {
  1044. Fail(MSG_OPENAPPENDINF,infname,infpath);
  1045. }
  1046. return ThisInf;
  1047. }
  1048. //
  1049. // load the source disks files and destination dirs that's in this INF
  1050. //
  1051. if(ThisIsLayoutInf || !pGlobalScan->LimitedSourceDisksFiles) {
  1052. ThisInf->LoadSourceDisksFiles();
  1053. }
  1054. ThisInf->LoadDestinationDirs();
  1055. return ThisInf;
  1056. }
  1057. int
  1058. InfScan::PartialCleanup()
  1059. /*++
  1060. Routine Description:
  1061. Clean up as much as we can
  1062. leaving only the info we need to complete the results phase
  1063. Whatever we do, don't leave INF handles open
  1064. 700+ INF handles eats up virtual memory
  1065. Arguments:
  1066. NONE
  1067. Return Value:
  1068. 0 on success
  1069. --*/
  1070. {
  1071. //
  1072. // 'LocalInfDescriptions' required for cross-checking
  1073. // 'LocalErrorFilters' required for cross-checking
  1074. // 'LocalErrors' required for output
  1075. // 'Infs' required for filter generation (but not handle)
  1076. //
  1077. PotentialInstallSections.clear();
  1078. UsedInstallSections.clear();
  1079. if(pGlobalScan->NewFilter == INVALID_HANDLE_VALUE) {
  1080. //
  1081. // for results generation only, we don't need Inf information
  1082. //
  1083. Infs.clear();
  1084. }
  1085. //
  1086. // If we still have Infs table, make sure all INF's are closed
  1087. //
  1088. ParseInfContextMap::iterator i;
  1089. for(i = Infs.begin(); i != Infs.end(); i++) {
  1090. i->second->PartialCleanup();
  1091. }
  1092. return 0;
  1093. }
  1094. int
  1095. InfScan::PreResults()
  1096. /*++
  1097. Routine Description:
  1098. Perform pre-results phase. Prime any global tables that will
  1099. be scanned by other InfScan functions during Results phase
  1100. In particular, do the cross-inf checking
  1101. Arguments:
  1102. NONE
  1103. Return Value:
  1104. 0 on success
  1105. --*/
  1106. {
  1107. if(!pGlobalScan->IgnoreErrors) {
  1108. PrepareCrossInfInstallCheck();
  1109. PrepareCrossInfDeviceCheck();
  1110. } else {
  1111. if(pGlobalScan->DeviceFilterList != INVALID_HANDLE_VALUE) {
  1112. PrepareCrossInfDeviceCheck();
  1113. }
  1114. }
  1115. return 0;
  1116. }
  1117. int
  1118. InfScan::Results()
  1119. /*++
  1120. Routine Description:
  1121. Perform results phase. This function is called sequentially
  1122. so we can do thread-unsafe operations such as merging results
  1123. Arguments:
  1124. NONE
  1125. Return Value:
  1126. 0 on success
  1127. --*/
  1128. {
  1129. int res;
  1130. //
  1131. // finish checking for cross-inf conflicts
  1132. //
  1133. if(!pGlobalScan->IgnoreErrors) {
  1134. CheckCrossInfInstallConflicts();
  1135. CheckCrossInfDeviceConflicts();
  1136. }
  1137. if(pGlobalScan->DetermineCopySections) {
  1138. pGlobalScan->SetCopySections(FileNameOnly,OtherInstallSections);
  1139. }
  1140. res = pGlobalScan->AddSourceFiles(SourceFiles);
  1141. if(res != 0) {
  1142. return res;
  1143. }
  1144. if(pGlobalScan->NewFilter == INVALID_HANDLE_VALUE) {
  1145. //
  1146. // display errors
  1147. //
  1148. ReportEntryMap::iterator byTag;
  1149. for(byTag = LocalErrors.begin(); byTag != LocalErrors.end(); byTag++) {
  1150. //
  1151. // this is our class/tag of error
  1152. //
  1153. int tag = byTag->first;
  1154. ReportEntrySet &s = byTag->second;
  1155. ReportEntrySet::iterator byText;
  1156. for(byText = s.begin(); byText != s.end(); byText++) {
  1157. //
  1158. // this is our actual error
  1159. //
  1160. (*byText)->Report(tag,FullInfName);
  1161. }
  1162. }
  1163. } else {
  1164. res = GenerateFilterInformation();
  1165. if(res != 0) {
  1166. return res;
  1167. }
  1168. }
  1169. return 0;
  1170. }
  1171. int InfScan::GenerateFilterInformation()
  1172. /*++
  1173. Routine Description:
  1174. Generate entries into the new filter file
  1175. called as part of results processing
  1176. Arguments:
  1177. NONE
  1178. Return Value:
  1179. 0 on success
  1180. --*/
  1181. {
  1182. //
  1183. // generate all the filter information required
  1184. //
  1185. FileDisposition & filedisp = pGlobalScan->GetFileDisposition(FileNameOnly);
  1186. filedisp.Filtered = true;
  1187. filedisp.FilterAction = FilterAction;
  1188. filedisp.FileGuid = FilterGuid;
  1189. if(FilterGuid.length()) {
  1190. filedisp.FilterAction |= ACTION_CHECKGUID;
  1191. FileDisposition & guiddisp = pGlobalScan->GetGuidDisposition(FilterGuid);
  1192. guiddisp.Filtered = true;
  1193. guiddisp.FilterAction = ACTION_DEFAULT;
  1194. }
  1195. //
  1196. // process through all errors and create local error filter
  1197. // if there is any errors, designate a section name for the errors
  1198. //
  1199. if(HasErrors) {
  1200. filedisp.FilterErrorSection = GetFileNamePart(FullInfName) + TEXT(".Errors");
  1201. Write(pGlobalScan->NewFilter,"\r\n[");
  1202. Write(pGlobalScan->NewFilter,filedisp.FilterErrorSection);
  1203. Write(pGlobalScan->NewFilter,"]\r\n");
  1204. ReportEntryMap::iterator byTag;
  1205. for(byTag = LocalErrors.begin(); byTag != LocalErrors.end(); byTag++) {
  1206. //
  1207. // this is our class/tag of error
  1208. //
  1209. int tag = byTag->first;
  1210. ReportEntrySet &s = byTag->second;
  1211. ReportEntrySet::iterator byText;
  1212. for(byText = s.begin(); byText != s.end(); byText++) {
  1213. //
  1214. // this is our actual error
  1215. //
  1216. (*byText)->AppendFilterInformation(pGlobalScan->NewFilter,tag);
  1217. }
  1218. }
  1219. }
  1220. //
  1221. // process through all DestinationDirs
  1222. // and create a list of unprocessed sections
  1223. // for a 2nd pass CopyFiles
  1224. //
  1225. return 0;
  1226. }