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.

3101 lines
94 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. infopenv.c
  5. Abstract:
  6. Externally exposed INF routines for INF opening, closing,
  7. and versioning.
  8. Author:
  9. Ted Miller (tedm) 20-Jan-1995
  10. Revision History:
  11. Jamie Hunter (JamieHun) May-2-2002
  12. Security code review
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. BOOL
  17. pSetupVersionNodeFromInfInformation(
  18. IN PSP_INF_INFORMATION InfInformation,
  19. IN UINT InfIndex,
  20. OUT PINF_VERSION_NODE VersionNode,
  21. OUT PTSTR OriginalFilename OPTIONAL
  22. );
  23. #ifdef UNICODE
  24. //
  25. // ANSI version
  26. //
  27. BOOL
  28. SetupGetInfInformationA(
  29. IN LPCVOID InfSpec,
  30. IN DWORD SearchControl,
  31. OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
  32. IN DWORD ReturnBufferSize,
  33. OUT PDWORD RequiredSize OPTIONAL
  34. )
  35. {
  36. PCWSTR infspec;
  37. BOOL b;
  38. DWORD rc;
  39. //
  40. // For this API, the return buffer does not have to be translated
  41. // from Unicode to ANSI. This makes things much easier since the
  42. // required size is the same for the ANSI and Unicode versions.
  43. //
  44. if((SearchControl == INFINFO_INF_NAME_IS_ABSOLUTE)
  45. || (SearchControl == INFINFO_DEFAULT_SEARCH)
  46. || (SearchControl == INFINFO_REVERSE_DEFAULT_SEARCH)
  47. || (SearchControl == INFINFO_INF_PATH_LIST_SEARCH)) {
  48. rc = pSetupCaptureAndConvertAnsiArg(InfSpec,&infspec);
  49. if(rc != NO_ERROR) {
  50. SetLastError(rc);
  51. return(FALSE);
  52. }
  53. } else {
  54. //
  55. // Not a pointer to a string, just pass it on.
  56. //
  57. infspec = InfSpec;
  58. }
  59. //
  60. // Note that the data returned from this API is in an
  61. // internal format, and thus we don't need any less space
  62. // for the ANSI API, and can just use the buffer and sizes
  63. // passed in by the caller.
  64. //
  65. b = SetupGetInfInformationW(
  66. infspec,
  67. SearchControl,
  68. ReturnBuffer,
  69. ReturnBufferSize,
  70. RequiredSize
  71. );
  72. rc = GetLastError();
  73. if(infspec != InfSpec) {
  74. MyFree(infspec);
  75. }
  76. SetLastError(rc);
  77. return(b);
  78. }
  79. #else
  80. //
  81. // Unicode stub
  82. //
  83. BOOL
  84. SetupGetInfInformationW(
  85. IN LPCVOID InfSpec,
  86. IN DWORD SearchControl,
  87. OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
  88. IN DWORD ReturnBufferSize,
  89. OUT PDWORD RequiredSize OPTIONAL
  90. )
  91. {
  92. UNREFERENCED_PARAMETER(InfSpec);
  93. UNREFERENCED_PARAMETER(SearchControl);
  94. UNREFERENCED_PARAMETER(ReturnBuffer);
  95. UNREFERENCED_PARAMETER(ReturnBufferSize);
  96. UNREFERENCED_PARAMETER(RequiredSize);
  97. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  98. return(FALSE);
  99. }
  100. #endif
  101. BOOL
  102. SetupGetInfInformation(
  103. IN LPCVOID InfSpec,
  104. IN DWORD SearchControl,
  105. OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
  106. IN DWORD ReturnBufferSize,
  107. OUT PDWORD RequiredSize OPTIONAL
  108. )
  109. /*++
  110. Routine Description:
  111. Arguments:
  112. Return Value:
  113. --*/
  114. {
  115. BOOL UnloadInf;
  116. PLOADED_INF Inf, CurInf;
  117. UINT InfCount;
  118. PUCHAR Out;
  119. DWORD TotalSpaceRequired;
  120. DWORD d;
  121. DWORD ErrorLineNumber;
  122. TCHAR Path[MAX_PATH];
  123. PINF_VERSION_NODE VersionNode;
  124. INF_VERSION_BLOCK UNALIGNED *Prev;
  125. BOOL TryPnf;
  126. WIN32_FIND_DATA FindData;
  127. PTSTR DontCare;
  128. UINT OriginalFilenameSize;
  129. //
  130. // Set up some state based on the SearchSpec parameter.
  131. //
  132. Inf = NULL;
  133. switch(SearchControl) {
  134. case INFINFO_INF_SPEC_IS_HINF:
  135. Inf = (PLOADED_INF)InfSpec;
  136. d = NO_ERROR;
  137. try {
  138. if (!LockInf(Inf)) {
  139. d = ERROR_INVALID_HANDLE;
  140. }
  141. } except(EXCEPTION_EXECUTE_HANDLER) {
  142. d = ERROR_INVALID_HANDLE;
  143. }
  144. if (d != NO_ERROR) {
  145. SetLastError(d);
  146. return FALSE;
  147. }
  148. break;
  149. case INFINFO_INF_NAME_IS_ABSOLUTE:
  150. //
  151. // Make sure we have a fully-qualified path.
  152. //
  153. d = GetFullPathName((PCTSTR)InfSpec,
  154. SIZECHARS(Path),
  155. Path,
  156. &DontCare
  157. );
  158. if(!d) {
  159. //
  160. // LastError has already been set
  161. // (unless InfSpec was NULL or "")
  162. //
  163. if (GetLastError()==NO_ERROR) {
  164. SetLastError(ERROR_FILE_NOT_FOUND);
  165. }
  166. return FALSE;
  167. } else if(d >= SIZECHARS(Path)) {
  168. MYASSERT(0);
  169. SetLastError(ERROR_BUFFER_OVERFLOW);
  170. return FALSE;
  171. }
  172. if(FileExists(Path, &FindData)) {
  173. InfSourcePathFromFileName(Path, NULL, &TryPnf);
  174. break;
  175. } else {
  176. //
  177. // LastError has already been set.
  178. //
  179. return FALSE;
  180. }
  181. case INFINFO_DEFAULT_SEARCH:
  182. case INFINFO_REVERSE_DEFAULT_SEARCH:
  183. case INFINFO_INF_PATH_LIST_SEARCH:
  184. try {
  185. d = SearchForInfFile((PCTSTR)InfSpec,
  186. &FindData,
  187. SearchControl,
  188. Path,
  189. SIZECHARS(Path),
  190. NULL
  191. );
  192. } except(EXCEPTION_EXECUTE_HANDLER) {
  193. d = ERROR_INVALID_PARAMETER;
  194. }
  195. if(d == NO_ERROR) {
  196. TryPnf = TRUE;
  197. break;
  198. } else {
  199. SetLastError(d);
  200. return FALSE;
  201. }
  202. default:
  203. SetLastError(ERROR_INVALID_PARAMETER);
  204. return(FALSE);
  205. }
  206. //
  207. // Load the inf if necessary.
  208. //
  209. if(Inf) {
  210. UnloadInf = FALSE;
  211. } else {
  212. d = LoadInfFile(Path,
  213. &FindData,
  214. INF_STYLE_ALL,
  215. TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
  216. NULL,
  217. NULL,
  218. NULL,
  219. NULL,
  220. NULL, // LogContext
  221. &Inf,
  222. &ErrorLineNumber,
  223. NULL
  224. );
  225. if(d != NO_ERROR) {
  226. SetLastError(d);
  227. return(FALSE);
  228. }
  229. UnloadInf = TRUE;
  230. }
  231. //
  232. // Determine the number of infs associated with this handle,
  233. // and calculate the amount of space that will be needed to
  234. // store version information about them.
  235. //
  236. // For each inf we will need space for the version block,
  237. // as well as an offset in the SP_INF_INFORMATION structure
  238. // to indicate where that inf's version block is located
  239. // in the output buffer.
  240. //
  241. TotalSpaceRequired = offsetof(SP_INF_INFORMATION, VersionData);
  242. for(InfCount = 0, CurInf = Inf;
  243. CurInf;
  244. InfCount++, CurInf = CurInf->Next)
  245. {
  246. OriginalFilenameSize = CurInf->OriginalInfName
  247. ? (lstrlen(CurInf->OriginalInfName) + 1) * sizeof(TCHAR)
  248. : 0;
  249. TotalSpaceRequired += (offsetof(INF_VERSION_BLOCK, Filename) +
  250. CurInf->VersionBlock.FilenameSize +
  251. CurInf->VersionBlock.DataSize +
  252. OriginalFilenameSize
  253. );
  254. }
  255. if(RequiredSize) {
  256. *RequiredSize = TotalSpaceRequired;
  257. }
  258. //
  259. // See if we have a large enough output buffer.
  260. // If we have a large enough buffer then set up some
  261. // initial values in it.
  262. //
  263. if(ReturnBufferSize < TotalSpaceRequired) {
  264. if(UnloadInf) {
  265. FreeInfFile(Inf);
  266. } else {
  267. UnlockInf(Inf);
  268. }
  269. if(ReturnBuffer) {
  270. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  271. return FALSE;
  272. } else {
  273. return TRUE;
  274. }
  275. }
  276. d = NO_ERROR;
  277. try {
  278. ReturnBuffer->InfStyle = Inf->Style;
  279. ReturnBuffer->InfCount = InfCount;
  280. } except(EXCEPTION_EXECUTE_HANDLER) {
  281. if(UnloadInf) {
  282. FreeInfFile(Inf);
  283. } else {
  284. UnlockInf(Inf);
  285. }
  286. SetLastError(d = ERROR_INVALID_PARAMETER);
  287. }
  288. if(d != NO_ERROR) {
  289. return FALSE;
  290. }
  291. Out = (PUCHAR)ReturnBuffer + offsetof(SP_INF_INFORMATION, VersionData);
  292. //
  293. // Traverse all infs associated with this inf handle and copy
  294. // version data into the caller's buffer. Guard with SEH to ensure
  295. // that the caller passed a valid buffer.
  296. //
  297. try {
  298. Prev = NULL;
  299. for(CurInf = Inf; CurInf; CurInf = CurInf->Next) {
  300. //
  301. // Store offset into
  302. //
  303. if(Prev) {
  304. Prev->NextOffset = (UINT)((UINT_PTR)Out - (UINT_PTR)ReturnBuffer);
  305. }
  306. Prev = (PVOID)Out;
  307. OriginalFilenameSize = CurInf->OriginalInfName
  308. ? (lstrlen(CurInf->OriginalInfName) + 1) * sizeof(TCHAR)
  309. : 0;
  310. Prev->LastWriteTime = CurInf->VersionBlock.LastWriteTime;
  311. Prev->DatumCount = CurInf->VersionBlock.DatumCount;
  312. Prev->OffsetToData = CurInf->VersionBlock.FilenameSize + OriginalFilenameSize;
  313. Prev->DataSize = CurInf->VersionBlock.DataSize;
  314. Prev->TotalSize = offsetof(INF_VERSION_BLOCK, Filename) +
  315. CurInf->VersionBlock.FilenameSize +
  316. OriginalFilenameSize +
  317. CurInf->VersionBlock.DataSize;
  318. Out += offsetof(INF_VERSION_BLOCK, Filename);
  319. //
  320. // Now copy the filename, (optionally) original filename, and
  321. // version data into the output buffer.
  322. //
  323. CopyMemory(Out, CurInf->VersionBlock.Filename, CurInf->VersionBlock.FilenameSize);
  324. Out += CurInf->VersionBlock.FilenameSize;
  325. if(CurInf->OriginalInfName) {
  326. CopyMemory(Out, CurInf->OriginalInfName, OriginalFilenameSize);
  327. Out += OriginalFilenameSize;
  328. }
  329. CopyMemory(Out, CurInf->VersionBlock.DataBlock, CurInf->VersionBlock.DataSize);
  330. Out += CurInf->VersionBlock.DataSize;
  331. }
  332. } except(EXCEPTION_EXECUTE_HANDLER) {
  333. if(UnloadInf) {
  334. FreeInfFile(Inf);
  335. } else {
  336. UnlockInf(Inf);
  337. }
  338. SetLastError(d = ERROR_INVALID_PARAMETER);
  339. }
  340. if(d != NO_ERROR) {
  341. return FALSE;
  342. }
  343. Prev->NextOffset = 0;
  344. //
  345. // Unload the inf if necessary
  346. //
  347. if(UnloadInf) {
  348. FreeInfFile(Inf);
  349. } else {
  350. UnlockInf(Inf);
  351. }
  352. return TRUE;
  353. }
  354. #ifdef UNICODE
  355. //
  356. // ANSI version
  357. //
  358. BOOL
  359. SetupQueryInfFileInformationA(
  360. IN PSP_INF_INFORMATION InfInformation,
  361. IN UINT InfIndex,
  362. OUT PSTR ReturnBuffer, OPTIONAL
  363. IN DWORD ReturnBufferSize,
  364. OUT PDWORD RequiredSize OPTIONAL
  365. )
  366. {
  367. WCHAR returnbuffer[MAX_PATH];
  368. DWORD requiredsize;
  369. DWORD rc;
  370. PSTR ansi;
  371. BOOL b;
  372. b = SetupQueryInfFileInformationW(
  373. InfInformation,
  374. InfIndex,
  375. returnbuffer,
  376. MAX_PATH,
  377. &requiredsize
  378. );
  379. rc = GetLastError();
  380. if(b) {
  381. if(ansi = pSetupUnicodeToAnsi(returnbuffer)) {
  382. rc = NO_ERROR;
  383. requiredsize = lstrlenA(ansi)+1;
  384. if(RequiredSize) {
  385. try {
  386. *RequiredSize = requiredsize;
  387. } except(EXCEPTION_EXECUTE_HANDLER) {
  388. rc = ERROR_INVALID_PARAMETER;
  389. b = FALSE;
  390. }
  391. }
  392. if(b) {
  393. if(ReturnBuffer) {
  394. if(ReturnBufferSize >= requiredsize) {
  395. //
  396. // lstrcpy returns NULL if it faults
  397. //
  398. if(!lstrcpyA(ReturnBuffer,ansi)) {
  399. rc = ERROR_INVALID_PARAMETER;
  400. b = FALSE;
  401. }
  402. } else {
  403. b = FALSE;
  404. rc = ERROR_INSUFFICIENT_BUFFER;
  405. }
  406. }
  407. }
  408. MyFree(ansi);
  409. } else {
  410. rc = ERROR_NOT_ENOUGH_MEMORY;
  411. b = FALSE;
  412. }
  413. }
  414. SetLastError(rc);
  415. return(b);
  416. }
  417. #else
  418. //
  419. // Unicode stub
  420. //
  421. BOOL
  422. SetupQueryInfFileInformationW(
  423. IN PSP_INF_INFORMATION InfInformation,
  424. IN UINT InfIndex,
  425. OUT PWSTR ReturnBuffer, OPTIONAL
  426. IN DWORD ReturnBufferSize,
  427. OUT PDWORD RequiredSize OPTIONAL
  428. )
  429. {
  430. UNREFERENCED_PARAMETER(InfInformation);
  431. UNREFERENCED_PARAMETER(InfIndex);
  432. UNREFERENCED_PARAMETER(ReturnBuffer);
  433. UNREFERENCED_PARAMETER(ReturnBufferSize);
  434. UNREFERENCED_PARAMETER(RequiredSize);
  435. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  436. return(FALSE);
  437. }
  438. #endif
  439. BOOL
  440. SetupQueryInfFileInformation(
  441. IN PSP_INF_INFORMATION InfInformation,
  442. IN UINT InfIndex,
  443. OUT PTSTR ReturnBuffer, OPTIONAL
  444. IN DWORD ReturnBufferSize,
  445. OUT PDWORD RequiredSize OPTIONAL
  446. )
  447. /*++
  448. Routine Description:
  449. Arguments:
  450. Return Value:
  451. --*/
  452. {
  453. UINT FilenameLength;
  454. INF_VERSION_NODE VersionNode;
  455. DWORD rc;
  456. //
  457. // See whether the index is in range and
  458. // retrieve the version descriptor for this inf.
  459. //
  460. rc = NO_ERROR;
  461. try {
  462. if(!pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode,NULL)) {
  463. rc = ERROR_INVALID_PARAMETER;
  464. }
  465. } except(EXCEPTION_EXECUTE_HANDLER) {
  466. rc = ERROR_INVALID_PARAMETER;
  467. }
  468. if(rc != NO_ERROR) {
  469. SetLastError(rc);
  470. return(FALSE);
  471. }
  472. FilenameLength = VersionNode.FilenameSize / sizeof(TCHAR);
  473. if(RequiredSize) {
  474. try {
  475. *RequiredSize = FilenameLength;
  476. } except(EXCEPTION_EXECUTE_HANDLER) {
  477. rc = ERROR_INVALID_PARAMETER;
  478. }
  479. if(rc != NO_ERROR) {
  480. SetLastError(rc);
  481. return(FALSE);
  482. }
  483. }
  484. //
  485. // Check length of user's buffer.
  486. //
  487. if(FilenameLength > ReturnBufferSize) {
  488. if(ReturnBuffer) {
  489. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  490. return FALSE;
  491. } else {
  492. return TRUE;
  493. }
  494. }
  495. //
  496. // Copy the data into user's buffer.
  497. //
  498. try {
  499. CopyMemory(ReturnBuffer,VersionNode.Filename,VersionNode.FilenameSize);
  500. } except(EXCEPTION_EXECUTE_HANDLER) {
  501. rc = ERROR_INVALID_PARAMETER;
  502. }
  503. if(rc != NO_ERROR) {
  504. SetLastError(rc);
  505. return(FALSE);
  506. }
  507. return TRUE;
  508. }
  509. #ifdef UNICODE
  510. //
  511. // ANSI version
  512. //
  513. BOOL
  514. WINAPI
  515. SetupQueryInfOriginalFileInformationA(
  516. IN PSP_INF_INFORMATION InfInformation,
  517. IN UINT InfIndex,
  518. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  519. OUT PSP_ORIGINAL_FILE_INFO_A OriginalFileInfo
  520. )
  521. {
  522. SP_ORIGINAL_FILE_INFO_W UnicodeOriginalFileInfo;
  523. DWORD rc;
  524. int i;
  525. BOOL b;
  526. rc = NO_ERROR;
  527. //
  528. // Do an initial check on user-supplied output buffer to see if it seems
  529. // to be valid.
  530. //
  531. try {
  532. if(OriginalFileInfo->cbSize != sizeof(SP_ORIGINAL_FILE_INFO_A)) {
  533. rc = ERROR_INVALID_USER_BUFFER;
  534. }
  535. } except(EXCEPTION_EXECUTE_HANDLER) {
  536. rc = ERROR_INVALID_PARAMETER;
  537. }
  538. if(rc != NO_ERROR) {
  539. SetLastError(rc);
  540. return FALSE;
  541. }
  542. UnicodeOriginalFileInfo.cbSize = sizeof(SP_ORIGINAL_FILE_INFO_W);
  543. b = SetupQueryInfOriginalFileInformationW(
  544. InfInformation,
  545. InfIndex,
  546. AlternatePlatformInfo,
  547. &UnicodeOriginalFileInfo
  548. );
  549. rc = GetLastError();
  550. if(b) {
  551. //
  552. // Convert the Unicode fields of the original file info structure into
  553. // ANSI, and store the information in the caller-supplied ANSI
  554. // structure.
  555. //
  556. try {
  557. //
  558. // First, translate/store the original INF name...
  559. //
  560. i = WideCharToMultiByte(
  561. CP_ACP,
  562. 0,
  563. UnicodeOriginalFileInfo.OriginalInfName,
  564. -1,
  565. OriginalFileInfo->OriginalInfName,
  566. SIZECHARS(OriginalFileInfo->OriginalInfName),
  567. NULL,
  568. NULL
  569. );
  570. //
  571. // ...and if that succeeded, then translate/store the original
  572. // catalog filename.
  573. //
  574. if(i) {
  575. //
  576. // Note that the original catalog filename may be the empty
  577. // string (i.e., the INF didn't specify an associated catalog
  578. // file). We don't need to special-case this, since
  579. // WideCharToMultiByte can handle empty strings just fine.
  580. //
  581. i = WideCharToMultiByte(
  582. CP_ACP,
  583. 0,
  584. UnicodeOriginalFileInfo.OriginalCatalogName,
  585. -1,
  586. OriginalFileInfo->OriginalCatalogName,
  587. SIZECHARS(OriginalFileInfo->OriginalCatalogName),
  588. NULL,
  589. NULL
  590. );
  591. }
  592. if(!i) {
  593. b = FALSE;
  594. rc = GetLastError();
  595. //
  596. // If we start seeing cases where our Unicode->ANSI expansion
  597. // blows our buffersize, we need to know about it...
  598. //
  599. MYASSERT((rc != NO_ERROR) && (rc != ERROR_INSUFFICIENT_BUFFER));
  600. }
  601. } except(EXCEPTION_EXECUTE_HANDLER) {
  602. rc = ERROR_INVALID_PARAMETER;
  603. b = FALSE;
  604. }
  605. }
  606. SetLastError(rc);
  607. return b;
  608. }
  609. #else
  610. //
  611. // Unicode stub
  612. //
  613. BOOL
  614. WINAPI
  615. SetupQueryInfOriginalFileInformationW(
  616. IN PSP_INF_INFORMATION InfInformation,
  617. IN UINT InfIndex,
  618. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  619. OUT PSP_ORIGINAL_FILE_INFO_W OriginalFileInfo
  620. )
  621. {
  622. UNREFERENCED_PARAMETER(InfInformation);
  623. UNREFERENCED_PARAMETER(InfIndex);
  624. UNREFERENCED_PARAMETER(AlternatePlatformInfo);
  625. UNREFERENCED_PARAMETER(OriginalFileInfo);
  626. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  627. return(FALSE);
  628. }
  629. #endif
  630. BOOL
  631. WINAPI
  632. SetupQueryInfOriginalFileInformation(
  633. IN PSP_INF_INFORMATION InfInformation,
  634. IN UINT InfIndex,
  635. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  636. OUT PSP_ORIGINAL_FILE_INFO OriginalFileInfo
  637. )
  638. /*++
  639. Routine Description:
  640. This routine returns an INF's original name (which will be different from
  641. its current name if the INF was installed into %windir%\Inf, for example).
  642. If the INF's original name is the same as its current name, the current
  643. name is returned.
  644. It also returns the original filename of the catalog file specified by the
  645. INF via a (potentially decorated) CatalogFile= entry in the INF's [version]
  646. section. The OS/architecture-specific decoration may be overridden from
  647. the default (i.e., current platform) by passing in an optional alternate
  648. platform information structure. If the INF doesn't specify any catalog
  649. file, then this field in the output OriginalFileInfo structure will be set
  650. to an empty string.
  651. Both filenames returned in the OriginalFileInfo are simple filenames, i.e.,
  652. there is no path information included.
  653. Arguments:
  654. InfInformation - supplies context from which we retrieve information about
  655. the INF whose index is specified by InfIndex.
  656. InfIndex - supplies the zero-based index of the INF within the
  657. InfInformation context buffer that we're retrieving original file
  658. information for.
  659. AlternatePlatformInfo - optionally, supplies alternate platform information
  660. used when searching for the appropriately decorated CatalogFile= entry
  661. within the INF's [version] section.
  662. (NOTE: caller may actually pass in a V1 struct instead--we detect this
  663. case and convert the V1 struct into a V2 one.)
  664. OriginalFileInfo - supplies the address of an original file information
  665. buffer that upon success receives information about the original
  666. (simple) filenames of files associated with this INF. This structure
  667. must have its cbSize field set to sizeof(SP_ORIGINAL_FILE_INFO) upon
  668. entry to this routine or the call will fail with GetLastError()
  669. returning ERROR_INVALID_USER_BUFFER.
  670. The fields of this structure are set upon successful return as follows:
  671. OriginalInfName - receives the INF's original filename, which may be
  672. different than its current filename in the case where the INF was
  673. an OEM in that was installed into the %windir%\Inf directory (e.g.,
  674. via SetupCopyOEMInf).
  675. OriginalCatalogName - receives the platform-appropriate CatalogFile=
  676. entry in the INF's [version] section (where the platform is the
  677. default native one unless AlternatePlatformInfo is supplied). If
  678. there is no applicable CatalogFile= entry, this field will be set
  679. to the empty string.
  680. Return Value:
  681. If successful, the return value is non-zero.
  682. If unsuccessful, the return value is FALSE, and GetLastError() may be
  683. called to determine the cause of failure.
  684. --*/
  685. {
  686. INF_VERSION_NODE VersionNode;
  687. DWORD rc;
  688. SP_ALTPLATFORM_INFO_V2 AltPlatformInfoV2;
  689. rc = NO_ERROR;
  690. //
  691. // See whether the index is in range and retrieve the version descriptor
  692. // and original filename for this inf.
  693. //
  694. try {
  695. //
  696. // Do an initial check on user-supplied output buffer to see if it
  697. // seems to be valid.
  698. //
  699. if(OriginalFileInfo->cbSize != sizeof(SP_ORIGINAL_FILE_INFO)) {
  700. rc = ERROR_INVALID_USER_BUFFER;
  701. goto clean0;
  702. }
  703. //
  704. // Now validate the AlternatePlatformInfo parameter.
  705. //
  706. if(AlternatePlatformInfo) {
  707. if(AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V2)) {
  708. //
  709. // The caller may have passed us in a Version 1 struct, or they
  710. // may have passed us in bad data...
  711. //
  712. if(AlternatePlatformInfo->cbSize == sizeof(SP_ALTPLATFORM_INFO_V1)) {
  713. //
  714. // Flags/Reserved field is reserved in V1
  715. //
  716. if(AlternatePlatformInfo->Reserved) {
  717. rc = ERROR_INVALID_PARAMETER;
  718. goto clean0;
  719. }
  720. //
  721. // Convert the caller-supplied data into Version 2 format.
  722. //
  723. ZeroMemory(&AltPlatformInfoV2, sizeof(AltPlatformInfoV2));
  724. AltPlatformInfoV2.cbSize = sizeof(SP_ALTPLATFORM_INFO_V2);
  725. AltPlatformInfoV2.Platform = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->Platform;
  726. AltPlatformInfoV2.MajorVersion = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->MajorVersion;
  727. AltPlatformInfoV2.MinorVersion = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->MinorVersion;
  728. AltPlatformInfoV2.ProcessorArchitecture = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->ProcessorArchitecture;
  729. AltPlatformInfoV2.Flags = 0;
  730. AlternatePlatformInfo = &AltPlatformInfoV2;
  731. } else {
  732. rc = ERROR_INVALID_USER_BUFFER;
  733. goto clean0;
  734. }
  735. }
  736. //
  737. // Gotta be either Windows or Windows NT
  738. //
  739. if((AlternatePlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS) &&
  740. (AlternatePlatformInfo->Platform != VER_PLATFORM_WIN32_NT)) {
  741. rc = ERROR_INVALID_PARAMETER;
  742. goto clean0;
  743. }
  744. //
  745. // Processor had better be either i386, amd64, or ia64
  746. //
  747. if((AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) &&
  748. (AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) &&
  749. (AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64)) {
  750. rc = ERROR_INVALID_PARAMETER;
  751. goto clean0;
  752. }
  753. //
  754. // MajorVersion field must be non-zero (MinorVersion field can be
  755. // anything)
  756. //
  757. if(!AlternatePlatformInfo->MajorVersion) {
  758. rc = ERROR_INVALID_PARAMETER;
  759. goto clean0;
  760. }
  761. //
  762. // Validate structure parameter flags (bits indicating what
  763. // parts of the structure are valid).
  764. //
  765. if((AlternatePlatformInfo->Flags & ~ (SP_ALTPLATFORM_FLAGS_VERSION_RANGE)) != 0) {
  766. rc = ERROR_INVALID_PARAMETER;
  767. goto clean0;
  768. }
  769. //
  770. // fill in version validation range if none supplied by caller
  771. //
  772. if((AlternatePlatformInfo->Flags & SP_ALTPLATFORM_FLAGS_VERSION_RANGE) == 0) {
  773. //
  774. // If caller does not know about FirstValidate*Version,
  775. // version upper and lower bounds are equal.
  776. //
  777. AlternatePlatformInfo->FirstValidatedMajorVersion = AlternatePlatformInfo->MajorVersion;
  778. AlternatePlatformInfo->FirstValidatedMinorVersion = AlternatePlatformInfo->MinorVersion;
  779. AlternatePlatformInfo->Flags |= SP_ALTPLATFORM_FLAGS_VERSION_RANGE;
  780. }
  781. }
  782. //
  783. // OK, now retrieve the INF's original filename...
  784. //
  785. if(!pSetupVersionNodeFromInfInformation(InfInformation,
  786. InfIndex,
  787. &VersionNode,
  788. OriginalFileInfo->OriginalInfName)) {
  789. rc = ERROR_INVALID_PARAMETER;
  790. goto clean0;
  791. }
  792. //
  793. // ...and retrieve the (platform-appropriate) catalog file associated
  794. // with this INF (if there is one).
  795. //
  796. if(!pSetupGetCatalogFileValue(&VersionNode,
  797. OriginalFileInfo->OriginalCatalogName,
  798. SIZECHARS(OriginalFileInfo->OriginalCatalogName),
  799. AlternatePlatformInfo)) {
  800. //
  801. // No applicable CatalogFile= entry found--set field to empty
  802. // string.
  803. //
  804. *(OriginalFileInfo->OriginalCatalogName) = TEXT('\0');
  805. }
  806. clean0: ; // nothing to do
  807. } except(EXCEPTION_EXECUTE_HANDLER) {
  808. rc = ERROR_INVALID_PARAMETER;
  809. }
  810. SetLastError(rc);
  811. return (rc == NO_ERROR);
  812. }
  813. #ifdef UNICODE
  814. //
  815. // ANSI version
  816. //
  817. BOOL
  818. SetupQueryInfVersionInformationA(
  819. IN PSP_INF_INFORMATION InfInformation,
  820. IN UINT InfIndex,
  821. IN PCSTR Key, OPTIONAL
  822. OUT PSTR ReturnBuffer, OPTIONAL
  823. IN DWORD ReturnBufferSize,
  824. OUT PDWORD RequiredSize OPTIONAL
  825. )
  826. {
  827. INF_VERSION_NODE VersionNode;
  828. PCWSTR Data;
  829. DWORD rc;
  830. PSTR ansidata;
  831. UINT ansilength;
  832. PCWSTR key;
  833. //
  834. // See whether the index is in range and
  835. // get pointer to version descriptor for this inf.
  836. //
  837. try {
  838. if(pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode,NULL)) {
  839. //
  840. // See whether we want a specific value.
  841. //
  842. if(Key) {
  843. rc = pSetupCaptureAndConvertAnsiArg(Key,&key);
  844. if(rc == NO_ERROR) {
  845. if(Data = pSetupGetVersionDatum(&VersionNode,key)) {
  846. if(ansidata = pSetupUnicodeToAnsi(Data)) {
  847. ansilength = lstrlenA(ansidata) + 1;
  848. if(RequiredSize) {
  849. *RequiredSize = ansilength;
  850. }
  851. if(ReturnBuffer) {
  852. if(ReturnBufferSize >= ansilength) {
  853. CopyMemory(ReturnBuffer,ansidata,ansilength);
  854. rc = NO_ERROR;
  855. } else {
  856. rc = ERROR_INSUFFICIENT_BUFFER;
  857. }
  858. } else {
  859. rc = NO_ERROR;
  860. }
  861. MyFree(ansidata);
  862. } else {
  863. rc = ERROR_NOT_ENOUGH_MEMORY;
  864. }
  865. } else {
  866. rc = ERROR_INVALID_DATA;
  867. }
  868. MyFree(key);
  869. }
  870. } else {
  871. //
  872. // Caller wants all values. Copy whole data block to caller's buffer,
  873. // plus a terminating NUL character.
  874. //
  875. // Maximum size the data could be in ansi is the exact same
  876. // size it is in unicode, if every char is a double-byte char.
  877. //
  878. if(ansidata = MyMalloc(VersionNode.DataSize)) {
  879. ansilength = WideCharToMultiByte(
  880. CP_ACP,
  881. 0,
  882. (PWSTR)VersionNode.DataBlock,
  883. VersionNode.DataSize / sizeof(WCHAR),
  884. ansidata,
  885. VersionNode.DataSize,
  886. NULL,
  887. NULL
  888. );
  889. if(RequiredSize) {
  890. //
  891. // account for terminating nul
  892. //
  893. *RequiredSize = ansilength+1;
  894. }
  895. if(ReturnBuffer) {
  896. if(ReturnBufferSize >= *RequiredSize) {
  897. CopyMemory(ReturnBuffer,ansidata,ansilength);
  898. ReturnBuffer[ansilength] = 0;
  899. rc = NO_ERROR;
  900. } else {
  901. rc = ERROR_INSUFFICIENT_BUFFER;
  902. }
  903. } else {
  904. rc = NO_ERROR;
  905. }
  906. MyFree(ansidata);
  907. } else {
  908. rc = ERROR_NOT_ENOUGH_MEMORY;
  909. }
  910. }
  911. } else {
  912. rc = ERROR_INVALID_PARAMETER;
  913. }
  914. } except(EXCEPTION_EXECUTE_HANDLER) {
  915. rc = ERROR_INVALID_PARAMETER;
  916. }
  917. SetLastError(rc);
  918. return(rc == NO_ERROR);
  919. }
  920. #else
  921. //
  922. // Unicode stub
  923. //
  924. BOOL
  925. SetupQueryInfVersionInformationW(
  926. IN PSP_INF_INFORMATION InfInformation,
  927. IN UINT InfIndex,
  928. IN PCWSTR Key, OPTIONAL
  929. OUT PWSTR ReturnBuffer, OPTIONAL
  930. IN DWORD ReturnBufferSize,
  931. OUT PDWORD RequiredSize OPTIONAL
  932. )
  933. {
  934. UNREFERENCED_PARAMETER(InfInformation);
  935. UNREFERENCED_PARAMETER(InfIndex);
  936. UNREFERENCED_PARAMETER(Key);
  937. UNREFERENCED_PARAMETER(ReturnBuffer);
  938. UNREFERENCED_PARAMETER(ReturnBufferSize);
  939. UNREFERENCED_PARAMETER(RequiredSize);
  940. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  941. return(FALSE);
  942. }
  943. #endif
  944. BOOL
  945. SetupQueryInfVersionInformation(
  946. IN PSP_INF_INFORMATION InfInformation,
  947. IN UINT InfIndex,
  948. IN PCTSTR Key, OPTIONAL
  949. OUT PTSTR ReturnBuffer, OPTIONAL
  950. IN DWORD ReturnBufferSize,
  951. OUT PDWORD RequiredSize OPTIONAL
  952. )
  953. /*++
  954. Routine Description:
  955. Arguments:
  956. Return Value:
  957. --*/
  958. {
  959. INF_VERSION_NODE VersionNode;
  960. PCTSTR Data;
  961. UINT DataLength;
  962. DWORD rc;
  963. //
  964. // See whether the index is in range and
  965. // get pointer to version descriptor for this inf.
  966. //
  967. try {
  968. if(pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode,NULL)) {
  969. //
  970. // See whether we want a specific value.
  971. //
  972. if(Key) {
  973. if(Data = pSetupGetVersionDatum(&VersionNode,Key)) {
  974. DataLength = lstrlen(Data) + 1;
  975. if(RequiredSize) {
  976. *RequiredSize = DataLength;
  977. }
  978. if(ReturnBuffer) {
  979. if(ReturnBufferSize >= DataLength) {
  980. CopyMemory(ReturnBuffer,Data,DataLength * sizeof(TCHAR));
  981. rc = NO_ERROR;
  982. } else {
  983. rc = ERROR_INSUFFICIENT_BUFFER;
  984. }
  985. } else {
  986. rc = NO_ERROR;
  987. }
  988. } else {
  989. rc = ERROR_INVALID_DATA;
  990. }
  991. } else {
  992. //
  993. // Caller wants all values. Copy whole data block to caller's buffer,
  994. // plus a terminating NUL character.
  995. //
  996. DataLength = (VersionNode.DataSize / sizeof(TCHAR)) + 1;
  997. if(RequiredSize) {
  998. *RequiredSize = DataLength;
  999. }
  1000. if(ReturnBuffer) {
  1001. if(ReturnBufferSize >= DataLength) {
  1002. CopyMemory(ReturnBuffer,VersionNode.DataBlock,VersionNode.DataSize);
  1003. ReturnBuffer[VersionNode.DataSize/sizeof(TCHAR)] = 0;
  1004. rc = NO_ERROR;
  1005. } else {
  1006. rc = ERROR_INSUFFICIENT_BUFFER;
  1007. }
  1008. } else {
  1009. rc = NO_ERROR;
  1010. }
  1011. }
  1012. } else {
  1013. rc = ERROR_INVALID_PARAMETER;
  1014. }
  1015. } except(EXCEPTION_EXECUTE_HANDLER) {
  1016. rc = ERROR_INVALID_PARAMETER;
  1017. }
  1018. SetLastError(rc);
  1019. return(rc == NO_ERROR);
  1020. }
  1021. BOOL
  1022. _SetupGetInfFileList(
  1023. IN PCTSTR DirectoryPath, OPTIONAL
  1024. IN DWORD InfStyle,
  1025. OUT PVOID ReturnBuffer, OPTIONAL
  1026. IN DWORD ReturnBufferSize,
  1027. OUT PDWORD RequiredSize OPTIONAL
  1028. #ifdef UNICODE
  1029. IN ,BOOL ConvertToAnsi
  1030. #endif
  1031. )
  1032. {
  1033. TCHAR SearchSpec[MAX_PATH];
  1034. PTCHAR FilenameStart;
  1035. WIN32_FIND_DATA FindData;
  1036. HANDLE FindHandle;
  1037. DWORD Style;
  1038. UINT FileNameLength;
  1039. DWORD RemainingSpaceInBuffer;
  1040. DWORD CurrentOffsetInBuffer;
  1041. DWORD TotalSpaceNeededInBuffer;
  1042. BOOL InsufficientBuffer;
  1043. DWORD d;
  1044. PTSTR DontCare;
  1045. #ifdef UNICODE
  1046. CHAR ansi[MAX_PATH];
  1047. #endif
  1048. //
  1049. // Set up the search directory
  1050. //
  1051. if(DirectoryPath) {
  1052. //
  1053. // Make sure this directory path is fully-qualified.
  1054. //
  1055. d = GetFullPathName(DirectoryPath,
  1056. SIZECHARS(SearchSpec),
  1057. SearchSpec,
  1058. &DontCare
  1059. );
  1060. if(!d) {
  1061. //
  1062. // LastError has already been set.
  1063. //
  1064. return FALSE;
  1065. } else if(d >= SIZECHARS(SearchSpec)) {
  1066. MYASSERT(0);
  1067. SetLastError(ERROR_BUFFER_OVERFLOW);
  1068. return FALSE;
  1069. }
  1070. } else {
  1071. lstrcpyn(SearchSpec, InfDirectory,SIZECHARS(SearchSpec));
  1072. }
  1073. pSetupConcatenatePaths(SearchSpec, pszInfWildcard, SIZECHARS(SearchSpec), NULL);
  1074. FilenameStart = (PTSTR)pSetupGetFileTitle(SearchSpec);
  1075. FindHandle = FindFirstFile(SearchSpec,&FindData);
  1076. if(FindHandle == INVALID_HANDLE_VALUE) {
  1077. d = GetLastError();
  1078. if((d == ERROR_NO_MORE_FILES) || (d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
  1079. if(RequiredSize) {
  1080. d = NO_ERROR;
  1081. try {
  1082. *RequiredSize = 1;
  1083. } except(EXCEPTION_EXECUTE_HANDLER) {
  1084. d = ERROR_INVALID_PARAMETER;
  1085. }
  1086. if(d != NO_ERROR) {
  1087. SetLastError(d);
  1088. return(FALSE);
  1089. }
  1090. }
  1091. if(ReturnBuffer) {
  1092. if(ReturnBufferSize) {
  1093. d = NO_ERROR;
  1094. try {
  1095. #ifdef UNICODE
  1096. if(ConvertToAnsi) {
  1097. *(PCHAR)ReturnBuffer = 0;
  1098. } else
  1099. #endif
  1100. *(PTCHAR)ReturnBuffer = 0;
  1101. } except(EXCEPTION_EXECUTE_HANDLER) {
  1102. d = ERROR_INVALID_PARAMETER;
  1103. }
  1104. SetLastError(d);
  1105. return(d == NO_ERROR);
  1106. } else {
  1107. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1108. return FALSE;
  1109. }
  1110. } else {
  1111. return TRUE;
  1112. }
  1113. }
  1114. SetLastError(d);
  1115. return(FALSE);
  1116. }
  1117. //
  1118. // Leave space for the extra terminating nul char.
  1119. //
  1120. RemainingSpaceInBuffer = ReturnBufferSize;
  1121. if(RemainingSpaceInBuffer) {
  1122. RemainingSpaceInBuffer--;
  1123. }
  1124. TotalSpaceNeededInBuffer = 1;
  1125. CurrentOffsetInBuffer = 0;
  1126. InsufficientBuffer = FALSE;
  1127. d = NO_ERROR;
  1128. do {
  1129. //
  1130. // Skip directories
  1131. //
  1132. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1133. continue;
  1134. }
  1135. //
  1136. // Form full pathname of file in SearchSpec.
  1137. //
  1138. lstrcpy(FilenameStart,FindData.cFileName);
  1139. //
  1140. // Determine the inf type and see whether the caller
  1141. // wants to know about infs of this type.
  1142. //
  1143. Style = DetermineInfStyle(SearchSpec, &FindData);
  1144. if((Style == INF_STYLE_NONE) || !(Style & InfStyle)) {
  1145. continue;
  1146. }
  1147. //
  1148. // Got a legit inf file.
  1149. //
  1150. #ifdef UNICODE
  1151. if(ConvertToAnsi) {
  1152. //
  1153. // The nul is included because it's converted
  1154. // so no need to add 1
  1155. //
  1156. FileNameLength = WideCharToMultiByte(
  1157. CP_ACP,
  1158. 0,
  1159. FindData.cFileName,
  1160. -1,
  1161. ansi,
  1162. MAX_PATH,
  1163. NULL,
  1164. NULL
  1165. );
  1166. } else
  1167. #endif
  1168. FileNameLength = lstrlen(FindData.cFileName) + 1;
  1169. TotalSpaceNeededInBuffer += FileNameLength;
  1170. if(ReturnBuffer) {
  1171. if(RemainingSpaceInBuffer >= FileNameLength ) {
  1172. RemainingSpaceInBuffer -= FileNameLength;
  1173. //
  1174. // lstrcpy will return NULL if it faults
  1175. //
  1176. #ifdef UNICODE
  1177. if(ConvertToAnsi) {
  1178. DontCare = (PVOID)lstrcpyA((PCHAR)ReturnBuffer+CurrentOffsetInBuffer,ansi);
  1179. } else
  1180. #endif
  1181. DontCare = lstrcpy((PTCHAR)ReturnBuffer+CurrentOffsetInBuffer,FindData.cFileName);
  1182. if(!DontCare) {
  1183. d = ERROR_INVALID_PARAMETER;
  1184. } else {
  1185. CurrentOffsetInBuffer += FileNameLength;
  1186. try {
  1187. #ifdef UNICODE
  1188. if(ConvertToAnsi) {
  1189. ((PCHAR)ReturnBuffer)[CurrentOffsetInBuffer] = 0;
  1190. } else
  1191. #endif
  1192. ((PTCHAR)ReturnBuffer)[CurrentOffsetInBuffer] = 0;
  1193. } except(EXCEPTION_EXECUTE_HANDLER) {
  1194. d = ERROR_INVALID_PARAMETER;
  1195. }
  1196. }
  1197. } else {
  1198. InsufficientBuffer = TRUE;
  1199. }
  1200. }
  1201. } while((d == NO_ERROR) && FindNextFile(FindHandle,&FindData));
  1202. FindClose(FindHandle);
  1203. if(d != NO_ERROR) {
  1204. SetLastError(d);
  1205. }
  1206. if(GetLastError() == ERROR_NO_MORE_FILES) {
  1207. d = NO_ERROR;
  1208. try {
  1209. if(RequiredSize) {
  1210. *RequiredSize = TotalSpaceNeededInBuffer;
  1211. }
  1212. } except(EXCEPTION_EXECUTE_HANDLER) {
  1213. d = ERROR_INVALID_PARAMETER;
  1214. }
  1215. if(d == NO_ERROR) {
  1216. if(InsufficientBuffer) {
  1217. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1218. return FALSE;
  1219. }
  1220. return(TRUE);
  1221. } else {
  1222. SetLastError(d);
  1223. }
  1224. }
  1225. //
  1226. // Last error already set
  1227. //
  1228. return(FALSE);
  1229. }
  1230. #ifdef UNICODE
  1231. //
  1232. // ANSI version
  1233. //
  1234. BOOL
  1235. SetupGetInfFileListA(
  1236. IN PCSTR DirectoryPath, OPTIONAL
  1237. IN DWORD InfStyle,
  1238. OUT PSTR ReturnBuffer, OPTIONAL
  1239. IN DWORD ReturnBufferSize,
  1240. OUT PDWORD RequiredSize OPTIONAL
  1241. )
  1242. {
  1243. PWSTR dirpath;
  1244. DWORD rc;
  1245. BOOL b;
  1246. if(DirectoryPath) {
  1247. rc = pSetupCaptureAndConvertAnsiArg(DirectoryPath,&dirpath);
  1248. if(rc != NO_ERROR) {
  1249. SetLastError(rc);
  1250. return(FALSE);
  1251. }
  1252. } else {
  1253. dirpath = NULL;
  1254. }
  1255. b = _SetupGetInfFileList(dirpath,InfStyle,ReturnBuffer,ReturnBufferSize,RequiredSize,TRUE);
  1256. rc = GetLastError();
  1257. if(dirpath) {
  1258. MyFree(dirpath);
  1259. }
  1260. SetLastError(rc);
  1261. return(b);
  1262. }
  1263. #else
  1264. //
  1265. // Unicode stub
  1266. //
  1267. BOOL
  1268. SetupGetInfFileListW(
  1269. IN PCWSTR DirectoryPath, OPTIONAL
  1270. IN DWORD InfStyle,
  1271. OUT PWSTR ReturnBuffer, OPTIONAL
  1272. IN DWORD ReturnBufferSize,
  1273. OUT PDWORD RequiredSize OPTIONAL
  1274. )
  1275. {
  1276. UNREFERENCED_PARAMETER(DirectoryPath);
  1277. UNREFERENCED_PARAMETER(InfStyle);
  1278. UNREFERENCED_PARAMETER(ReturnBuffer);
  1279. UNREFERENCED_PARAMETER(ReturnBufferSize);
  1280. UNREFERENCED_PARAMETER(RequiredSize);
  1281. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1282. return(FALSE);
  1283. }
  1284. #endif
  1285. BOOL
  1286. SetupGetInfFileList(
  1287. IN PCTSTR DirectoryPath, OPTIONAL
  1288. IN DWORD InfStyle,
  1289. OUT PTSTR ReturnBuffer, OPTIONAL
  1290. IN DWORD ReturnBufferSize,
  1291. OUT PDWORD RequiredSize OPTIONAL
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. Arguments:
  1296. Return Value:
  1297. --*/
  1298. {
  1299. PTSTR dirpath;
  1300. DWORD rc;
  1301. BOOL b;
  1302. if(DirectoryPath) {
  1303. rc = CaptureStringArg(DirectoryPath,&dirpath);
  1304. if(rc != NO_ERROR) {
  1305. SetLastError(rc);
  1306. return(FALSE);
  1307. }
  1308. } else {
  1309. dirpath = NULL;
  1310. }
  1311. b = _SetupGetInfFileList(
  1312. dirpath,
  1313. InfStyle,
  1314. ReturnBuffer,
  1315. ReturnBufferSize,
  1316. RequiredSize
  1317. #ifdef UNICODE
  1318. ,FALSE
  1319. #endif
  1320. );
  1321. rc = GetLastError();
  1322. if(dirpath) {
  1323. MyFree(dirpath);
  1324. }
  1325. SetLastError(rc);
  1326. return(b);
  1327. }
  1328. #ifdef UNICODE
  1329. //
  1330. // ANSI version
  1331. //
  1332. HINF
  1333. SetupOpenInfFileA(
  1334. IN PCSTR FileName,
  1335. IN PCSTR InfType, OPTIONAL
  1336. IN DWORD InfStyle,
  1337. OUT PUINT ErrorLine OPTIONAL
  1338. )
  1339. {
  1340. PCTSTR fileName,infType;
  1341. DWORD err;
  1342. HINF h;
  1343. err = NO_ERROR;
  1344. fileName = NULL;
  1345. infType = NULL;
  1346. //
  1347. // Set error line to 0 since ansi arg conversion could fail
  1348. // and we need to indicate that there's no error in the inf itself.
  1349. //
  1350. if(ErrorLine) {
  1351. try {
  1352. *ErrorLine = 0;
  1353. } except(EXCEPTION_EXECUTE_HANDLER) {
  1354. err = ERROR_INVALID_PARAMETER;
  1355. }
  1356. }
  1357. if(err == NO_ERROR) {
  1358. err = pSetupCaptureAndConvertAnsiArg(FileName,&fileName);
  1359. if((err == NO_ERROR) && InfType) {
  1360. err = pSetupCaptureAndConvertAnsiArg(InfType,&infType);
  1361. }
  1362. }
  1363. if(err == NO_ERROR) {
  1364. h = SetupOpenInfFileW(fileName,infType,InfStyle,ErrorLine);
  1365. err = GetLastError();
  1366. } else {
  1367. h = INVALID_HANDLE_VALUE;
  1368. }
  1369. if(fileName) {
  1370. MyFree(fileName);
  1371. }
  1372. if(infType) {
  1373. MyFree(infType);
  1374. }
  1375. SetLastError(err);
  1376. return(h);
  1377. }
  1378. #else
  1379. //
  1380. // Unicode stub
  1381. //
  1382. HINF
  1383. SetupOpenInfFileW(
  1384. IN PCWSTR FileName,
  1385. IN PCWSTR InfType, OPTIONAL
  1386. IN DWORD InfStyle,
  1387. OUT PUINT ErrorLine OPTIONAL
  1388. )
  1389. {
  1390. UNREFERENCED_PARAMETER(FileName);
  1391. UNREFERENCED_PARAMETER(InfType);
  1392. UNREFERENCED_PARAMETER(InfStyle);
  1393. UNREFERENCED_PARAMETER(ErrorLine);
  1394. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1395. return(INVALID_HANDLE_VALUE);
  1396. }
  1397. #endif
  1398. HINF
  1399. SetupOpenInfFile(
  1400. IN PCTSTR FileName,
  1401. IN PCTSTR InfClass, OPTIONAL
  1402. IN DWORD InfStyle,
  1403. OUT PUINT ErrorLine OPTIONAL
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. This routine opens an INF file and returns a handle to it.
  1408. Arguments:
  1409. FileName - Supplies the address of a NULL-terminated string containing
  1410. the name (and optionally, the path) of the INF file to be opened. If
  1411. the filename contains no path separator characters, it is searched for
  1412. first in the %windir%\inf directory, and then in the %windir%\system32
  1413. directory. Otherwise, the name is assumed to be a full path
  1414. specification, and no is opened as-is.
  1415. InfClass - Optionally, supplies the address of a NULL-terminated string
  1416. containing the class of the INF file desired. For old-style (i.e.,
  1417. Windows NT 3.x script-base) INF files, this string must match the type
  1418. specified in the OptionType value of the [Identification] section of the
  1419. INF (e.g., OptionType=NetAdapter). For Windows 95-compatibile INF
  1420. files, this string must match the class of the specified INF. If the
  1421. INF has a Class value in its [version] section, then this value is used
  1422. for the comparison. If no Class value is present, but a ClassGUID value
  1423. is present in the [version] section, then the corresponding class name
  1424. for that GUID is retrieved, and comparison is done based on that name.
  1425. InfStyle - Specifies the style of the INF to open. May be a combination of
  1426. the following flags:
  1427. INF_STYLE_OLDNT - Windows NT 3.x script-based INF files.
  1428. INF_STYLE_WIN4 - Windows 95-compatible INF files.
  1429. INF_STYLE_CACHE_ENABLE - always cache INF, even outside of
  1430. %windir%\Inf.
  1431. INF_STYLE_CACHE_DISABLE - delete INF from cache, if outside of
  1432. %windir%\Inf.
  1433. INF_STYLE_CACHE_IGNORE - access INF only, do not touch or look
  1434. at other files.
  1435. ErrorLine - If an error occurs loading the file, this parameter receives the
  1436. (1-based) line number where the error occurred. This value is generally
  1437. reliable only if GetLastError does not return ERROR_NOT_ENOUGH_MEMORY.
  1438. If out-of-memory does occur, the ErrorLine may be 0.
  1439. Return Value:
  1440. If the function succeeds, the return value is a handle to the opened INF
  1441. file.
  1442. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  1443. extended error information, call GetLastError.
  1444. Remarks:
  1445. If the load fails because the INF class does not match InfClass, the
  1446. function returns FALSE, and GetLastError returns ERROR_CLASS_MISMATCH.
  1447. The SetupCloseInfFile function is used to close a handle returned by
  1448. SetupOpenInfFile.
  1449. If multiple INF styles are specified, the style of the INF file opened may
  1450. be ascertained by calling SetupGetInfInformation.
  1451. Since there may be multiple class GUIDs all having the same class name,
  1452. callers interested in only INFs of a particular class (i.e., a particular
  1453. class GUID) should retrieve the ClassGuid value from the INF to verify that
  1454. the class matches exactly.
  1455. If both the INF_STYLE_CACHE_ENABLE and INF_STYLE_CACHE_DISABLE InfStyle
  1456. flags are specified, then the existing cached information that is maintained
  1457. about the INF (e.g., original source location) is discarded, and the INF is
  1458. re-added to the cache without this old information.
  1459. (Internal: Presently, the INF_STYLE_CACHE_ENABLE and
  1460. INF_STYLE_CACHE_DISABLE flags cause us to create or delete PNFs outside of
  1461. %windir%\Inf. Their rather vague-sounding names were chosen to reflect the
  1462. possibility of modifying the caching/indexing scheme in the future.)
  1463. --*/
  1464. {
  1465. UINT errorLine;
  1466. DWORD d;
  1467. PLOADED_INF Inf;
  1468. PCTSTR Class;
  1469. TCHAR TempString[MAX_PATH];
  1470. GUID ClassGuid;
  1471. HRESULT hr;
  1472. BOOL TryPnf = FALSE;
  1473. BOOL IgnorePnf = FALSE;
  1474. WIN32_FIND_DATA FindData;
  1475. PTSTR DontCare;
  1476. PTSTR TempCharPtr = NULL;
  1477. //
  1478. // Determine whether just the filename (no path) was specified. If so,
  1479. // look for it in the DevicePath directory search path. Otherwise,
  1480. // use the path as-is.
  1481. //
  1482. try {
  1483. if(FileName == pSetupGetFileTitle(FileName)) {
  1484. //
  1485. // The specified INF name is a simple filename. Search for it in
  1486. // the INF directories using the default search order.
  1487. //
  1488. d = SearchForInfFile(
  1489. FileName,
  1490. &FindData,
  1491. INFINFO_DEFAULT_SEARCH,
  1492. TempString,
  1493. SIZECHARS(TempString),
  1494. NULL
  1495. );
  1496. if(d == NO_ERROR) {
  1497. TryPnf = TRUE;
  1498. }
  1499. } else {
  1500. //
  1501. // The specified INF filename contains more than just a filename.
  1502. // Assume it's an absolute path. (We need to make sure it's
  1503. // fully-qualified, because that's what LoadInfFile expects.)
  1504. //
  1505. d = GetFullPathName(FileName,
  1506. SIZECHARS(TempString),
  1507. TempString,
  1508. &DontCare
  1509. );
  1510. if(!d) {
  1511. d = GetLastError();
  1512. } else if(d >= SIZECHARS(TempString)) {
  1513. MYASSERT(0);
  1514. d = ERROR_BUFFER_OVERFLOW;
  1515. } else {
  1516. //
  1517. // We successfully retrieved the full pathname, now see if the
  1518. // file exists.
  1519. //
  1520. if(FileExists(TempString, &FindData)) {
  1521. //
  1522. // We have everything we need to load this INF.
  1523. //
  1524. InfSourcePathFromFileName(TempString, &TempCharPtr, &TryPnf);
  1525. d = NO_ERROR;
  1526. } else {
  1527. d = GetLastError();
  1528. }
  1529. }
  1530. }
  1531. } except(EXCEPTION_EXECUTE_HANDLER) {
  1532. //
  1533. // Assume FileName was invalid and thus pSetupGetFileTitle fell over.
  1534. //
  1535. d = ERROR_INVALID_PARAMETER;
  1536. TempCharPtr = TempCharPtr;
  1537. }
  1538. if(d != NO_ERROR) {
  1539. goto PrepareForReturn;
  1540. }
  1541. if(InfStyle & INF_STYLE_CACHE_DISABLE) {
  1542. //
  1543. // Delete the existing PNF for this INF (if any).
  1544. //
  1545. TCHAR PnfFullPath[MAX_PATH];
  1546. PTSTR PnfFileName, PnfFileExt;
  1547. lstrcpy(PnfFullPath, TempString);
  1548. //
  1549. // Find the start of the filename component of the path, and then find
  1550. // the last period (if one exists) in that filename.
  1551. //
  1552. PnfFileName = (PTSTR)pSetupGetFileTitle(PnfFullPath);
  1553. if(!(PnfFileExt = _tcsrchr(PnfFileName, TEXT('.')))) {
  1554. PnfFileExt = PnfFullPath + lstrlen(PnfFullPath);
  1555. }
  1556. //
  1557. // Now create a corresponding filename with the extension '.PNF'
  1558. //
  1559. lstrcpyn(PnfFileExt, pszPnfSuffix, SIZECHARS(PnfFullPath) - (int)(PnfFileExt - PnfFullPath));
  1560. SetFileAttributes(PnfFullPath, FILE_ATTRIBUTE_NORMAL);
  1561. DeleteFile(PnfFullPath);
  1562. }
  1563. if(InfStyle & INF_STYLE_CACHE_ENABLE) {
  1564. //
  1565. // The caller has requested that this INF be cached (even though it may
  1566. // be outside of our INF search path).
  1567. //
  1568. TryPnf = TRUE;
  1569. }
  1570. if(InfStyle & INF_STYLE_CACHE_IGNORE) {
  1571. //
  1572. // The caller has requested that we don't trust the PNF
  1573. // overrides TryPnf
  1574. //
  1575. TryPnf = FALSE;
  1576. IgnorePnf = TRUE;
  1577. }
  1578. try {
  1579. d = LoadInfFile(
  1580. TempString,
  1581. &FindData,
  1582. InfStyle,
  1583. (TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0)
  1584. | (IgnorePnf ? LDINF_FLAG_ALWAYS_IGNORE_PNF : 0),
  1585. NULL,
  1586. TempCharPtr,
  1587. NULL,
  1588. NULL,
  1589. NULL, // LogContext
  1590. &Inf,
  1591. &errorLine,
  1592. NULL
  1593. );
  1594. } except(EXCEPTION_EXECUTE_HANDLER) {
  1595. d = ERROR_INVALID_PARAMETER;
  1596. }
  1597. if(d == NO_ERROR) {
  1598. if(InfClass) {
  1599. d = ERROR_CLASS_MISMATCH; // assume mismatch
  1600. //
  1601. // Match based on class of inf. The following check works for
  1602. // both new and old style infs, because old-style infs use
  1603. // [Identification].OptionType as the class (see oldinf.c
  1604. // function ProcessOldInfVersionBlock()).
  1605. //
  1606. if(Class = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClass)) {
  1607. try {
  1608. if(!lstrcmpi(Class,InfClass)) {
  1609. d = NO_ERROR;
  1610. }
  1611. } except(EXCEPTION_EXECUTE_HANDLER) {
  1612. d = ERROR_INVALID_PARAMETER;
  1613. }
  1614. } else {
  1615. //
  1616. // No Class entry--check for ClassGUID entry.
  1617. //
  1618. if(Class = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClassGuid)) {
  1619. //
  1620. // Get the class name associated with this GUID, and see if it
  1621. // matches the caller-supplied class name.
  1622. //
  1623. // (We have to cast away the CONST-ness of the Class string, because
  1624. // the prototype for CLSIDFromString doesn't specify this parameter
  1625. // as constant.)
  1626. //
  1627. if((hr = pSetupGuidFromString((PTSTR)Class, &ClassGuid)) == S_OK) {
  1628. if(SetupDiClassNameFromGuid(&ClassGuid,
  1629. TempString,
  1630. SIZECHARS(TempString),
  1631. NULL)) {
  1632. try {
  1633. if(!lstrcmpi(TempString,InfClass)) {
  1634. d = NO_ERROR;
  1635. }
  1636. } except(EXCEPTION_EXECUTE_HANDLER) {
  1637. d = ERROR_INVALID_PARAMETER;
  1638. }
  1639. }
  1640. } else {
  1641. if(hr == E_OUTOFMEMORY) {
  1642. d = ERROR_NOT_ENOUGH_MEMORY;
  1643. }
  1644. }
  1645. }
  1646. }
  1647. if(d != NO_ERROR) {
  1648. FreeInfFile(Inf);
  1649. }
  1650. }
  1651. } else {
  1652. if(ErrorLine) {
  1653. try {
  1654. *ErrorLine = errorLine;
  1655. } except(EXCEPTION_EXECUTE_HANDLER) {
  1656. d = ERROR_INVALID_PARAMETER;
  1657. }
  1658. }
  1659. }
  1660. PrepareForReturn:
  1661. if(TempCharPtr) {
  1662. MyFree(TempCharPtr);
  1663. }
  1664. SetLastError(d);
  1665. return((d == NO_ERROR) ? (HINF)Inf : (HINF)INVALID_HANDLE_VALUE);
  1666. }
  1667. HINF
  1668. SetupOpenMasterInf(
  1669. VOID
  1670. )
  1671. /*++
  1672. Routine Description:
  1673. Arguments:
  1674. Return Value:
  1675. --*/
  1676. {
  1677. TCHAR FileName[MAX_PATH];
  1678. lstrcpyn(FileName,InfDirectory,SIZECHARS(FileName)-11);
  1679. lstrcat(FileName,TEXT("\\LAYOUT.INF"));
  1680. return(SetupOpenInfFile(FileName,NULL,INF_STYLE_WIN4,NULL));
  1681. }
  1682. #ifdef UNICODE
  1683. //
  1684. // ANSI version
  1685. //
  1686. BOOL
  1687. SetupOpenAppendInfFileA(
  1688. IN PCSTR FileName, OPTIONAL
  1689. IN HINF InfHandle,
  1690. OUT PUINT ErrorLine OPTIONAL
  1691. )
  1692. {
  1693. PCWSTR fileName = NULL;
  1694. DWORD d;
  1695. BOOL b;
  1696. //
  1697. // Set error line to 0 since ansi arg conversion could fail
  1698. // and we need to indicate that there's no error in the inf itself.
  1699. //
  1700. d = NO_ERROR;
  1701. if(ErrorLine) {
  1702. try {
  1703. *ErrorLine = 0;
  1704. } except(EXCEPTION_EXECUTE_HANDLER) {
  1705. d = ERROR_INVALID_PARAMETER;
  1706. }
  1707. }
  1708. if(d == NO_ERROR) {
  1709. if(FileName) {
  1710. d = pSetupCaptureAndConvertAnsiArg(FileName,&fileName);
  1711. } else {
  1712. fileName = NULL;
  1713. }
  1714. }
  1715. if(d == NO_ERROR) {
  1716. b = SetupOpenAppendInfFileW(fileName,InfHandle,ErrorLine);
  1717. d = GetLastError();
  1718. } else {
  1719. b = FALSE;
  1720. }
  1721. if(fileName) {
  1722. MyFree(fileName);
  1723. }
  1724. SetLastError(d);
  1725. return(b);
  1726. }
  1727. #else
  1728. //
  1729. // Unicode stub
  1730. //
  1731. BOOL
  1732. SetupOpenAppendInfFileW(
  1733. IN PCWSTR FileName, OPTIONAL
  1734. IN HINF InfHandle,
  1735. OUT PUINT ErrorLine OPTIONAL
  1736. )
  1737. {
  1738. UNREFERENCED_PARAMETER(FileName);
  1739. UNREFERENCED_PARAMETER(InfHandle);
  1740. UNREFERENCED_PARAMETER(ErrorLine);
  1741. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1742. return(FALSE);
  1743. }
  1744. #endif
  1745. BOOL
  1746. SetupOpenAppendInfFile(
  1747. IN PCTSTR FileName, OPTIONAL
  1748. IN HINF InfHandle,
  1749. OUT PUINT ErrorLine OPTIONAL
  1750. )
  1751. /*++
  1752. Routine Description:
  1753. Arguments:
  1754. Return Value:
  1755. --*/
  1756. {
  1757. PLOADED_INF ExistingInf = NULL, CurInf = NULL;
  1758. DWORD d = NO_ERROR;
  1759. TCHAR Filename[2][MAX_PATH];
  1760. UINT FilenameCount, i, Field;
  1761. UINT errorLine = 0;
  1762. BOOL LookInInfDirAlso;
  1763. BOOL TryPnf;
  1764. WIN32_FIND_DATA FindData;
  1765. PTSTR TempCharPtr = NULL;
  1766. PTSTR DontCare;
  1767. PINF_SECTION InfSection;
  1768. UINT LineNumber;
  1769. PINF_LINE InfLine = NULL;
  1770. try {
  1771. if(LockInf((PLOADED_INF)InfHandle)) {
  1772. ExistingInf = (PLOADED_INF)InfHandle;
  1773. } else {
  1774. d = ERROR_INVALID_HANDLE;
  1775. goto clean0;
  1776. }
  1777. //
  1778. // Check INF Signature field as a further validation on the InfHandle.
  1779. //
  1780. if(ExistingInf->Signature != LOADED_INF_SIG) {
  1781. d = ERROR_INVALID_HANDLE;
  1782. goto clean0;
  1783. }
  1784. //
  1785. // Only allow this for win95-style infs.
  1786. //
  1787. if(ExistingInf->Style != INF_STYLE_WIN4) {
  1788. d = ERROR_INVALID_PARAMETER;
  1789. goto clean0;
  1790. }
  1791. //
  1792. // If there is no filename, search through the list of existing INFs, looking
  1793. // for a layout entry in their version blocks. We begin at the end of the list,
  1794. // and search backward, using the first layout file we encounter. This allows
  1795. // for the possibility of append-loading several INFs together (e.g., as done by the
  1796. // optional components dialog), and calling SetupOpenAppendInfFile with no filename
  1797. // for each. Each INF could specify its own layout file, and everything works great.
  1798. // (NOTE: In the above example, if all the INFs specified the same layout file, it
  1799. // would only get loaded once, as expected.)
  1800. //
  1801. // We also can now handle 'LayoutFile' entries that specify multiple layout files. E.g.,
  1802. //
  1803. // LayoutFile = pluslay.inf, layout.inf
  1804. //
  1805. // In the above example, we would append-load 'pluslay.inf', followed by 'layout.inf'.
  1806. // Because of the way we store INFs, any duplicate entries in both INFs would resolve in
  1807. // favor of pluslay.inf, since it was loaded first (unless, of course, layout.inf was
  1808. // already in our list of loaded INFs).
  1809. //
  1810. if(!FileName) {
  1811. //
  1812. // First, find the end of the list.
  1813. //
  1814. for(CurInf = ExistingInf; CurInf->Next; CurInf = CurInf->Next);
  1815. //
  1816. // Now, search the list, back-to-front, looking for a layout file in each INF's
  1817. // [version] section.
  1818. //
  1819. for(; CurInf; CurInf = CurInf->Prev) {
  1820. //
  1821. // Locate the [Version] section.
  1822. //
  1823. if(InfSection = InfLocateSection(CurInf, pszVersion, NULL)) {
  1824. //
  1825. // Now look for a LayoutFile line.
  1826. //
  1827. LineNumber = 0;
  1828. if(InfLocateLine(CurInf, InfSection, pszLayoutFile, &LineNumber, &InfLine)) {
  1829. //
  1830. // We've found the line containing the INFs to be append-
  1831. // loaded. Get the first field on the line to start off
  1832. // our loop below.
  1833. //
  1834. FileName = InfGetField(CurInf, InfLine, 1, NULL);
  1835. break;
  1836. } else {
  1837. //
  1838. // Make sure InfLine is still NULL, so we won't try to use it.
  1839. //
  1840. InfLine = NULL;
  1841. }
  1842. }
  1843. }
  1844. if(!FileName) {
  1845. //
  1846. // Then we didn't find any INFs that specify a layout file.
  1847. //
  1848. d = ERROR_INVALID_DATA;
  1849. goto clean0;
  1850. }
  1851. }
  1852. //
  1853. // Now append-load the INF (or the possibly multiple INFs, if we're
  1854. // using a LayoutFile line).
  1855. //
  1856. for(Field = 1;
  1857. FileName;
  1858. FileName = InfLine ? InfGetField(CurInf, InfLine, ++Field, NULL) : NULL) {
  1859. FilenameCount = 0;
  1860. LookInInfDirAlso = TRUE;
  1861. TryPnf = FALSE;
  1862. //
  1863. // Determine whether just the filename (no path) was specified.
  1864. //
  1865. if(FileName == pSetupGetFileTitle(FileName)) {
  1866. //
  1867. // If we retrieved this filename from an INF's [version] section,
  1868. // then we first attempt to open up the layout file from the
  1869. // directory where we found the INF. If we don't find it in that
  1870. // directory, and that directory wasn't the Inf directory, then
  1871. // we try to open it up in %windir%\Inf as well.
  1872. //
  1873. if(CurInf) {
  1874. //
  1875. // Copy the path without the ending backslash character,
  1876. // because that's how the 'InfDirectory' string is formatted.
  1877. //
  1878. lstrcpyn(Filename[0],
  1879. CurInf->VersionBlock.Filename,
  1880. (int)(pSetupGetFileTitle(CurInf->VersionBlock.Filename) - CurInf->VersionBlock.Filename)
  1881. );
  1882. //
  1883. // Compare this path against the InfDirectory path, to see
  1884. // if they're the same.
  1885. //
  1886. if(!lstrcmpi(Filename[0], InfDirectory)) {
  1887. TryPnf = TRUE;
  1888. LookInInfDirAlso = FALSE;
  1889. }
  1890. //
  1891. // Now concatenate the layout filename onto the path.
  1892. //
  1893. pSetupConcatenatePaths(Filename[0], FileName, MAX_PATH, NULL);
  1894. FilenameCount = 1;
  1895. //
  1896. // If 'TryPnf' is still FALSE, then that means that the INF
  1897. // wasn't in the INF directory. Now find out if it's in a
  1898. // location that requires a non-NULL SourcePath (i.e.,
  1899. // something other than the default).
  1900. //
  1901. if(!TryPnf) {
  1902. InfSourcePathFromFileName(Filename[0], &TempCharPtr, &TryPnf);
  1903. }
  1904. }
  1905. if(LookInInfDirAlso) {
  1906. lstrcpy(Filename[FilenameCount], InfDirectory);
  1907. pSetupConcatenatePaths(Filename[FilenameCount], FileName, MAX_PATH, NULL);
  1908. if(!FilenameCount) {
  1909. TryPnf = TRUE;
  1910. }
  1911. FilenameCount++;
  1912. }
  1913. } else {
  1914. //
  1915. // The INF filename contains more than just a filename. Assume
  1916. // it's an absolute path. (We need to make sure it's fully-
  1917. // qualified, because that's what LoadInfFile expects.)
  1918. //
  1919. d = GetFullPathName(FileName,
  1920. SIZECHARS(Filename[0]),
  1921. Filename[0],
  1922. &DontCare
  1923. );
  1924. if(!d) {
  1925. d = GetLastError();
  1926. goto clean0;
  1927. } else if(d >= SIZECHARS(Filename[0])) {
  1928. MYASSERT(0);
  1929. d = ERROR_BUFFER_OVERFLOW;
  1930. goto clean0;
  1931. }
  1932. InfSourcePathFromFileName(Filename[0], &TempCharPtr, &TryPnf);
  1933. FilenameCount = 1;
  1934. //
  1935. // (Since we're setting FilenameCount to 1, we know we'll go
  1936. // through the loop below at least once, thus d will get set to
  1937. // the proper error, so we don't have to re-initialize it to
  1938. // NO_ERROR here.)
  1939. //
  1940. }
  1941. for(i = 0; i < FilenameCount; i++) {
  1942. //
  1943. // Load the inf
  1944. //
  1945. if(FileExists(Filename[i], &FindData)) {
  1946. if((d = LoadInfFile(Filename[i],
  1947. &FindData,
  1948. INF_STYLE_WIN4,
  1949. (i | TryPnf) ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
  1950. NULL,
  1951. (i | TryPnf) ? NULL : TempCharPtr,
  1952. NULL,
  1953. ExistingInf,
  1954. ExistingInf->LogContext,
  1955. &ExistingInf,
  1956. &errorLine,
  1957. NULL)) == NO_ERROR) {
  1958. break;
  1959. }
  1960. } else {
  1961. d = GetLastError();
  1962. }
  1963. }
  1964. //
  1965. // We no longer need the INF source path--free it if necessary.
  1966. //
  1967. if(TempCharPtr) {
  1968. MyFree(TempCharPtr);
  1969. TempCharPtr = NULL;
  1970. }
  1971. if(d != NO_ERROR) {
  1972. break;
  1973. }
  1974. }
  1975. clean0:
  1976. //
  1977. // If the caller requested it, give them the line number at which any error occurred.
  1978. // (This may be zero on non-parse errors.)
  1979. //
  1980. if(ErrorLine) {
  1981. *ErrorLine = errorLine;
  1982. }
  1983. } except(EXCEPTION_EXECUTE_HANDLER) {
  1984. //
  1985. // If we hit an AV, then use invalid parameter error, otherwise, assume an inpage error when dealing
  1986. // with a mapped-in file.
  1987. //
  1988. d = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  1989. if(TempCharPtr) {
  1990. MyFree(TempCharPtr);
  1991. }
  1992. //
  1993. // Access the 'ExistingInf' variable, so that the compiler will respect our statement
  1994. // ordering w.r.t. this variable. Otherwise, we may not always know whether or not
  1995. // we should be unlocking this INF.
  1996. //
  1997. ExistingInf = ExistingInf;
  1998. }
  1999. if(ExistingInf) {
  2000. UnlockInf(ExistingInf);
  2001. }
  2002. SetLastError(d);
  2003. return(d == NO_ERROR);
  2004. }
  2005. VOID
  2006. SetupCloseInfFile(
  2007. IN HINF InfHandle
  2008. )
  2009. /*++
  2010. Routine Description:
  2011. Arguments:
  2012. Return Value:
  2013. --*/
  2014. {
  2015. PLOADED_INF CurInf, NextInf;
  2016. try {
  2017. //
  2018. // Make sure we can lock the head of the INF list before
  2019. // we start deleting!
  2020. //
  2021. if(LockInf((PLOADED_INF)InfHandle)) {
  2022. //
  2023. // Also check INF Signature field as a further validation.
  2024. //
  2025. if(((PLOADED_INF)InfHandle)->Signature == LOADED_INF_SIG) {
  2026. CurInf = ((PLOADED_INF)InfHandle)->Next;
  2027. DestroySynchronizedAccess(&(((PLOADED_INF)InfHandle)->Lock));
  2028. FreeLoadedInfDescriptor((PLOADED_INF)InfHandle);
  2029. for(; CurInf; CurInf = NextInf) {
  2030. NextInf = CurInf->Next;
  2031. FreeInfFile(CurInf);
  2032. }
  2033. } else {
  2034. UnlockInf((PLOADED_INF)InfHandle);
  2035. }
  2036. }
  2037. } except(EXCEPTION_EXECUTE_HANDLER) {
  2038. ;
  2039. }
  2040. }
  2041. //
  2042. // ANSI version
  2043. //
  2044. BOOL
  2045. WINAPI
  2046. SetupVerifyInfFileA(
  2047. IN PCSTR InfName,
  2048. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  2049. OUT PSP_INF_SIGNER_INFO_A InfSignerInfo
  2050. )
  2051. {
  2052. DWORD Err = NO_ERROR;
  2053. SP_INF_SIGNER_INFO_W InfSignerInfoW;
  2054. int i;
  2055. PWSTR InfNameUnicode = NULL;
  2056. try {
  2057. if (!InfName) {
  2058. SetLastError(ERROR_INVALID_PARAMETER);
  2059. leave;
  2060. }
  2061. if (!InfSignerInfo || (InfSignerInfo->cbSize != sizeof(SP_INF_SIGNER_INFO_A))) {
  2062. SetLastError(ERROR_INVALID_PARAMETER);
  2063. leave; // exit try block
  2064. }
  2065. Err = pSetupCaptureAndConvertAnsiArg(InfName, &InfNameUnicode);
  2066. if (Err != NO_ERROR) {
  2067. leave; // exit try block
  2068. }
  2069. InfSignerInfoW.cbSize = sizeof(InfSignerInfoW);
  2070. Err = GLE_FN_CALL(FALSE,
  2071. SetupVerifyInfFile(InfNameUnicode,
  2072. AltPlatformInfo,
  2073. &InfSignerInfoW)
  2074. );
  2075. if((Err == NO_ERROR) ||
  2076. (Err == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  2077. (Err == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  2078. i = WideCharToMultiByte(
  2079. CP_ACP,
  2080. 0,
  2081. InfSignerInfoW.CatalogFile,
  2082. -1,
  2083. InfSignerInfo->CatalogFile,
  2084. SIZECHARS(InfSignerInfo->CatalogFile),
  2085. NULL,
  2086. NULL
  2087. );
  2088. if (i==0) {
  2089. //
  2090. // error occurred (LastError set to error)
  2091. //
  2092. Err = GetLastError();
  2093. leave; // exit try block
  2094. }
  2095. i = WideCharToMultiByte(
  2096. CP_ACP,
  2097. 0,
  2098. InfSignerInfoW.DigitalSigner,
  2099. -1,
  2100. InfSignerInfo->DigitalSigner,
  2101. SIZECHARS(InfSignerInfo->DigitalSigner),
  2102. NULL,
  2103. NULL
  2104. );
  2105. if (i==0) {
  2106. //
  2107. // error occurred (LastError set to error)
  2108. //
  2109. Err = GetLastError();
  2110. leave; // exit try block
  2111. }
  2112. i = WideCharToMultiByte(
  2113. CP_ACP,
  2114. 0,
  2115. InfSignerInfoW.DigitalSignerVersion,
  2116. -1,
  2117. InfSignerInfo->DigitalSignerVersion,
  2118. SIZECHARS(InfSignerInfo->DigitalSignerVersion),
  2119. NULL,
  2120. NULL
  2121. );
  2122. if (i==0) {
  2123. //
  2124. // error occurred (LastError set to error)
  2125. //
  2126. Err = GetLastError();
  2127. leave; // exit try block
  2128. }
  2129. }
  2130. } except(EXCEPTION_EXECUTE_HANDLER) {
  2131. Err = ERROR_INVALID_PARAMETER;
  2132. }
  2133. if (InfNameUnicode) {
  2134. MyFree(InfNameUnicode);
  2135. }
  2136. SetLastError(Err);
  2137. return (Err == NO_ERROR);
  2138. }
  2139. BOOL
  2140. WINAPI
  2141. SetupVerifyInfFile(
  2142. IN LPCTSTR InfName,
  2143. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  2144. OUT PSP_INF_SIGNER_INFO InfSignerInfo
  2145. )
  2146. /*++
  2147. Routine Description:
  2148. This routine verifies the digital signature of the specified INF,
  2149. using its corresponding catalog. The verification can optionally
  2150. be performed against a non-native platform.
  2151. Arguments:
  2152. InfName - Supplies the name of the INF file to be verified.
  2153. This name may include a path.
  2154. AltPlatformInfo - optionally, supplies the address of a structure
  2155. containing information regarding the alternate platform that is
  2156. to be used when validating the INF file.
  2157. InfSignerInfo - Supplies the address of a structure that receives information
  2158. about the INF's digital signature (if it is signed).
  2159. Return Value:
  2160. If the INF was successfully validated using driver signing policy, the
  2161. return value is TRUE.
  2162. If the INF was successfully validated using Authenticode policy, and the
  2163. publisher was in the TrustedPublisher store, the return value is FALSE and
  2164. GetLastError returns ERROR_AUTHENTICODE_TRUSTED_PUBLISHER.
  2165. If the INF was successfully validated using Authenticode policy, and the
  2166. publisher was *not* in the TrustedPublisher store, the return value is
  2167. FALSE and GetLastError returns ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED.
  2168. If the function fails, the return value is FALSE. To get extended error
  2169. information, call GetLastError.
  2170. --*/
  2171. {
  2172. DWORD Err = NO_ERROR;
  2173. DWORD AuthenticodeError;
  2174. TCHAR PathBuffer[MAX_PATH];
  2175. PLOADED_INF Inf = NULL;
  2176. BOOL PnfWasUsed;
  2177. UINT ErrorLineNumber;
  2178. BOOL TryPnf;
  2179. WIN32_FIND_DATA FindData;
  2180. DWORD TempRequiredSize;
  2181. PTSTR DontCare;
  2182. HANDLE hWVTStateData;
  2183. PCRYPT_PROVIDER_DATA ProviderData;
  2184. PCRYPT_PROVIDER_SGNR ProviderSigner;
  2185. PCRYPT_PROVIDER_CERT ProviderCert;
  2186. try {
  2187. if (!InfName) {
  2188. Err = ERROR_INVALID_PARAMETER;
  2189. leave;
  2190. }
  2191. if (!InfSignerInfo || (InfSignerInfo->cbSize != sizeof(SP_INF_SIGNER_INFO))) {
  2192. Err = ERROR_INVALID_PARAMETER;
  2193. leave;
  2194. }
  2195. if(InfName == pSetupGetFileTitle(InfName)) {
  2196. //
  2197. // The specified INF name is a simple filename. Search for it in
  2198. // the DevicePath search path list.
  2199. //
  2200. Err = SearchForInfFile(InfName,
  2201. &FindData,
  2202. INFINFO_INF_PATH_LIST_SEARCH,
  2203. PathBuffer,
  2204. SIZECHARS(PathBuffer),
  2205. NULL
  2206. );
  2207. if(Err == NO_ERROR) {
  2208. TryPnf = TRUE;
  2209. } else {
  2210. leave;
  2211. }
  2212. } else {
  2213. //
  2214. // The specified INF filename contains more than just a filename.
  2215. // Assume it's an absolute path. (We need to make sure it's
  2216. // fully-qualified, because that's what LoadInfFile expects.)
  2217. //
  2218. TempRequiredSize = GetFullPathName(InfName,
  2219. SIZECHARS(PathBuffer),
  2220. PathBuffer,
  2221. &DontCare
  2222. );
  2223. if(!TempRequiredSize) {
  2224. Err = GetLastError();
  2225. leave;
  2226. } else if(TempRequiredSize >= SIZECHARS(PathBuffer)) {
  2227. MYASSERT(0);
  2228. Err = ERROR_BUFFER_OVERFLOW;
  2229. leave;
  2230. }
  2231. if(FileExists(PathBuffer, &FindData)) {
  2232. //
  2233. // We have a valid file path, and we're ready to load this INF.
  2234. //
  2235. InfSourcePathFromFileName(PathBuffer, NULL, &TryPnf);
  2236. } else {
  2237. Err = GetLastError();
  2238. leave;
  2239. }
  2240. }
  2241. //
  2242. // Load the INF.
  2243. //
  2244. Err = LoadInfFile(PathBuffer,
  2245. &FindData,
  2246. INF_STYLE_WIN4,
  2247. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | (TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0),
  2248. NULL,
  2249. NULL,
  2250. NULL,
  2251. NULL,
  2252. NULL, // LogContext
  2253. &Inf,
  2254. &ErrorLineNumber,
  2255. NULL
  2256. );
  2257. if(Err != NO_ERROR) {
  2258. leave;
  2259. }
  2260. InfSignerInfo->CatalogFile[0] = TEXT('\0');
  2261. InfSignerInfo->DigitalSigner[0] = TEXT('\0');
  2262. InfSignerInfo->DigitalSignerVersion[0] = TEXT('\0');
  2263. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  2264. //
  2265. // We can't call the VerifyDeviceInfFile internal routine, because
  2266. // it doesn't expect to be asked for the signer info (it doesn't
  2267. // make any sense to talk about the signer info, because we have
  2268. // no idea who signed the INF, or even if it was signed).
  2269. //
  2270. Err = NO_ERROR;
  2271. } else {
  2272. Err = VerifyDeviceInfFile(NULL,
  2273. NULL,
  2274. PathBuffer,
  2275. Inf,
  2276. AltPlatformInfo,
  2277. InfSignerInfo->CatalogFile,
  2278. InfSignerInfo->DigitalSigner,
  2279. InfSignerInfo->DigitalSignerVersion,
  2280. 0,
  2281. NULL
  2282. );
  2283. if((Err != NO_ERROR) && (Err != ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH)) {
  2284. //
  2285. // We failed to verify via driver signing policy (and it wasn't
  2286. // simply because a valid driver signing catalog didn't have an
  2287. // applicable osattribute). Fall back to validating via
  2288. // Authenticode policy. NOTE: we don't have to worry about
  2289. // whether Authenticode verification is acceptable for this
  2290. // class--the VerifyDeviceInfFile routine will check for that.
  2291. //
  2292. // NTRAID#NTBUG9-719853-2002/10/11-LonnyM We may be using Authenticode policy when we shouldn't!
  2293. // It's possible that we have a valid catalog (per driver
  2294. // signing policy), and the failure was due to the INF having
  2295. // been tampered with. In that case, we really shouldn't be
  2296. // doing Authenticode validation. However, we know that
  2297. // WinVerifyTrust should fail in either case, and Authenticode
  2298. // policy actually gives us a better error (TRUST_E_NOSIGNATURE
  2299. // instead of ERROR_INVALID_PARAMETER).
  2300. //
  2301. AuthenticodeError = VerifyDeviceInfFile(
  2302. NULL,
  2303. NULL,
  2304. PathBuffer,
  2305. Inf,
  2306. AltPlatformInfo,
  2307. InfSignerInfo->CatalogFile,
  2308. NULL,
  2309. NULL,
  2310. VERIFY_INF_USE_AUTHENTICODE_CATALOG,
  2311. &hWVTStateData
  2312. );
  2313. if((AuthenticodeError == ERROR_AUTHENTICODE_TRUSTED_PUBLISHER) ||
  2314. (AuthenticodeError == ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED)) {
  2315. //
  2316. // Update error to indicate that the INF was Authenticode
  2317. // signed.
  2318. //
  2319. Err = AuthenticodeError;
  2320. ProviderData = WTHelperProvDataFromStateData(hWVTStateData);
  2321. MYASSERT(ProviderData);
  2322. if (ProviderData) {
  2323. ProviderSigner = WTHelperGetProvSignerFromChain(ProviderData,
  2324. 0,
  2325. FALSE,
  2326. 0);
  2327. MYASSERT(ProviderSigner);
  2328. if (ProviderSigner) {
  2329. ProviderCert = WTHelperGetProvCertFromChain(ProviderSigner,
  2330. 0);
  2331. MYASSERT(ProviderCert);
  2332. if (ProviderCert) {
  2333. //
  2334. // Get the publisher and add this
  2335. // as the DigitalSigner.
  2336. //
  2337. CertGetNameString(ProviderCert->pCert,
  2338. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  2339. 0,
  2340. NULL,
  2341. InfSignerInfo->DigitalSigner,
  2342. SIZECHARS(InfSignerInfo->DigitalSigner));
  2343. }
  2344. }
  2345. }
  2346. if(hWVTStateData) {
  2347. pSetupCloseWVTStateData(hWVTStateData);
  2348. }
  2349. } else if(AuthenticodeError != ERROR_AUTHENTICODE_DISALLOWED) {
  2350. //
  2351. // It was acceptable to validate using Authenticode
  2352. // policy (it just didn't work). Use this error,
  2353. // instead of the one generated based on driver signing
  2354. // verification policy.
  2355. //
  2356. Err = AuthenticodeError;
  2357. }
  2358. }
  2359. }
  2360. } except(EXCEPTION_EXECUTE_HANDLER) {
  2361. Err = ERROR_INVALID_DATA;
  2362. }
  2363. if (Inf) {
  2364. FreeInfFile(Inf);
  2365. Inf = NULL;
  2366. }
  2367. SetLastError(Err);
  2368. return (Err == NO_ERROR);
  2369. }
  2370. /////////////////////////////////////////////////////////////////
  2371. //
  2372. // Internal routines
  2373. //
  2374. /////////////////////////////////////////////////////////////////
  2375. BOOL
  2376. pSetupVersionNodeFromInfInformation(
  2377. IN PSP_INF_INFORMATION InfInformation,
  2378. IN UINT InfIndex,
  2379. OUT PINF_VERSION_NODE VersionNode,
  2380. OUT PTSTR OriginalFilename OPTIONAL
  2381. )
  2382. /*++
  2383. Routine Description:
  2384. Fills in a caller-supplied INF_VERSION_NODE buffer for an INF file
  2385. from the SP_INF_INFORMATION structure.
  2386. Arguments:
  2387. InfInformation - supplies the inf information descriptor
  2388. InfIndex - supplies the 0-based index of the inf whose version block
  2389. is requested. If this value is not inrange an error is returned.
  2390. VersionNode - supplies the address of a buffer that receives the version
  2391. node structure.
  2392. OriginalFilename - optionally, supplies the address of a character buffer
  2393. (that must be at least MAX_PATH characters large) that receives the
  2394. INF's original filename (which may be the same as its current filename
  2395. if the INF isn't an OEM INF.
  2396. Return Value:
  2397. If successful, the return value is TRUE, otherwise, it is FALSE.
  2398. --*/
  2399. {
  2400. PINF_VERSION_BLOCK First;
  2401. INF_VERSION_BLOCK UNALIGNED *Ver;
  2402. PUCHAR Base;
  2403. UINT ord;
  2404. INF_VERSION_BLOCK TempVersionBlock;
  2405. UINT FilenameSize;
  2406. //
  2407. // Get pointer to first version block.
  2408. //
  2409. Base = (PUCHAR)InfInformation;
  2410. First = (PINF_VERSION_BLOCK)(Base+offsetof(SP_INF_INFORMATION,VersionData));
  2411. //
  2412. // Find relevant version block
  2413. //
  2414. ord = 0;
  2415. for(Ver=First; Ver; Ver=(INF_VERSION_BLOCK UNALIGNED *)(Base+Ver->NextOffset)) {
  2416. if(ord++ == InfIndex) {
  2417. break;
  2418. }
  2419. }
  2420. if(!Ver) {
  2421. SetLastError(ERROR_NO_MORE_ITEMS);
  2422. return FALSE;
  2423. }
  2424. //
  2425. // Now fill in the version node based on the information contained in the version block.
  2426. //
  2427. VersionNode->LastWriteTime = Ver->LastWriteTime;
  2428. VersionNode->DataBlock = (CONST TCHAR *)((PBYTE)(Ver->Filename) + Ver->OffsetToData);
  2429. VersionNode->DataSize = Ver->DataSize;
  2430. VersionNode->DatumCount = Ver->DatumCount;
  2431. //
  2432. // The 'filename' character buffer may actually contain two strings--the
  2433. // first being the INF's current filename (with path), and the second being
  2434. // the INF's original filename (this won't be present if the INF's name
  2435. // hasn't changed from its original name).
  2436. //
  2437. // Copy the first MAX_PATH characters of this buffer (or the entire buffer,
  2438. // whichever is smaller) into the VersionNode's Filename buffer, then after
  2439. // we've computed the string length of that string, we can ascertain whether
  2440. // or not there's another string following it containing the INF's original
  2441. // name.
  2442. //
  2443. FilenameSize = (Ver->OffsetToData < SIZECHARS(VersionNode->Filename))
  2444. ? Ver->OffsetToData : SIZECHARS(VersionNode->Filename);
  2445. CopyMemory(VersionNode->Filename, Ver->Filename, FilenameSize);
  2446. VersionNode->FilenameSize = (lstrlen(VersionNode->Filename) + 1) * sizeof(TCHAR);
  2447. MYASSERT(Ver->OffsetToData >= VersionNode->FilenameSize);
  2448. if(OriginalFilename) {
  2449. if(Ver->OffsetToData > VersionNode->FilenameSize) {
  2450. //
  2451. // Then there's more data in the Filename buffer, namely the INF's
  2452. // original name--fill this filename into the caller-supplied buffer.
  2453. //
  2454. FilenameSize = Ver->OffsetToData - VersionNode->FilenameSize;
  2455. MYASSERT(((UINT)(FilenameSize / sizeof(TCHAR)) * sizeof(TCHAR)) == FilenameSize);
  2456. MYASSERT(FilenameSize > sizeof(TCHAR));
  2457. CopyMemory(OriginalFilename,
  2458. (PBYTE)Ver->Filename + VersionNode->FilenameSize,
  2459. FilenameSize
  2460. );
  2461. MYASSERT(((lstrlen(OriginalFilename) + 1) * sizeof(TCHAR)) == FilenameSize);
  2462. } else {
  2463. //
  2464. // No original name info stored--must be same as current name.
  2465. //
  2466. if(FAILED(StringCchCopy(OriginalFilename,MAX_PATH, pSetupGetFileTitle(VersionNode->Filename)))) {
  2467. SetLastError(ERROR_BUFFER_OVERFLOW);
  2468. return FALSE;
  2469. }
  2470. }
  2471. }
  2472. return TRUE;
  2473. }
  2474. PCTSTR
  2475. pSetupGetVersionDatum(
  2476. IN PINF_VERSION_NODE VersionNode,
  2477. IN PCTSTR DatumName
  2478. )
  2479. /*++
  2480. Routine Description:
  2481. Look up a piece of version data in an version data node.
  2482. Arguments:
  2483. VersionNode - supplies a pointer to the version node to
  2484. be searched for the datum.
  2485. DatumName - supplies the name of the datum to be retreived.
  2486. Return Value:
  2487. NULL if the datum does not exist in the data block.
  2488. Otherwise a pointer to the datum value is returned. The caller
  2489. must not free or write into this memory.
  2490. --*/
  2491. {
  2492. WORD Datum;
  2493. UINT StringLength;
  2494. PCTSTR Data = VersionNode->DataBlock;
  2495. for(Datum=0; Datum < VersionNode->DatumCount; Datum++) {
  2496. StringLength = lstrlen(Data) + 1;
  2497. //
  2498. // Go through the version block looking for a matching datum name.
  2499. //
  2500. if(lstrcmpi(Data, DatumName)) {
  2501. //
  2502. // Point to the next one.
  2503. //
  2504. Data += StringLength;
  2505. Data += lstrlen(Data) + 1;
  2506. } else {
  2507. //
  2508. // Found it. Return datum value to caller.
  2509. //
  2510. return (Data + StringLength);
  2511. }
  2512. }
  2513. return(NULL);
  2514. }
  2515. BOOL
  2516. pSetupGetCatalogFileValue(
  2517. IN PINF_VERSION_NODE InfVersionNode,
  2518. OUT LPTSTR Buffer,
  2519. IN DWORD BufferSize,
  2520. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo OPTIONAL
  2521. )
  2522. /*++
  2523. Routine Description:
  2524. This routine fetches the (potentially decorated) CatalogFile= value from the
  2525. specified inf version section.
  2526. Arguments:
  2527. InfVersionNode - points to the INF version node from which we're attempting
  2528. to retrieve the associated catalog file.
  2529. Buffer - if the routine returns TRUE, receives the value for CatalogFile=
  2530. in the [Version] section of the inf.
  2531. BufferSize - supplies the size in bytes (ansi) or chars (unicode) of
  2532. the buffer pointed to by Buffer.
  2533. AltPlatformInfo - optionally, supplies the address of a structure describing
  2534. the platform parameters that should be used in formulating the decorated
  2535. CatalogFile= entry to be used when searching for the INF's associated
  2536. catalog file.
  2537. Return Value:
  2538. Boolean value indicating whether a value was found and copied to the
  2539. caller-supplied Buffer.
  2540. --*/
  2541. {
  2542. TCHAR CatFileWithExt[64];
  2543. LPCTSTR p, NtPlatformSuffixToUse;
  2544. DWORD PlatformId;
  2545. MYASSERT(BufferSize >= MAX_PATH);
  2546. p = NULL;
  2547. CopyMemory(CatFileWithExt, pszCatalogFile, sizeof(pszCatalogFile) - sizeof(TCHAR));
  2548. //
  2549. // Set up some variables based on the native platform or upon the non-native
  2550. // platform specified in the AltPlatformInfo parameter.
  2551. //
  2552. if(AltPlatformInfo) {
  2553. PlatformId = AltPlatformInfo->Platform;
  2554. switch(AltPlatformInfo->ProcessorArchitecture) {
  2555. case PROCESSOR_ARCHITECTURE_INTEL:
  2556. NtPlatformSuffixToUse = pszNtX86Suffix;
  2557. break;
  2558. case PROCESSOR_ARCHITECTURE_IA64:
  2559. NtPlatformSuffixToUse = pszNtIA64Suffix;
  2560. break;
  2561. case PROCESSOR_ARCHITECTURE_AMD64:
  2562. NtPlatformSuffixToUse = pszNtAMD64Suffix;
  2563. break;
  2564. default:
  2565. return FALSE;
  2566. }
  2567. } else {
  2568. PlatformId = OSVersionInfo.dwPlatformId;
  2569. NtPlatformSuffixToUse = pszNtPlatformSuffix;
  2570. }
  2571. if(PlatformId == VER_PLATFORM_WIN32_NT) {
  2572. //
  2573. // We're running on NT, so first try the NT architecture-specific
  2574. // extension, then the generic NT extension.
  2575. //
  2576. lstrcpyn((PTSTR)((PBYTE)CatFileWithExt + (sizeof(pszCatalogFile) - sizeof(TCHAR))),
  2577. NtPlatformSuffixToUse,
  2578. SIZECHARS(CatFileWithExt) - (sizeof(pszCatalogFile) - sizeof(TCHAR))
  2579. );
  2580. p = pSetupGetVersionDatum(InfVersionNode, CatFileWithExt);
  2581. if(!p) {
  2582. //
  2583. // We didn't find an NT architecture-specific CatalogFile= entry, so
  2584. // fall back to looking for just an NT-specific one.
  2585. //
  2586. CopyMemory((PBYTE)CatFileWithExt + (sizeof(pszCatalogFile) - sizeof(TCHAR)),
  2587. pszNtSuffix,
  2588. sizeof(pszNtSuffix)
  2589. );
  2590. p = pSetupGetVersionDatum(InfVersionNode, CatFileWithExt);
  2591. }
  2592. } else {
  2593. //
  2594. // We're running on Windows 95, so try the Windows-specific extension
  2595. //
  2596. CopyMemory((PBYTE)CatFileWithExt + (sizeof(pszCatalogFile) - sizeof(TCHAR)),
  2597. pszWinSuffix,
  2598. sizeof(pszWinSuffix)
  2599. );
  2600. p = pSetupGetVersionDatum(InfVersionNode, CatFileWithExt);
  2601. }
  2602. //
  2603. // If we didn't find an OS/architecture-specific CatalogFile= entry above,
  2604. // then look for an undecorated entry.
  2605. //
  2606. if(!p) {
  2607. p = pSetupGetVersionDatum(InfVersionNode, pszCatalogFile);
  2608. }
  2609. //
  2610. // If we got back an empty string, then treat this as if there was no
  2611. // CatalogFile= entry (this might be used, for example, so that a system-
  2612. // supplied INF that supports both NT and Win98 could specify an undecorated
  2613. // CatalogFile= entry for Win98, yet supply an NT-specific CatalogFile=
  2614. // entry that's an empty string, so that we'd do global verification on NT).
  2615. //
  2616. if(p && lstrlen(p)) {
  2617. lstrcpyn(Buffer, p, BufferSize);
  2618. return TRUE;
  2619. } else {
  2620. return FALSE;
  2621. }
  2622. }
  2623. VOID
  2624. pSetupGetPhysicalInfFilepath(
  2625. IN PINFCONTEXT LineContext,
  2626. OUT LPTSTR Buffer,
  2627. IN DWORD BufferSize
  2628. )
  2629. {
  2630. lstrcpyn(
  2631. Buffer,
  2632. ((PLOADED_INF)LineContext->CurrentInf)->VersionBlock.Filename,
  2633. BufferSize
  2634. );
  2635. }