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.

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