Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1591 lines
43 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. hwdisk.c
  5. Abstract:
  6. Implements detection of a third-party NT driver supplied before the
  7. installation of NT and copies all files for the specified devices
  8. to a temporary directory.
  9. Author:
  10. Jim Schmidt (jimschm) 06-Nov-1997
  11. Revision History:
  12. jimschm 15-Jun-1998 Added support for catalog files
  13. --*/
  14. #include "pch.h"
  15. #include "hwcompp.h"
  16. #include "memdb.h"
  17. #define DBG_HWDISK "HwDisk"
  18. //
  19. // VWIN32 interface
  20. //
  21. #define VWIN32_DIOC_DOS_IOCTL 1
  22. typedef struct _DIOC_REGISTERS {
  23. DWORD reg_EBX;
  24. DWORD reg_EDX;
  25. DWORD reg_ECX;
  26. DWORD reg_EAX;
  27. DWORD reg_EDI;
  28. DWORD reg_ESI;
  29. DWORD reg_Flags;
  30. } DIOC_REGISTERS, *PDIOC_REGISTERS;
  31. //
  32. // Private types and local functions
  33. //
  34. typedef struct {
  35. HINF Inf;
  36. HINF LayoutInf;
  37. PCTSTR BaseDir;
  38. PCTSTR DestDir;
  39. DWORD ResultCode;
  40. HWND WorkingDlg; OPTIONAL
  41. HANDLE CancelEvent; OPTIONAL
  42. } COPYPARAMS, *PCOPYPARAMS;
  43. BOOL
  44. pAddHashTable (
  45. IN HASHTABLE Table,
  46. IN HASHITEM StringId,
  47. IN PCTSTR String,
  48. IN PVOID ExtraData,
  49. IN UINT ExtraDataSize,
  50. IN LPARAM lParam
  51. );
  52. BOOL
  53. pInstallSectionCallback (
  54. IN HASHTABLE Table,
  55. IN HASHITEM StringId,
  56. IN PCTSTR String,
  57. IN PVOID ExtraData,
  58. IN UINT ExtraDataSize,
  59. IN LPARAM lParam
  60. );
  61. PCTSTR g_EjectMedia = NULL;
  62. TCHAR g_EjectMediaFileSpec[MAX_TCHAR_PATH];
  63. //
  64. // Implementation
  65. //
  66. BOOL
  67. CopyDriverFilesToTempDir (
  68. IN HWND WorkingDlg, OPTIONAL
  69. IN HANDLE CancelEvent, OPTIONAL
  70. IN PCTSTR SourceInfDir,
  71. IN PCTSTR SourceInfSpec,
  72. IN HASHTABLE PnpIdTable,
  73. IN PCTSTR TempDir,
  74. IN HASHTABLE PrevSuppliedIdTable,
  75. IN OUT HASHTABLE SuppliedIdTable,
  76. OUT PTSTR DestDirCreated,
  77. IN PCTSTR OriginalInstallPath
  78. )
  79. /*++
  80. Routine Description:
  81. CopyDriverFilesToTempDir copies all files required by the driver to
  82. the specified temporary directory. This routine scans the indicated
  83. INF file for one or more PNP IDs, and if at least one is found, the
  84. installer sections are traversed to locate files that need to be
  85. copied.
  86. This routine is divided into the following operations:
  87. (1) Detect the support of one or more PNP IDs in the source INF
  88. (2) For each supported PNP ID:
  89. (A) Scan the installer sections for include lines
  90. (B) Copy all necessary files to a unique subdirectory.
  91. Maintain a mapping of PNP IDs to installer INF
  92. locations using memdb.
  93. Arguments:
  94. WorkingDlg - Specifies the window handle of the parent for the
  95. file copy dialog.
  96. CancelEvent - Specifies the event that when signaled causes the copy
  97. to be canceled
  98. SourceInfDir - Specifies directory of SourceInfSpec
  99. SourceInfSpec - Specifies full path to INF file to process
  100. PnpIdTable - Specifies a hash table of PNP IDs that are installed
  101. on the Win9x computer. If one or more IDs in this list
  102. are found in SourceInfSpec, driver files are copied.
  103. TempDir - Specifies root path for device driver files. Subdirs
  104. will be created under TempDir for each device driver.
  105. PrevSuppliedIdTable - Specifies string table holding a list of PNP IDs
  106. considered to be compatible with NT 5. This routine
  107. filters out all drivers that have previously been
  108. supplied.
  109. SuppliedIdTable - Specifies string table receiving a list of PNP IDs
  110. found in SourceInfSpec.
  111. DestDirCreated - Receives the destination directory upon successful copy
  112. of driver files, or is returned empty.
  113. Return Value:
  114. TRUE if one or more PNP IDs in PnpIdTable (and not in PrevSuppliedIdTable
  115. or SuppliedIdTable) were found in SourceInfSpec, or FALSE if either
  116. (A) no IDs were found or (B) an error occurred. Call GetLastError() for
  117. error details.
  118. --*/
  119. {
  120. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  121. INFSTRUCT isFile = INITINFSTRUCT_GROWBUFFER;
  122. INFSTRUCT isMfg = INITINFSTRUCT_GROWBUFFER;
  123. COPYPARAMS CopyParams;
  124. GROWLIST MatchingPnpIds = GROWLIST_INIT;
  125. HINF Inf;
  126. HASHTABLE InstallSectionsTable;
  127. PCTSTR Manufacturer;
  128. PCTSTR PnpId;
  129. PCTSTR MatchingPnpId;
  130. PCTSTR Section;
  131. PCTSTR DestDir = NULL;
  132. PCTSTR DestInfSpec = NULL;
  133. TCHAR TmpFileName[32];
  134. BOOL HaveOneId = FALSE;
  135. UINT u;
  136. UINT Count;
  137. static UINT DirCount = 0;
  138. BOOL NeedThisDriver;
  139. PTSTR ListPnpId;
  140. PCTSTR FileName;
  141. PCTSTR SourcePath;
  142. PCTSTR DestPath;
  143. PCTSTR LayoutFiles;
  144. BOOL Result = FALSE;
  145. BOOL SubResult;
  146. DWORD InfLine;
  147. HINF LayoutInf;
  148. #if 0
  149. PCTSTR Signature;
  150. #endif
  151. *DestDirCreated = 0;
  152. Inf = InfOpenInfFile (SourceInfSpec);
  153. if (Inf == INVALID_HANDLE_VALUE) {
  154. return FALSE;
  155. }
  156. InstallSectionsTable = HtAlloc();
  157. __try {
  158. //
  159. // We do not check version... because Signature is meaningless.
  160. //
  161. #if 0
  162. //
  163. // Verify INF is a $WINDOWS NT$ version
  164. //
  165. if (InfFindFirstLine (Inf, S_VERSION, S_SIGNATURE, &is)) {
  166. Signature = InfGetStringField (&is, 1);
  167. if (!StringIMatch (Signature, S_DOLLAR_WINDOWS_NT_DOLLAR)) {
  168. SetLastError (ERROR_WRONG_INF_STYLE);
  169. __leave;
  170. }
  171. } else {
  172. SetLastError (ERROR_WRONG_INF_STYLE);
  173. __leave;
  174. }
  175. #endif
  176. //
  177. // Check if this INF has a layout line.
  178. //
  179. LayoutInf = NULL;
  180. if (InfFindFirstLine (Inf, S_VERSION, S_LAYOUTFILES, &is)) {
  181. LayoutFiles = InfGetMultiSzField (&is, 1);
  182. if (LayoutFiles) {
  183. while (*LayoutFiles) {
  184. if (StringIMatch (LayoutFiles, S_LAYOUT_INF)) {
  185. LayoutInf = InfOpenInfInAllSources (S_LAYOUT_INF);
  186. if (LayoutInf == INVALID_HANDLE_VALUE) {
  187. DEBUGMSG ((DBG_ERROR, "Can't open %s", S_LAYOUT_INF));
  188. LayoutInf = NULL;
  189. }
  190. break;
  191. }
  192. LayoutFiles = GetEndOfString (LayoutFiles) + 1;
  193. }
  194. }
  195. }
  196. //
  197. // Create DestDir path
  198. //
  199. do {
  200. FreePathString (DestDir);
  201. DirCount++;
  202. wsprintf (TmpFileName, TEXT("driver.%03u"), DirCount);
  203. DestDir = JoinPaths (TempDir, TmpFileName);
  204. } while (DoesFileExist (DestDir));
  205. //
  206. // Scan [Manufacturer] section, then for each manufacturer, scan the
  207. // device list looking for PNP IDs that are in PnpIdTable.
  208. //
  209. if (InfFindFirstLine (Inf, S_MANUFACTURER, NULL, &is)) {
  210. do {
  211. //
  212. // Get manufacturer section name
  213. //
  214. Manufacturer = InfGetStringField (&is, 1);
  215. if (!Manufacturer) {
  216. DEBUGMSG ((DBG_HWDISK, "Can't get manufacturer string in %s", SourceInfSpec));
  217. __leave;
  218. }
  219. //
  220. // Enumerate all devices supported by the manufacturer
  221. //
  222. if (InfFindFirstLine (Inf, Manufacturer, NULL, &isMfg)) {
  223. do {
  224. //
  225. // Extract PNP ID
  226. //
  227. PnpId = InfGetMultiSzField (&isMfg, 2);
  228. MatchingPnpId = PnpId;
  229. if (PnpId) {
  230. while (*PnpId) {
  231. //
  232. // Check string table for ID
  233. //
  234. if (HtFindString (PnpIdTable, PnpId)) {
  235. //
  236. // ID was found! Add all PNP IDs to our list of
  237. // matching IDs, and add install section to
  238. // string table.
  239. //
  240. HaveOneId = TRUE;
  241. while (*MatchingPnpId) {
  242. if (!AddPnpIdsToGrowList (
  243. &MatchingPnpIds,
  244. MatchingPnpId
  245. )) {
  246. LOG ((
  247. LOG_ERROR,
  248. "Error adding %s to grow list",
  249. PnpId
  250. ));
  251. __leave;
  252. }
  253. MatchingPnpId = GetEndOfString (MatchingPnpId) + 1;
  254. }
  255. Section = InfGetStringField (&isMfg, 1);
  256. if (!Section) {
  257. LOG ((
  258. LOG_ERROR,
  259. "Can't get install section for line in [%s] of %s",
  260. Manufacturer,
  261. SourceInfSpec
  262. ));
  263. __leave;
  264. }
  265. if (!HtAddString (InstallSectionsTable, Section)) {
  266. LOG ((
  267. LOG_ERROR,
  268. "Error adding %s to string table",
  269. Section
  270. ));
  271. __leave;
  272. }
  273. break;
  274. }
  275. PnpId = GetEndOfString (PnpId) + 1;
  276. }
  277. } else {
  278. DEBUGMSG ((
  279. DBG_HWDISK,
  280. "Can't get PNP ID for line in [%s] of %s",
  281. Manufacturer,
  282. SourceInfSpec
  283. ));
  284. }
  285. } while (InfFindNextLine (&isMfg));
  286. } else {
  287. DEBUGMSG ((DBG_HWDISK, "INF %s does not have [%s]", Manufacturer));
  288. }
  289. } while (InfFindNextLine (&is));
  290. } else {
  291. DEBUGMSG ((DBG_HWDISK, "INF %s does not have [%s]", SourceInfSpec, S_MANUFACTURER));
  292. __leave;
  293. }
  294. //
  295. // If we have at least one PNP ID, process the install section
  296. //
  297. if (HaveOneId) {
  298. //
  299. // Create the working directory
  300. //
  301. CreateDirectory (DestDir, NULL);
  302. _tcssafecpy (DestDirCreated, DestDir, MAX_TCHAR_PATH);
  303. DestInfSpec = JoinPaths (DestDir, GetFileNameFromPath (SourceInfSpec));
  304. if (!CopyFile (SourceInfSpec, DestInfSpec, TRUE)) {
  305. LOG ((LOG_ERROR, "Could not copy %s to %s", SourceInfSpec, DestInfSpec));
  306. __leave;
  307. }
  308. //
  309. // Ignore the driver if all matching IDs are in either PrevSuppliedIdTable
  310. // or SuppliedIdTable. This causes only the first instance of the driver
  311. // to be used.
  312. //
  313. Count = GrowListGetSize (&MatchingPnpIds);
  314. NeedThisDriver = FALSE;
  315. for (u = 0 ; u < Count ; u++) {
  316. ListPnpId = (PTSTR) GrowListGetString (&MatchingPnpIds, u);
  317. if (!HtFindString (PrevSuppliedIdTable, ListPnpId)) {
  318. //
  319. // Not in PrevSuppliedIdTable; check SuppliedIdTable
  320. //
  321. if (!HtFindString (SuppliedIdTable, ListPnpId)) {
  322. //
  323. // Not in either table, so we need this driver. Add PNP ID to
  324. // answer file and set flag to copy driver files.
  325. //
  326. NeedThisDriver = TRUE;
  327. }
  328. }
  329. }
  330. if (!NeedThisDriver) {
  331. DEBUGMSG ((
  332. DBG_HWDISK,
  333. "Driver skipped (%s) because all devices are compatible already",
  334. SourceInfSpec
  335. ));
  336. __leave;
  337. }
  338. //
  339. // Enumerate the string table of installed sections,
  340. // copying all the files they reference.
  341. //
  342. CopyParams.Inf = Inf;
  343. CopyParams.LayoutInf = LayoutInf;
  344. CopyParams.WorkingDlg = WorkingDlg;
  345. CopyParams.CancelEvent = CancelEvent;
  346. CopyParams.BaseDir = SourceInfDir;
  347. CopyParams.DestDir = DestDir;
  348. CopyParams.ResultCode = ERROR_SUCCESS;
  349. EnumHashTableWithCallback (
  350. InstallSectionsTable,
  351. pInstallSectionCallback,
  352. (LPARAM) &CopyParams
  353. );
  354. //
  355. // If enumeration fails, we return the error code to the
  356. // caller.
  357. //
  358. if (CopyParams.ResultCode != ERROR_SUCCESS) {
  359. SetLastError (CopyParams.ResultCode);
  360. DEBUGMSG ((DBG_HWDISK, "Error processing an install section"));
  361. __leave;
  362. }
  363. //
  364. // Copy CatalogFile setting, if it exists
  365. //
  366. if (InfFindFirstLine (Inf, S_VERSION, S_CATALOGFILE, &isFile)) {
  367. do {
  368. FileName = InfGetStringField (&isFile, 1);
  369. if (FileName) {
  370. SourcePath = JoinPaths (SourceInfDir, FileName);
  371. DestPath = JoinPaths (DestDir, FileName);
  372. SubResult = FALSE;
  373. if (SourcePath && DestPath) {
  374. SubResult = CopyFile (SourcePath, DestPath, TRUE);
  375. }
  376. PushError();
  377. FreePathString (SourcePath);
  378. FreePathString (DestPath);
  379. PopError();
  380. if (!SubResult) {
  381. LOG ((
  382. LOG_ERROR,
  383. "Could not copy %s to %s (catalog file)",
  384. SourcePath,
  385. DestPath
  386. ));
  387. __leave;
  388. }
  389. }
  390. } while (InfFindNextLine (&isFile));
  391. }
  392. //
  393. // Everything was copied fine; stick all matching IDs in
  394. // SuppliedIdTable
  395. //
  396. for (u = 0 ; u < Count ; u++) {
  397. ListPnpId = (PTSTR) GrowListGetString (&MatchingPnpIds, u);
  398. if (!HtAddString (SuppliedIdTable, ListPnpId)) {
  399. DEBUGMSG ((
  400. DBG_WARNING,
  401. "CopyDriverFilesToTempDir: Error adding %s to "
  402. "supported ID string table",
  403. ListPnpId
  404. ));
  405. }
  406. InfLine = WriteInfKeyEx (
  407. S_DEVICE_DRIVERS,
  408. ListPnpId,
  409. DestInfSpec,
  410. 0,
  411. FALSE
  412. );
  413. if (InfLine) {
  414. InfLine = WriteInfKeyEx (
  415. S_DEVICE_DRIVERS,
  416. ListPnpId,
  417. OriginalInstallPath,
  418. InfLine,
  419. FALSE
  420. );
  421. }
  422. if (!InfLine) {
  423. LOG ((LOG_ERROR, "Can't write answer file key"));
  424. __leave;
  425. }
  426. }
  427. }
  428. Result = TRUE;
  429. }
  430. __finally {
  431. PushError();
  432. InfCloseInfFile (Inf);
  433. InfCleanUpInfStruct (&is);
  434. InfCleanUpInfStruct (&isMfg);
  435. InfCleanUpInfStruct (&isFile);
  436. if (LayoutInf) {
  437. InfCloseInfFile (LayoutInf);
  438. LayoutInf = NULL;
  439. }
  440. if (InstallSectionsTable) {
  441. HtFree (InstallSectionsTable);
  442. }
  443. FreePathString (DestDir);
  444. FreePathString (DestInfSpec);
  445. PopError();
  446. }
  447. return Result && HaveOneId;
  448. }
  449. BOOL
  450. pCopyDriverFileWorker (
  451. IN HINF LayoutInf, OPTIONAL
  452. IN PCTSTR BaseDir,
  453. IN PCTSTR DestDir,
  454. IN PCTSTR FileName,
  455. IN HANDLE CancelEvent OPTIONAL
  456. )
  457. /*++
  458. Routine Description:
  459. pCopyDriverFileWorker copies driver files to a temporary directory. It
  460. copies a single file, and copies the compressed version if it exists.
  461. Arguments:
  462. LayoutInf - Specifies the handle to NT's layout.inf, used to tell if
  463. the source file comes from NT or not
  464. BaseDir - Specifies the base directory of the driver media (i.e.,
  465. a:\i386)
  466. DestDir - Specifies the destination directory (i.e.,
  467. c:\windows\setup\driver.001)
  468. FileName - Specifies the file to copy.
  469. CancelEvent - Specifies the handle to the UI cancel event (set when the
  470. user clicks cancel)
  471. Return Value:
  472. TRUE if the copy was successful, FALSE if not.
  473. --*/
  474. {
  475. PCTSTR SourceName = NULL;
  476. PCTSTR DestName = NULL;
  477. PTSTR p;
  478. BOOL b = FALSE;
  479. TCHAR FileNameCopy[MAX_TCHAR_PATH];
  480. LONG rc;
  481. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  482. StringCopy (FileNameCopy, FileName);
  483. if (CancelEvent &&
  484. WAIT_OBJECT_0 == WaitForSingleObject (CancelEvent, 0)
  485. ) {
  486. SetLastError (ERROR_CANCELLED);
  487. return FALSE;
  488. }
  489. __try {
  490. SourceName = JoinPaths (BaseDir, FileNameCopy);
  491. //
  492. // If file does not exist, then try with trailing underscore
  493. //
  494. if (!DoesFileExist (SourceName)) {
  495. p = GetEndOfString (SourceName);
  496. p = _tcsdec2 (SourceName, p);
  497. if (p) {
  498. *p = TEXT('_');
  499. p = _tcsinc (p);
  500. *p = 0;
  501. }
  502. #ifdef PRESERVE_COMPRESSED_FILES
  503. p = GetEndOfString (FileNameCopy);
  504. p = _tcsdec2 (FileNameCopy, p);
  505. if (p) {
  506. *p = TEXT('_');
  507. p = _tcsinc (p);
  508. *p = 0;
  509. }
  510. #endif
  511. }
  512. DestName = JoinPaths (DestDir, FileNameCopy);
  513. #ifdef PRESERVE_COMPRESSED_FILES
  514. b = CopyFile (SourceName, DestName, TRUE);
  515. #else
  516. rc = SetupDecompressOrCopyFile (SourceName, DestName, 0);
  517. b = (rc == ERROR_SUCCESS);
  518. if (!b) {
  519. SetLastError (rc);
  520. }
  521. #endif
  522. if (!b) {
  523. //
  524. // Check layout.inf for this file
  525. //
  526. if (LayoutInf) {
  527. if (InfFindFirstLine (
  528. LayoutInf,
  529. S_SOURCEDISKSFILES,
  530. FileName,
  531. &is
  532. )) {
  533. b = TRUE;
  534. DEBUGMSG ((DBG_VERBOSE, "File %s is expected to be supplied by NT 5"));
  535. } else {
  536. LOG ((LOG_ERROR, "%s is not supplied by Windows XP", FileName));
  537. }
  538. InfCleanUpInfStruct (&is);
  539. } else {
  540. LOG ((LOG_ERROR, "Could not copy %s to %s", SourceName, DestName));
  541. }
  542. }
  543. }
  544. __finally {
  545. PushError();
  546. FreePathString (SourceName);
  547. FreePathString (DestName);
  548. PopError();
  549. }
  550. return b;
  551. }
  552. BOOL
  553. pCopyDriverFilesToTempDir (
  554. IN HINF Inf,
  555. IN HINF LayoutInf, OPTIONAL
  556. IN PCTSTR FileOrSection,
  557. IN PCTSTR BaseDir,
  558. IN PCTSTR DestDir,
  559. IN HANDLE CancelEvent OPTIONAL
  560. )
  561. /*++
  562. Routine Description:
  563. pCopyDriverFilesToTempDir parses the specified driver INF and copies all
  564. needed files to the specified destination. The cancel event allows UI to
  565. cancel the copy.
  566. Arguments:
  567. Inf - Specifies the handle to the driver INF
  568. LayoutInf - Specifies the handle to the NT layout INF, used to ignore copy
  569. errors for files that ship with the product
  570. FileOrSection - Specifies the file name or section name. File names begin
  571. with an @ symbol. This is the same way setupapi handles a
  572. FileCopy section.
  573. BaseDir - Specifies the media directory (i.e., a:\i386)
  574. DestDir - Specifies the setup temporary directory (i.e.,
  575. c:\windows\setup\driver.001)
  576. CancelEvent - Specifies the handle the an event that is set when the user
  577. cancels via UI.
  578. Return Value:
  579. TRUE if the copy was successful, or FALSE if a file could not be copied.
  580. --*/
  581. {
  582. PCTSTR FileName;
  583. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  584. BOOL b = FALSE;
  585. if (_tcsnextc (FileOrSection) == TEXT('@')) {
  586. //
  587. // FileOrSection is a file
  588. //
  589. b = pCopyDriverFileWorker (
  590. LayoutInf,
  591. BaseDir,
  592. DestDir,
  593. _tcsinc (FileOrSection),
  594. CancelEvent
  595. );
  596. } else {
  597. //
  598. // FileOrSection is a section
  599. //
  600. if (InfFindFirstLine (Inf, FileOrSection, NULL, &is)) {
  601. do {
  602. //
  603. // Each line in the section represents a file to be copied
  604. // to the DestDir
  605. //
  606. FileName = InfGetStringField (&is, 1);
  607. if (!FileName) {
  608. DEBUGMSG ((
  609. DBG_WARNING,
  610. "pCopyDriverFilesToTempDir: Error accessing %s",
  611. FileOrSection
  612. ));
  613. b = FALSE;
  614. } else {
  615. b = pCopyDriverFileWorker (
  616. LayoutInf,
  617. BaseDir,
  618. DestDir,
  619. FileName,
  620. CancelEvent
  621. );
  622. }
  623. } while (b && InfFindNextLine (&is));
  624. } else {
  625. DEBUGMSG ((
  626. DBG_WARNING,
  627. "pCopyDriverFilesToTempDir: %s is empty or does not exist",
  628. FileOrSection
  629. ));
  630. b = TRUE;
  631. }
  632. }
  633. InfCleanUpInfStruct (&is);
  634. return b;
  635. }
  636. BOOL
  637. pInstallSectionCallback (
  638. IN HASHTABLE Table,
  639. IN HASHITEM StringId,
  640. IN PCTSTR InstallSection,
  641. IN PVOID ExtraData,
  642. IN UINT ExtraDataSize,
  643. IN LPARAM lParam
  644. )
  645. /*++
  646. Routine Description:
  647. pInstallSectionCallback is called for each installation section specified
  648. in a driver INF. It does the same processing as the device installer
  649. routines in Setup API. It supports include= and needs= lines, and then
  650. enumerates the install section for ClassInstall and CopyFiles. When the
  651. routine completes, the entire install section, and an optional class
  652. installer, will be present in a temp dir on the system drive.
  653. Special attention is paid to the extensions on the section names. One
  654. section is processed, using the following precedence table:
  655. <section>.NTx86
  656. <section>.NT
  657. <section>
  658. Arguments:
  659. Table - Specifies the string table (unused)
  660. StringId - Specifies the ID of the string being enumerated (unused)
  661. InstallSection - Specifies the text of the install section as maintained by
  662. the string table
  663. ExtraData - Specifies extra data (unused)
  664. ExtraDataSize - Specifies the size of ExtraData (unused)
  665. lParam - Specifies copy parameters, receives
  666. Return Value:
  667. TRUE if the install section was processed properly, or FALSE if an error
  668. occurred.
  669. --*/
  670. {
  671. PCOPYPARAMS Params;
  672. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  673. GROWLIST SectionList = GROWLIST_INIT;
  674. PCTSTR Key;
  675. PCTSTR IncludedFile;
  676. PCTSTR NeededSection;
  677. PCTSTR CopyFiles;
  678. PCTSTR p;
  679. PCTSTR RealSection;
  680. PCTSTR Section;
  681. PCTSTR ClassInstall32;
  682. UINT Count;
  683. UINT u;
  684. BOOL b = FALSE;
  685. Params = (PCOPYPARAMS) lParam;
  686. //
  687. // Look for InstallSection.NTx86
  688. //
  689. RealSection = JoinText (InstallSection, TEXT(".NTx86"));
  690. if (!RealSection) {
  691. return FALSE;
  692. }
  693. if (!InfFindFirstLine (Params->Inf, RealSection, NULL, &is)) {
  694. FreeText (RealSection);
  695. RealSection = JoinText (InstallSection, TEXT(".NT"));
  696. if (!RealSection) {
  697. return FALSE;
  698. }
  699. if (!InfFindFirstLine (Params->Inf, RealSection, NULL, &is)) {
  700. RealSection = DuplicateText (InstallSection);
  701. if (!RealSection) {
  702. return FALSE;
  703. }
  704. }
  705. }
  706. __try {
  707. //
  708. // Put RealSection in grow list
  709. //
  710. if (!GrowListAppendString (&SectionList, RealSection)) {
  711. __leave;
  712. }
  713. //
  714. // Append-load layout.inf if necessary
  715. //
  716. InfOpenAppendInfFile (NULL, Params->Inf, NULL);
  717. //
  718. // Scan RealSection for include
  719. //
  720. if (InfFindFirstLine (Params->Inf, RealSection, TEXT("include"), &is)) {
  721. do {
  722. //
  723. // Verify key is "include"
  724. //
  725. MYASSERT (StringIMatch (InfGetStringField (&is, 0), TEXT("include")));
  726. //
  727. // Get include file name(s)
  728. //
  729. IncludedFile = InfGetMultiSzField (&is, 1);
  730. if (!IncludedFile) {
  731. LOG ((
  732. LOG_ERROR,
  733. "Include= syntax error in %s",
  734. RealSection
  735. ));
  736. __leave;
  737. }
  738. p = IncludedFile;
  739. while (*p) {
  740. //
  741. // Append-load the INF
  742. //
  743. if (!InfOpenAppendInfFile (IncludedFile, Params->Inf, NULL)) {
  744. LOG ((
  745. LOG_ERROR,
  746. "Cannot append-load %s",
  747. IncludedFile
  748. ));
  749. __leave;
  750. }
  751. p = GetEndOfString (p) + 1;
  752. }
  753. InfResetInfStruct (&is);
  754. } while (InfFindNextLine (&is));
  755. }
  756. //
  757. // Scan RealSection for needs=
  758. //
  759. if (InfFindFirstLine (Params->Inf, RealSection, TEXT("needs"), &is)) {
  760. do {
  761. //
  762. // Verify key is "needs"
  763. //
  764. MYASSERT (StringIMatch (InfGetStringField (&is, 0), TEXT("needs")));
  765. //
  766. // Get needed section name(s)
  767. //
  768. NeededSection = InfGetMultiSzField (&is, 1);
  769. if (!NeededSection) {
  770. LOG ((
  771. LOG_ERROR,
  772. "Needs= syntax error in %s",
  773. RealSection
  774. ));
  775. __leave;
  776. }
  777. p = NeededSection;
  778. while (*p) {
  779. //
  780. // Add sections to grow list
  781. //
  782. if (!GrowListAppendString (&SectionList, p)) {
  783. __leave;
  784. }
  785. p = GetEndOfString (p) + 1;
  786. }
  787. } while (InfFindNextLine (&is));
  788. }
  789. //
  790. // Scan for ClassInstall32.NTx86, ClassInstall32.NT or ClassInstall32,
  791. // and if found, add to section list.
  792. //
  793. ClassInstall32 = TEXT("ClassInstall32.NTx86");
  794. if (!InfFindFirstLine (Params->Inf, ClassInstall32, NULL, &is)) {
  795. ClassInstall32 = TEXT("ClassInstall32.NT");
  796. if (!InfFindFirstLine (Params->Inf, ClassInstall32, NULL, &is)) {
  797. ClassInstall32 = TEXT("ClassInstall32");
  798. if (!InfFindFirstLine (Params->Inf, ClassInstall32, NULL, &is)) {
  799. ClassInstall32 = NULL;
  800. }
  801. }
  802. }
  803. if (ClassInstall32) {
  804. GrowListAppendString (&SectionList, ClassInstall32);
  805. }
  806. //
  807. // Scan all sections in SectionList for CopyFiles
  808. //
  809. Count = GrowListGetSize (&SectionList);
  810. for (u = 0; u < Count ; u++) {
  811. Section = GrowListGetString (&SectionList, u);
  812. if (InfFindFirstLine (Params->Inf, Section, S_COPYFILES, &is)) {
  813. do {
  814. //
  815. // Verify key is "CopyFiles"
  816. //
  817. MYASSERT (StringIMatch (InfGetStringField (&is, 0), S_COPYFILES));
  818. //
  819. // Obtain list of copy files
  820. //
  821. CopyFiles = InfGetMultiSzField (&is, 1);
  822. if (!CopyFiles) {
  823. LOG ((
  824. LOG_ERROR,
  825. "CopyFile syntax error in %s",
  826. Section
  827. ));
  828. __leave;
  829. }
  830. p = CopyFiles;
  831. while (*p) {
  832. //
  833. // Copy these files to temporary dir
  834. //
  835. if (!pCopyDriverFilesToTempDir (
  836. Params->Inf,
  837. Params->LayoutInf,
  838. p,
  839. Params->BaseDir,
  840. Params->DestDir,
  841. Params->CancelEvent
  842. )) {
  843. Params->ResultCode = GetLastError();
  844. __leave;
  845. }
  846. p = GetEndOfString (p) + 1;
  847. }
  848. } while (InfFindNextLine (&is));
  849. }
  850. }
  851. b = TRUE;
  852. }
  853. __finally {
  854. PushError();
  855. FreeText (RealSection);
  856. InfCleanUpInfStruct (&is);
  857. FreeGrowList (&SectionList);
  858. PopError();
  859. }
  860. return b;
  861. }
  862. BOOL
  863. ScanPathForDrivers (
  864. IN HWND WorkingDlg, OPTIONAL
  865. IN PCTSTR SourceInfDir,
  866. IN PCTSTR TempDir,
  867. IN HANDLE CancelEvent OPTIONAL
  868. )
  869. /*++
  870. Routine Description:
  871. ScanPathForDrivers searches SourceInfDir for any file that ends in
  872. INF, and then examines the file to see if it supports any of the
  873. devices in g_NeededHardwareIds. If a driver is found for a device not
  874. already in g_UiSuppliedIds, the driver is copied to the local
  875. drive for setup in GUI mode.
  876. Arguments:
  877. WorkingDlg - Specifies the parent window for the driver copy
  878. animation dialog. If not specified, no copy
  879. dialog is displayed.
  880. SourceInfDir - Specifies full path to dir to scan
  881. TempDir - Specifies root path for device driver files. Subdirs
  882. will be created under TempDir for each device driver.
  883. CancelEvent - Specifies the event set by the UI when the user clicks
  884. Cancel
  885. Return Value:
  886. TRUE if one or more drivers were found and were copied to the local
  887. disk, or FALSE if either (A) no IDs were found or (B) an error occurred.
  888. Call GetLastError() for error details.
  889. --*/
  890. {
  891. GROWLIST DriverDirList = GROWLIST_INIT;
  892. GROWLIST InfFileList = GROWLIST_INIT;
  893. TREE_ENUM Tree;
  894. BOOL ContinueEnum = FALSE;
  895. HASHTABLE SuppliedIdTable = NULL;
  896. PCTSTR TempFile = NULL;
  897. PCTSTR FullInfPath;
  898. PCTSTR ActualInfDir;
  899. PCTSTR DriverDir;
  900. PTSTR p;
  901. TCHAR TmpFileName[32];
  902. TCHAR DestDir[MAX_TCHAR_PATH];
  903. DWORD rc;
  904. UINT Count;
  905. UINT u;
  906. BOOL b;
  907. BOOL OneFound = FALSE;
  908. PCTSTR FileName;
  909. BOOL Result = FALSE;
  910. __try {
  911. //
  912. // Create string table to hold PNP IDs until all drivers have been
  913. // copied correctly. Once everything is OK, we merge SuppliedIdTable
  914. // into g_UiSuppliedIds.
  915. //
  916. SuppliedIdTable = HtAlloc();
  917. if (!SuppliedIdTable) {
  918. __leave;
  919. }
  920. ContinueEnum = EnumFirstFileInTree (&Tree, SourceInfDir, TEXT("*.in?"), FALSE);
  921. while (ContinueEnum) {
  922. if (!Tree.Directory) {
  923. FullInfPath = Tree.FullPath;
  924. p = GetEndOfString (Tree.Name);
  925. MYASSERT(p);
  926. p = _tcsdec2 (Tree.Name, p);
  927. MYASSERT(p);
  928. ActualInfDir = SourceInfDir;
  929. if (_tcsnextc (p) == TEXT('_')) {
  930. Count = 0;
  931. b = TRUE;
  932. //
  933. // Prepare a temporary file name
  934. //
  935. do {
  936. Count++;
  937. if (Count > 1) {
  938. wsprintf (TmpFileName, TEXT("oem%05u.inf"), Count);
  939. } else {
  940. StringCopy (TmpFileName, TEXT("oemsetup.inf"));
  941. }
  942. TempFile = JoinPaths (g_TempDir, TmpFileName);
  943. if (DoesFileExist (TempFile)) {
  944. FreePathString (TempFile);
  945. TempFile = NULL;
  946. }
  947. } while (!TempFile);
  948. //
  949. // Abort on memory allocation error
  950. //
  951. if (!b) {
  952. OneFound = FALSE;
  953. break;
  954. }
  955. //
  956. // Decompress the file to temporary location
  957. //
  958. rc = SetupDecompressOrCopyFile (FullInfPath, TempFile, 0);
  959. //
  960. // Handle errors
  961. //
  962. if (rc != ERROR_SUCCESS) {
  963. LOG ((LOG_ERROR, "Could not decompress %s", FullInfPath));
  964. FreePathString (TempFile);
  965. TempFile = NULL;
  966. SetLastError(rc);
  967. OneFound = FALSE;
  968. break;
  969. }
  970. //
  971. // Now use TempFile instead of FullInfPath
  972. //
  973. FullInfPath = TempFile;
  974. }
  975. //
  976. // Now that we have the uncompressed INF, let's check to see if it
  977. // has needed driver files, and if the files can be copied to the
  978. // local disk.
  979. //
  980. b = CopyDriverFilesToTempDir (
  981. WorkingDlg,
  982. CancelEvent,
  983. ActualInfDir,
  984. FullInfPath,
  985. g_NeededHardwareIds,
  986. TempDir,
  987. g_UiSuppliedIds,
  988. SuppliedIdTable,
  989. DestDir,
  990. ActualInfDir
  991. );
  992. OneFound |= b;
  993. //
  994. // Clean up temporary INF file and add DestDir to grow list
  995. //
  996. PushError();
  997. if (TempFile == FullInfPath) {
  998. DeleteFile (FullInfPath);
  999. FreePathString (TempFile);
  1000. TempFile = NULL;
  1001. }
  1002. if (*DestDir) {
  1003. GrowListAppendString (&DriverDirList, DestDir);
  1004. FileName = GetFileNameFromPath (FullInfPath);
  1005. GrowListAppendString (&InfFileList, FileName);
  1006. }
  1007. PopError();
  1008. //
  1009. // Check for failure (such as disk full)
  1010. //
  1011. if (!b) {
  1012. rc = GetLastError();
  1013. if (rc != ERROR_SUCCESS &&
  1014. (rc & 0xe0000000) != 0xe0000000
  1015. ) {
  1016. OneFound = FALSE;
  1017. break;
  1018. }
  1019. }
  1020. if (CancelEvent &&
  1021. WAIT_OBJECT_0 == WaitForSingleObject (CancelEvent, 0)
  1022. ) {
  1023. SetLastError (ERROR_CANCELLED);
  1024. OneFound = FALSE;
  1025. break;
  1026. }
  1027. } else {
  1028. //
  1029. // Check for scary directories such as windir and get out!
  1030. //
  1031. if (StringIMatchCharCount (Tree.FullPath, g_WinDirWack, g_WinDirWackChars)) {
  1032. AbortEnumCurrentDir(&Tree);
  1033. }
  1034. }
  1035. ContinueEnum = EnumNextFileInTree (&Tree);
  1036. }
  1037. if (OneFound) {
  1038. //
  1039. // Copy SuppliedIdTable to g_UiSuppliedIds
  1040. //
  1041. if (!EnumHashTableWithCallback (
  1042. SuppliedIdTable,
  1043. pAddHashTable,
  1044. (LPARAM) g_UiSuppliedIds
  1045. )) {
  1046. DEBUGMSG ((DBG_HWDISK, "Error copying SuppliedIdTable to g_UiSuppliedIds"));
  1047. }
  1048. if (GetDriveType (SourceInfDir) == DRIVE_REMOVABLE) {
  1049. //
  1050. // If there is already a different removable drive
  1051. // used, eject the media.
  1052. //
  1053. EjectDriverMedia (FullInfPath);
  1054. g_EjectMedia = g_EjectMediaFileSpec;
  1055. StringCopy (g_EjectMediaFileSpec, FullInfPath);
  1056. }
  1057. } else {
  1058. PushError();
  1059. //
  1060. // Delete all dirs in DeviceDirList
  1061. //
  1062. Count = GrowListGetSize (&DriverDirList);
  1063. for (u = 0 ; u < Count ; u++) {
  1064. //
  1065. // Blow away the temporary driver dir
  1066. //
  1067. DriverDir = GrowListGetString (&DriverDirList, u);
  1068. DeleteDirectoryContents (DriverDir);
  1069. SetFileAttributes (DriverDir, FILE_ATTRIBUTE_NORMAL);
  1070. b = RemoveDirectory (DriverDir);
  1071. DEBUGMSG_IF ((
  1072. !b && DoesFileExist (DriverDir),
  1073. DBG_WARNING,
  1074. "Could not clean up %s",
  1075. DriverDir
  1076. ));
  1077. }
  1078. PopError();
  1079. }
  1080. Result = OneFound;
  1081. }
  1082. __finally {
  1083. PushError();
  1084. MYASSERT (!TempFile);
  1085. if (SuppliedIdTable) {
  1086. HtFree (SuppliedIdTable);
  1087. }
  1088. FreeGrowList (&DriverDirList);
  1089. FreeGrowList (&InfFileList);
  1090. if (ContinueEnum) {
  1091. AbortEnumFileInTree (&Tree);
  1092. }
  1093. PopError();
  1094. }
  1095. return Result;
  1096. }
  1097. BOOL
  1098. pAddHashTable (
  1099. IN HASHTABLE Table,
  1100. IN HASHITEM StringId,
  1101. IN PCTSTR String,
  1102. IN PVOID ExtraData,
  1103. IN UINT ExtraDataSize,
  1104. IN LPARAM lParam
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. pAddHashTable adds one string table to another. It is an enumeration
  1109. callback.
  1110. Arguments:
  1111. Table - Specifies the table being enumerated (unused)
  1112. StringId - Specifies the ID of the current string (unused)
  1113. String - Specifies the current string to be copied to the table
  1114. indicated by lParam.
  1115. ExtraData - Specifies extra data for the item being enumerated (unused)
  1116. ExtraDataSize - Specifies the size of ExtraData (unused)
  1117. lParam - Specifies the destination table
  1118. Return Value:
  1119. TRUE if successful, FALSE otherwise.
  1120. --*/
  1121. {
  1122. HASHTABLE DestTable;
  1123. DestTable = (HASHTABLE) lParam;
  1124. if (!HtAddString (DestTable, String)) {
  1125. DEBUGMSG ((DBG_ERROR, "pAddHashTable: Can't add to table 0x%X", DestTable));
  1126. return FALSE;
  1127. }
  1128. return TRUE;
  1129. }
  1130. BOOL
  1131. pEjectMedia (
  1132. IN UINT DriveNum // A == 0, B == 1, etc...
  1133. )
  1134. {
  1135. HANDLE VWin32Handle;
  1136. DIOC_REGISTERS reg;
  1137. BOOL Result;
  1138. DWORD DontCare;
  1139. BOOL b;
  1140. VWin32Handle = CreateFile(
  1141. TEXT("\\\\.\\vwin32"),
  1142. 0,
  1143. 0,
  1144. NULL,
  1145. 0,
  1146. FILE_FLAG_DELETE_ON_CLOSE,
  1147. NULL
  1148. );
  1149. if (VWin32Handle == INVALID_HANDLE_VALUE) {
  1150. MYASSERT (VWin32Handle != INVALID_HANDLE_VALUE);
  1151. return FALSE;
  1152. }
  1153. reg.reg_EAX = 0x440D; // IOCTL for block devices
  1154. reg.reg_EBX = DriveNum; // zero-based drive identifier
  1155. reg.reg_ECX = 0x0849; // Get Media ID command
  1156. reg.reg_Flags = 0x0001; // assume error (carry flag is set)
  1157. Result = DeviceIoControl (
  1158. VWin32Handle,
  1159. VWIN32_DIOC_DOS_IOCTL,
  1160. &reg,
  1161. sizeof(reg),
  1162. &reg,
  1163. sizeof(reg),
  1164. &DontCare,
  1165. 0
  1166. );
  1167. if (!Result || (reg.reg_Flags & 0x0001)) {
  1168. DEBUGMSG ((DBG_WARNING, "Eject Media: error code is 0x%02X", reg.reg_EAX));
  1169. b = FALSE;
  1170. } else {
  1171. b = TRUE;
  1172. }
  1173. CloseHandle (VWin32Handle);
  1174. return b;
  1175. }
  1176. BOOL
  1177. EjectDriverMedia (
  1178. IN PCSTR IgnoreMediaOnDrive OPTIONAL
  1179. )
  1180. {
  1181. PCTSTR ArgArray[1];
  1182. TCHAR DriveLetter[2];
  1183. if (g_EjectMedia) {
  1184. //
  1185. // If IgnoreMediaOnDrive is specified, then assume no media
  1186. // exists when it is on the drive specified.
  1187. //
  1188. if (IgnoreMediaOnDrive) {
  1189. if (IgnoreMediaOnDrive[0] == g_EjectMedia[0]) {
  1190. return TRUE;
  1191. }
  1192. }
  1193. //
  1194. // Attempt to eject the media automatically
  1195. //
  1196. if (!pEjectMedia (g_EjectMedia[0])) {
  1197. //
  1198. // Force user to eject the media
  1199. //
  1200. DriveLetter[0] = g_EjectMedia[0];
  1201. DriveLetter[1] = 0;
  1202. ArgArray[0] = DriveLetter;
  1203. while (DoesFileExist (g_EjectMedia)) {
  1204. ResourceMessageBox (
  1205. g_ParentWndAlwaysValid,
  1206. MSG_REMOVE_DRIVER_DISK,
  1207. MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND,
  1208. ArgArray
  1209. );
  1210. }
  1211. }
  1212. g_EjectMedia = NULL;
  1213. }
  1214. return g_EjectMedia != NULL;
  1215. }