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.

1385 lines
37 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include "sxs.h"
  4. BOOL ForceNTFSConversion;
  5. ULONG
  6. CheckRegKeyVolatility (
  7. IN HKEY Root,
  8. IN LPCTSTR KeyPath
  9. )
  10. {
  11. HKEY Key;
  12. HKEY TestKey;
  13. ULONG Error;
  14. PTSTR TestKeyName = TEXT( "$winnt32$_test" );
  15. DWORD Disposition;
  16. Error = RegOpenKeyEx( Root,
  17. KeyPath,
  18. 0,
  19. MAXIMUM_ALLOWED,
  20. &Key );
  21. if( Error != ERROR_SUCCESS ) {
  22. return ( Error );
  23. }
  24. Error = RegCreateKeyEx( Key,
  25. TestKeyName,
  26. 0,
  27. NULL,
  28. REG_OPTION_NON_VOLATILE,
  29. MAXIMUM_ALLOWED,
  30. NULL,
  31. &TestKey,
  32. &Disposition );
  33. if( Error == ERROR_SUCCESS ) {
  34. RegCloseKey( TestKey );
  35. RegDeleteKey( Key, TestKeyName );
  36. }
  37. RegCloseKey( Key );
  38. return( Error );
  39. }
  40. ULONG
  41. DumpRegKeyToInf(
  42. IN PINFFILEGEN InfContext,
  43. IN HKEY PredefinedKey,
  44. IN LPCTSTR FullKeyPath,
  45. IN BOOL DumpIfEmpty,
  46. IN BOOL DumpSubKeys,
  47. IN BOOL SetNoClobberFlag,
  48. IN BOOL DumpIfVolatileKey
  49. )
  50. {
  51. HKEY Key;
  52. ULONG Error;
  53. TCHAR SubKeyName[ MAX_PATH + 1 ];
  54. ULONG SubKeyNameLength;
  55. ULONG cSubKeys;
  56. ULONG cValues;
  57. ULONG MaxValueNameLength;
  58. ULONG MaxValueLength;
  59. LPTSTR ValueName;
  60. PBYTE ValueData;
  61. ULONG i;
  62. LPTSTR SubKeyFullPath;
  63. ULONG MaxSubKeyNameLength;
  64. //
  65. // Open the key for read access
  66. //
  67. Error = RegOpenKeyEx( PredefinedKey,
  68. FullKeyPath,
  69. 0,
  70. KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
  71. &Key );
  72. if( Error != ERROR_SUCCESS ) {
  73. //
  74. // If the key doesn't exist, than assume it got dumped.
  75. //
  76. return( ( Error == ERROR_PATH_NOT_FOUND )? ERROR_SUCCESS : Error );
  77. }
  78. //
  79. // Find out if the key is empty (has no subkeys, and no values)
  80. //
  81. Error = RegQueryInfoKey( Key,
  82. NULL,
  83. NULL,
  84. NULL,
  85. &cSubKeys,
  86. &MaxSubKeyNameLength,
  87. NULL,
  88. &cValues,
  89. &MaxValueNameLength,
  90. &MaxValueLength,
  91. NULL,
  92. NULL );
  93. if( Error != ERROR_SUCCESS ) {
  94. RegCloseKey( Key );
  95. return( Error );
  96. }
  97. if( !DumpIfEmpty && (cSubKeys == 0) && (cValues == 0) ) {
  98. RegCloseKey( Key );
  99. return( ERROR_SUCCESS );
  100. }
  101. if( !DumpIfVolatileKey ) {
  102. //
  103. // If we are not supposed to dump volatile keys, then check if the key is volatile.
  104. //
  105. Error = CheckRegKeyVolatility ( PredefinedKey,
  106. FullKeyPath );
  107. if( Error == ERROR_CHILD_MUST_BE_VOLATILE ) {
  108. //
  109. // The key is volatile, so skip it.
  110. //
  111. RegCloseKey( Key );
  112. return( ERROR_SUCCESS );
  113. } else if( Error != ERROR_SUCCESS ) {
  114. //
  115. // We don't knlw if the key is volatile or non-volatile.
  116. RegCloseKey( Key );
  117. return( Error );
  118. }
  119. }
  120. Error = InfRecordAddReg( InfContext,
  121. PredefinedKey,
  122. FullKeyPath,
  123. NULL,
  124. REG_NONE,
  125. NULL,
  126. 0,
  127. SetNoClobberFlag );
  128. if( Error != ERROR_SUCCESS ) {
  129. RegCloseKey( Key );
  130. return( Error );
  131. }
  132. if( cValues != 0 ) {
  133. ValueName = (LPTSTR)MALLOC( (MaxValueNameLength + 1)*sizeof(TCHAR) );
  134. if( !ValueName ) {
  135. return ERROR_OUTOFMEMORY;
  136. }
  137. ValueData = (PBYTE)MALLOC( MaxValueLength );
  138. if( !ValueData ) {
  139. FREE( ValueName );
  140. return ERROR_OUTOFMEMORY;
  141. }
  142. //
  143. // Dump the value entries
  144. //
  145. for( i = 0; i < cValues; i++ ) {
  146. ULONG ValueNameLength;
  147. ULONG ValueType;
  148. ULONG DataSize;
  149. ValueNameLength = MaxValueNameLength + 1;
  150. DataSize = MaxValueLength;
  151. Error = RegEnumValue( Key, // handle of key to query
  152. i,
  153. ValueName,
  154. &ValueNameLength,
  155. NULL,
  156. &ValueType,
  157. ValueData,
  158. &DataSize );
  159. if( Error != ERROR_SUCCESS ) {
  160. break;
  161. }
  162. Error = InfRecordAddReg( InfContext,
  163. PredefinedKey,
  164. FullKeyPath,
  165. ValueName,
  166. ValueType,
  167. ValueData,
  168. DataSize,
  169. SetNoClobberFlag );
  170. if( Error != ERROR_SUCCESS ) {
  171. break;
  172. }
  173. }
  174. FREE( ValueName );
  175. FREE( ValueData );
  176. if( Error != ERROR_SUCCESS ) {
  177. RegCloseKey( Key );
  178. return( Error );
  179. }
  180. }
  181. //
  182. // Check if subkeys neeed to be dumped
  183. //
  184. if( !DumpSubKeys || (cSubKeys == 0) ) {
  185. RegCloseKey( Key );
  186. return( ERROR_SUCCESS );
  187. }
  188. //
  189. // Dump the subkeys
  190. //
  191. SubKeyFullPath = (LPTSTR)MALLOC( (lstrlen(FullKeyPath) + 1 + MaxSubKeyNameLength + 1)*sizeof(TCHAR) );
  192. if( SubKeyFullPath == NULL ) {
  193. RegCloseKey( Key );
  194. return( ERROR_NOT_ENOUGH_MEMORY );
  195. }
  196. for( i = 0; i < cSubKeys; i++ ) {
  197. SubKeyNameLength = sizeof( SubKeyName )/sizeof( TCHAR );
  198. Error = RegEnumKeyEx( Key,
  199. i,
  200. SubKeyName,
  201. &SubKeyNameLength,
  202. NULL,
  203. NULL,
  204. NULL,
  205. NULL );
  206. if( Error != ERROR_SUCCESS ) {
  207. break;
  208. }
  209. lstrcpy( SubKeyFullPath, FullKeyPath );
  210. lstrcat( SubKeyFullPath, TEXT("\\") );
  211. lstrcat( SubKeyFullPath, SubKeyName );
  212. Error = DumpRegKeyToInf( InfContext,
  213. PredefinedKey,
  214. SubKeyFullPath,
  215. DumpIfEmpty,
  216. DumpSubKeys,
  217. SetNoClobberFlag,
  218. DumpIfVolatileKey);
  219. if( Error != ERROR_SUCCESS ) {
  220. break;
  221. }
  222. }
  223. FREE( SubKeyFullPath );
  224. RegCloseKey( Key );
  225. return( Error );
  226. }
  227. BOOL
  228. GetAndSaveNTFTInfo(
  229. IN HWND ParentWindow
  230. )
  231. {
  232. static BOOL Done = FALSE;
  233. HKEY Key;
  234. DWORD d;
  235. LONG l;
  236. TCHAR HiveName[MAX_PATH];
  237. PINFFILEGEN InfContext;
  238. LONG i;
  239. LPTSTR KeysToMigrate[] = {
  240. TEXT("SYSTEM\\DISK"),
  241. TEXT("SYSTEM\\MountedDevices")
  242. };
  243. if(Done) {
  244. return(TRUE);
  245. }
  246. Done = TRUE;
  247. //
  248. // Before we migrate the disk information, make the drive letters sticky.
  249. // This will ensure that the drive letters assigned during textmode setup
  250. // are consistent with the drive letters in the current system.
  251. //
  252. ForceStickyDriveLetters();
  253. //
  254. // Load up the setupreg.hiv hive.
  255. //
  256. if (!IsArc()) {
  257. #ifdef _X86_
  258. if(Floppyless) {
  259. lstrcpy(HiveName,LocalBootDirectory);
  260. } else {
  261. HiveName[0] = FirstFloppyDriveLetter;
  262. HiveName[1] = TEXT(':');
  263. HiveName[2] = 0;
  264. }
  265. #endif
  266. } else {
  267. lstrcpy(HiveName,LocalSourceWithPlatform);
  268. }
  269. l = InfStart( WINNT_MIGRATE_INF_FILE,
  270. HiveName,
  271. &InfContext);
  272. if(l != NO_ERROR) {
  273. MessageBoxFromMessageAndSystemError(
  274. ParentWindow,
  275. MSG_CANT_SAVE_FT_INFO,
  276. l,
  277. AppTitleStringId,
  278. MB_OK | MB_ICONERROR | MB_TASKMODAL
  279. );
  280. return(FALSE);
  281. }
  282. l = InfCreateSection( TEXT("Addreg"), &InfContext );
  283. if(l != NO_ERROR) {
  284. MessageBoxFromMessageAndSystemError(
  285. ParentWindow,
  286. MSG_CANT_SAVE_FT_INFO,
  287. l,
  288. AppTitleStringId,
  289. MB_OK | MB_ICONERROR | MB_TASKMODAL
  290. );
  291. return(FALSE);
  292. }
  293. //
  294. // Dump each key to MIGRATE.INF.
  295. //
  296. for( i = 0; i < sizeof(KeysToMigrate)/sizeof(LPTSTR); i++ ) {
  297. //
  298. // Check if the key exists
  299. //
  300. l = RegOpenKeyEx(
  301. HKEY_LOCAL_MACHINE,
  302. KeysToMigrate[i],
  303. 0,
  304. KEY_QUERY_VALUE,
  305. &Key
  306. );
  307. if(l != NO_ERROR) {
  308. if( l == ERROR_FILE_NOT_FOUND ) {
  309. //
  310. // The key does not exist.
  311. // This is OK, just continue the migration of other keys
  312. //
  313. continue;
  314. } else {
  315. //
  316. // The key exists but we cannot read it
  317. //
  318. MessageBoxFromMessageAndSystemError(
  319. ParentWindow,
  320. MSG_CANT_SAVE_FT_INFO,
  321. l,
  322. AppTitleStringId,
  323. MB_OK | MB_ICONERROR | MB_TASKMODAL
  324. );
  325. InfEnd( &InfContext );
  326. return(FALSE);
  327. }
  328. }
  329. RegCloseKey( Key );
  330. //
  331. // The key exists, so go ahead and dump it.
  332. //
  333. l = DumpRegKeyToInf( InfContext,
  334. HKEY_LOCAL_MACHINE,
  335. KeysToMigrate[i],
  336. FALSE,
  337. FALSE,
  338. FALSE,
  339. TRUE );
  340. if(l != NO_ERROR) {
  341. MessageBoxFromMessageAndSystemError(
  342. ParentWindow,
  343. MSG_CANT_SAVE_FT_INFO,
  344. l,
  345. AppTitleStringId,
  346. MB_OK | MB_ICONERROR | MB_TASKMODAL
  347. );
  348. InfEnd( &InfContext );
  349. return(FALSE);
  350. }
  351. }
  352. InfEnd( &InfContext );
  353. return(TRUE);
  354. }
  355. BOOL
  356. ForceBootFilesUncompressed(
  357. IN HWND ParentWindow,
  358. IN BOOL TellUserAboutError
  359. )
  360. /*++
  361. Routine Description:
  362. This routine ensures that critical boot files (ntldr and $ldr$ on x86)
  363. are uncompressed. On ARC we also make sure setupldr is uncompressed,
  364. even though this is not strictly necessary since the system partition
  365. is always supposed to be FAT, just in case.
  366. Arguments:
  367. ParentWindow - supplies window handle for window to act as parent/owner of
  368. any ui windows this routine may display
  369. TellUserAboutError - if TRUE and and an error occurs, the user will get
  370. an error message. Otherwise the routine does not tell the user
  371. about errors.
  372. Return Value:
  373. Boolean value indicating whether relevent files were processed
  374. successfully.
  375. --*/
  376. {
  377. TCHAR Filename[MAX_PATH];
  378. #if defined(REMOTE_BOOT)
  379. //
  380. // For remote boot, the loader is on the server, so we don't need to
  381. // worry about whether it's compressed.
  382. //
  383. if (RemoteBoot) {
  384. return(TRUE);
  385. }
  386. #endif // defined(REMOTE_BOOT)
  387. if (!IsArc()) {
  388. #ifdef _X86_
  389. //
  390. // File is NTLDR on BIOS, but don't do this unless we're
  391. // dealing with the floppyless case.
  392. //
  393. if(!MakeBootMedia || !Floppyless) {
  394. return(TRUE);
  395. }
  396. BuildSystemPartitionPathToFile (TEXT("NTLDR"), Filename, MAX_PATH);
  397. #endif // _X86_
  398. } else {
  399. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  400. BuildSystemPartitionPathToFile (SETUPLDR_FILENAME, Filename, MAX_PATH);
  401. #endif // UNICODE
  402. } // if (!IsArc())
  403. if(!ForceFileNoCompress(Filename)) {
  404. if(TellUserAboutError) {
  405. MessageBoxFromMessageAndSystemError(
  406. ParentWindow,
  407. MSG_BOOT_FILE_ERROR,
  408. GetLastError(),
  409. AppTitleStringId,
  410. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  411. Filename
  412. );
  413. }
  414. return(FALSE);
  415. }
  416. //
  417. // Also do $LDR$
  418. //
  419. if (!IsArc()) {
  420. #ifdef _X86_
  421. BuildSystemPartitionPathToFile (AUX_BS_NAME, Filename, MAX_PATH);
  422. if(!ForceFileNoCompress(Filename)) {
  423. if(TellUserAboutError) {
  424. MessageBoxFromMessageAndSystemError(
  425. ParentWindow,
  426. MSG_BOOT_FILE_ERROR,
  427. GetLastError(),
  428. AppTitleStringId,
  429. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  430. Filename
  431. );
  432. }
  433. return(FALSE);
  434. }
  435. #endif // _X86_
  436. } // if (!IsArc())
  437. return(TRUE);
  438. }
  439. BOOL
  440. InDriverCacheInf(
  441. IN PVOID InfHandle,
  442. IN PCTSTR FileName,
  443. OUT PTSTR DriverCabName, OPTIONAL
  444. IN DWORD BufferChars OPTIONAL
  445. )
  446. {
  447. PCTSTR SectionName;
  448. UINT i;
  449. if( !InfHandle ) {
  450. return( FALSE );
  451. }
  452. //
  453. // Now get the section names that we have to search.
  454. //
  455. i = 0;
  456. SectionName = InfGetFieldByKey (
  457. InfHandle,
  458. TEXT("Version"),
  459. TEXT("CabFiles"),
  460. i);
  461. if (SectionName) {
  462. //
  463. // Search the sections for our entry.
  464. //
  465. do {
  466. if( InfDoesEntryExistInSection(InfHandle, SectionName, FileName)){
  467. if (DriverCabName) {
  468. //
  469. // fill out the parameter
  470. //
  471. PCTSTR p = InfGetFieldByKey (
  472. InfHandle,
  473. TEXT("Cabs"),
  474. SectionName,
  475. 0
  476. );
  477. if (p) {
  478. lstrcpyn (DriverCabName, p, BufferChars);
  479. } else {
  480. *DriverCabName = 0;
  481. }
  482. }
  483. //
  484. // we found a match
  485. //
  486. return(TRUE);
  487. }
  488. i++;
  489. SectionName = InfGetFieldByKey (
  490. InfHandle,
  491. TEXT("Version"),
  492. TEXT("CabFiles"),
  493. i);
  494. } while ( SectionName);
  495. }
  496. //
  497. // If we get here, we didn't find a match.
  498. //
  499. return( FALSE );
  500. }
  501. BOOL
  502. CreatePrivateFilesInf(
  503. IN PCTSTR PrivatesDirectory,
  504. IN PCTSTR InfName)
  505. {
  506. TCHAR infPath[MAX_PATH];
  507. TCHAR DriverInfName[MAX_PATH];
  508. TCHAR Search[MAX_PATH];
  509. WIN32_FIND_DATA CurrentFileInfo;
  510. HANDLE CurrentFile;
  511. PVOID InfHandle;
  512. BOOL retval = FALSE;
  513. DWORD d;
  514. HANDLE hPrivateInfFile;
  515. DWORD dontcare = 0;
  516. PCSTR privates = "[Privates]\r\n";
  517. lstrcpy(infPath,LocalSourceWithPlatform);
  518. ConcatenatePaths( infPath, InfName, MAX_PATH);
  519. lstrcpy(Search, PrivatesDirectory);
  520. ConcatenatePaths( Search, TEXT("*"), MAX_PATH);
  521. lstrcpy(DriverInfName, NativeSourcePaths[0]);
  522. ConcatenatePaths( DriverInfName, DRVINDEX_INF, MAX_PATH);
  523. CurrentFile = FindFirstFile(Search,&CurrentFileInfo);
  524. if (CurrentFile == INVALID_HANDLE_VALUE) {
  525. goto e0;
  526. }
  527. d = LoadInfFile( DriverInfName, FALSE, &InfHandle );
  528. if (d != NO_ERROR) {
  529. goto e1;
  530. }
  531. WritePrivateProfileString(TEXT("Version"),
  532. TEXT("Signature"),
  533. TEXT("\"$Windows NT$\""),
  534. infPath);
  535. #ifdef _X86_
  536. WritePrivateProfileString(
  537. TEXT("DestinationDirs"),
  538. TEXT("Privates"),
  539. IsNEC98() ?
  540. TEXT("10,\"Driver Cache\\nec98\"") :
  541. TEXT("10,\"Driver Cache\\i386\""),
  542. infPath
  543. );
  544. #else
  545. WritePrivateProfileString(
  546. TEXT("DestinationDirs"),
  547. TEXT("Privates"),
  548. TEXT("10,\"Driver Cache\\ia64\""),
  549. infPath
  550. );
  551. #endif
  552. WritePrivateProfileString(TEXT("InstallSection"),
  553. TEXT("CopyFiles"),
  554. TEXT("Privates"),
  555. infPath);
  556. #ifndef UNICODE
  557. WritePrivateProfileString (NULL, NULL, NULL, infPath);
  558. #endif
  559. //
  560. // writeprivateprofilestring works for the above, but doesnt work for
  561. // adding files to the section, so we have to do it manually...yuck!
  562. //
  563. hPrivateInfFile = CreateFile(
  564. infPath,
  565. GENERIC_WRITE,
  566. FILE_SHARE_READ,
  567. NULL,
  568. OPEN_EXISTING,
  569. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  570. NULL
  571. );
  572. if (hPrivateInfFile == INVALID_HANDLE_VALUE) {
  573. goto e2;
  574. }
  575. //
  576. // seek to the end of the file so we don't overwrite everything we already
  577. // put in there
  578. //
  579. SetFilePointer(hPrivateInfFile,0,0,FILE_END);
  580. WriteFile(hPrivateInfFile,(LPCVOID)privates,lstrlenA(privates),&dontcare,NULL);
  581. do {
  582. if (InDriverCacheInf( InfHandle, CurrentFileInfo.cFileName, NULL, 0 )) {
  583. CHAR AnsiFile[MAX_PATH];
  584. DWORD Size;
  585. DWORD Written;
  586. #ifdef UNICODE
  587. WideCharToMultiByte(
  588. CP_ACP,
  589. 0,
  590. CurrentFileInfo.cFileName,
  591. -1,
  592. AnsiFile,
  593. sizeof(AnsiFile),
  594. NULL,
  595. NULL
  596. );
  597. #else
  598. lstrcpyn(AnsiFile,CurrentFileInfo.cFileName,sizeof(AnsiFile));
  599. #endif
  600. strcat(AnsiFile,"\r\n");
  601. WriteFile(hPrivateInfFile,AnsiFile,lstrlenA(AnsiFile),&Written,NULL);
  602. }
  603. } while ( FindNextFile(CurrentFile,&CurrentFileInfo) );
  604. CloseHandle(hPrivateInfFile);
  605. retval = TRUE;
  606. e2:
  607. UnloadInfFile( InfHandle );
  608. e1:
  609. FindClose( CurrentFile );
  610. e0:
  611. return(retval);
  612. }
  613. DWORD
  614. DoPostCopyingStuff(
  615. IN PVOID ThreadParam
  616. )
  617. /*++
  618. Routine Description:
  619. This routine performs actions that are done after copying has been
  620. finished. This includes
  621. - X86 boot stuff (boot.ini, boot code, etc)
  622. - Saving NTFT information into the setup hive
  623. - Forcing ntldr or setupldr to be uncompressed
  624. Arguments:
  625. Return Value:
  626. --*/
  627. {
  628. HANDLE ThreadHandle;
  629. DWORD ThreadId;
  630. BOOL b;
  631. //
  632. // Check to see if delta.cat was processed as a result of
  633. // /m so that we can write the "includecatalog = delta.cat"
  634. // to winnt.sif
  635. //
  636. if ((AlternateSourcePath[0] != UNICODE_NULL) && MakeLocalSource) {
  637. TCHAR Buff[MAX_PATH];
  638. LPCTSTR WinntSetupSection = WINNT_SETUPPARAMS;
  639. lstrcpy( Buff, LocalSourceWithPlatform );
  640. ConcatenatePaths( Buff, TEXT("delta.cat"), MAX_PATH);
  641. if( FileExists(Buff,NULL) ){
  642. // Write out entry into winnt.sif
  643. WritePrivateProfileString(WinntSetupSection,WINNT_S_INCLUDECATALOG,TEXT("delta.cat"),ActualParamFile);
  644. }
  645. //
  646. // also create an inf file for the files that were changed and copy it to the local source as well
  647. //
  648. CreatePrivateFilesInf(AlternateSourcePath, TEXT("delta.inf"));
  649. }
  650. #ifdef TEST_EXCEPTION
  651. DoException( 4);
  652. #endif
  653. //
  654. // ALWAYS do this, since the system might not boot otherwise.
  655. //
  656. if(b = ForceBootFilesUncompressed(ThreadParam,TRUE)) {
  657. //
  658. // In the BIOS case, lay boot code, munge boot.ini, etc.
  659. //
  660. if (!IsArc()) {
  661. #ifdef _X86_
  662. if(MakeBootMedia && Floppyless) {
  663. b = DoX86BootStuff(ThreadParam);
  664. }
  665. #endif // _X86_
  666. } // if (!IsArc())
  667. //
  668. // In the NT case, also save off disk information into
  669. // the tiny setup system hive. This is done on both clean
  670. // install and upgrade case, so that drive letters can be
  671. // preserved.
  672. // Drive letters should not be migrated on OEM preinstall case
  673. //
  674. if(ISNT() && !OemPreinstall
  675. #ifdef _X86_
  676. && MakeBootMedia
  677. #endif
  678. ) {
  679. if( !GetAndSaveNTFTInfo(ThreadParam) ) {
  680. b = FALSE;
  681. }
  682. }
  683. }
  684. {
  685. SXS_CHECK_LOCAL_SOURCE SxsCheckLocalSourceParameters = { 0 };
  686. SxsCheckLocalSourceParameters.ParentWindow = ThreadParam;
  687. if (!SxsCheckLocalSource(&SxsCheckLocalSourceParameters))
  688. {
  689. b = FALSE;
  690. }
  691. }
  692. PostMessage(ThreadParam,WMX_I_AM_DONE,b,0);
  693. return(b);
  694. }
  695. BOOL
  696. IsNTFSConversionRecommended(
  697. void
  698. )
  699. {
  700. if (UnattendedOperation) {
  701. return FALSE;
  702. }
  703. if (TYPICAL() || !ISNT()) {
  704. //
  705. // NTFS conversion is not recommended
  706. // for win9x upgrades or if the user chooses typical
  707. //
  708. return FALSE;
  709. }
  710. if (NTFSConversionChanged) {
  711. return ForceNTFSConversion;
  712. }
  713. return TRUE;
  714. }
  715. BOOL
  716. NTFSConvertWizPage(
  717. IN HWND hdlg,
  718. IN UINT msg,
  719. IN WPARAM wParam,
  720. IN LPARAM lParam
  721. )
  722. {
  723. PPAGE_RUNTIME_DATA WizPage = (PPAGE_RUNTIME_DATA)GetWindowLongPtr(hdlg,DWLP_USER);
  724. static BOOL bPainted = FALSE;
  725. switch(msg) {
  726. case WM_INITDIALOG:
  727. if (!UnattendedOperation) {
  728. CheckRadioButton( hdlg, IDOK, IDCANCEL, IsNTFSConversionRecommended() ? IDOK : IDCANCEL );
  729. if (TYPICAL())
  730. {
  731. ForceNTFSConversion = FALSE;
  732. }
  733. }
  734. break;
  735. case WM_CTLCOLORDLG:
  736. bPainted = TRUE;
  737. return FALSE;
  738. case WMX_ACTIVATEPAGE:
  739. if(wParam) {
  740. HCURSOR OldCursor;
  741. MSG msgTemp;
  742. TCHAR buf[MAX_PATH];
  743. //
  744. // don't activate the page in restart mode
  745. //
  746. if (Winnt32RestartedWithAF ()) {
  747. if (GetPrivateProfileString(
  748. WINNT_UNATTENDED,
  749. TEXT("ForceNTFSConversion"),
  750. TEXT(""),
  751. buf,
  752. sizeof(buf) / sizeof(TCHAR),
  753. g_DynUpdtStatus->RestartAnswerFile
  754. )) {
  755. ForceNTFSConversion = !lstrcmpi (buf, WINNT_A_YES);
  756. }
  757. return FALSE;
  758. }
  759. // Scanning for drives can take a bit of time, so we lets change
  760. // the cursor to let the user know this should take a while
  761. OldCursor = SetCursor(LoadCursor (NULL, IDC_WAIT));
  762. #ifdef _X86_
  763. //
  764. // Skip if this is a clean install from Win95 so that dual boot is safe
  765. //
  766. if( !Upgrade && !ISNT() ){
  767. SetCursor(OldCursor);
  768. return( FALSE );
  769. }
  770. //
  771. // We will skip this wizard page if in Win9x upgrade and Boot16 option is ON.
  772. //
  773. if (Upgrade && !ISNT() && (g_Boot16 == BOOT16_YES)) {
  774. SetCursor(OldCursor);
  775. return FALSE;
  776. }
  777. #endif
  778. //
  779. // We may not want to display this page under
  780. // certain circumstances.
  781. //
  782. if( ISNT() && Upgrade ) {
  783. TCHAR Text[MAX_PATH];
  784. //
  785. // We're on NT and we know where the %windir%
  786. // will be since we're doing an upgrade. Is
  787. // it on a partition that's already NTFS? If so,
  788. // don't bother with this page.
  789. //
  790. MyGetWindowsDirectory( Text, MAX_PATH );
  791. if( IsDriveNTFS( Text[0] ) ) {
  792. SetCursor(OldCursor);
  793. return FALSE;
  794. }
  795. if (IsArc()) {
  796. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  797. //
  798. // Let's also make sure we're not asking to
  799. // upgrade the system partition on ARC (which
  800. // must remain FAT).
  801. //
  802. MyGetWindowsDirectory( Text, MAX_PATH );
  803. if( SystemPartitionDriveLetter == Text[0] ) {
  804. SetCursor(OldCursor);
  805. return FALSE;
  806. }
  807. #endif // UNICODE
  808. } // if (IsArc())
  809. }
  810. //
  811. // Last, but not least, disallow the page if all partitions
  812. // are already NTFS...
  813. //
  814. if( ISNT() ) {
  815. BOOL AllNTFS = TRUE;
  816. TCHAR DriveLetter;
  817. for( DriveLetter = TEXT('A'); DriveLetter <= TEXT('Z'); DriveLetter++ ) {
  818. //
  819. // Skip the system partition drive on ARC
  820. //
  821. if( (IsArc() && (DriveLetter != SystemPartitionDriveLetter)) || !IsArc() ) {
  822. AllNTFS &= (
  823. //
  824. // Is the drive NTFS?
  825. //
  826. (IsDriveNTFS(DriveLetter)) ||
  827. //
  828. // If it's removable, don't even
  829. // consider it because we can't
  830. // install there anyway. This gets
  831. // around the problem where the
  832. // user has a CD in his CDROM drive
  833. // or has a floppy in his floppy drive
  834. // while we're doing this check.
  835. //
  836. (MyGetDriveType(DriveLetter) != DRIVE_FIXED) );
  837. }
  838. }
  839. if( AllNTFS ) {
  840. SetCursor(OldCursor);
  841. return FALSE;
  842. }
  843. }
  844. //
  845. // Activation.
  846. //
  847. //
  848. // WMX_VALIDATE will return TRUE if the page should be skipped,
  849. // that is if we are in unattended mode and the parameters are OK.
  850. //
  851. if (CallWindowProc ((WNDPROC)NTFSConvertWizPage, hdlg, WMX_VALIDATE, 0, 0)) {
  852. SetCursor(OldCursor);
  853. return FALSE;
  854. }
  855. // if we get this far, we want to empty the message cue, to make sure
  856. // that people will see this page, and not accidentally agree to
  857. // converting their drives because they were antsy
  858. while (PeekMessage(&msgTemp,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE));
  859. while (PeekMessage(&msgTemp,NULL,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE));
  860. SetCursor(OldCursor);
  861. }
  862. return TRUE;
  863. case WMX_VALIDATE:
  864. //
  865. // In the unattended case, this page might get reactivated because of an error,
  866. // in which case we don't want to automatically continue because we could
  867. // get into an infinite loop.
  868. //
  869. if(!WizPage->PerPageData) {
  870. WizPage->PerPageData = 1;
  871. if (((UnattendedOperation) && (!CancelPending)) ||
  872. (NTFSConversionChanged && (!CancelPending)) ||
  873. (TYPICAL() && (!CancelPending)) ) {
  874. return TRUE;
  875. }
  876. }
  877. else if (TYPICAL() && (!CancelPending))
  878. {
  879. // If WizPage->PerPageData == 1 we already ran through the above check.
  880. // and in the typical case we don't show the NTFS conversion page.
  881. // Anything wrong with the unattend value for NTFS would have been
  882. // cought the first time.
  883. return TRUE;
  884. }
  885. return FALSE;
  886. case WMX_NEXTBUTTON:
  887. // don't let the user choose next until we know the screen has been painted.
  888. if (!bPainted){
  889. // while we're here, empty the queue of mouse/key presses so we might not
  890. // have to follow this path again.
  891. MSG m;
  892. while (PeekMessage(&m,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE));
  893. while (PeekMessage(&m,NULL,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE));
  894. return FALSE;
  895. }
  896. if (IsDlgButtonChecked( hdlg, IDOK ) == BST_CHECKED) {
  897. ForceNTFSConversion = TRUE;
  898. } else {
  899. ForceNTFSConversion = FALSE;
  900. }
  901. return TRUE;
  902. default:
  903. break;
  904. }
  905. return FALSE;
  906. }
  907. UINT
  908. MyGetWindowsDirectory(
  909. LPTSTR MyBuffer,
  910. UINT Size
  911. )
  912. /*++
  913. Routine Description:
  914. Get the windows directory in a terminal-server-aware fashion.
  915. Arguments:
  916. MyBuffer - Holds the return string.
  917. Size - How big is the buffer?
  918. Return Value:
  919. length of the string we copied.
  920. --*/
  921. {
  922. HMODULE hModuleKernel32;
  923. FARPROC MyProc;
  924. UINT ReturnVal = 0;
  925. #if defined(UNICODE)
  926. if( ISNT() ) {
  927. //
  928. // We can't trust GetWindowsDirectory because Terminal Server may be
  929. // installed, so use GetSystemWindowsDirectory.
  930. //
  931. if( hModuleKernel32 = LoadLibrary( TEXT("kernel32") ) ) {
  932. if( MyProc = GetProcAddress(hModuleKernel32,"GetSystemWindowsDirectoryW")) {
  933. ReturnVal = (UINT)MyProc( MyBuffer, Size );
  934. }
  935. FreeLibrary(hModuleKernel32);
  936. }
  937. }
  938. #endif
  939. if( ReturnVal == 0 ) {
  940. ReturnVal = GetWindowsDirectory( MyBuffer, Size );
  941. }
  942. return ReturnVal;
  943. }
  944. //
  945. // Calc how fast setup can coyp files
  946. //
  947. #define BUFFER_SIZE 0x1000
  948. DWORD dwThroughPutSrcToDest;
  949. DWORD dwThroughPutHDToHD;
  950. DWORD GetThroughput(LPTSTR Source, LPTSTR Dest)
  951. {
  952. BYTE buffer[BUFFER_SIZE];
  953. HANDLE hFile = NULL;
  954. HANDLE hFileOut = NULL;
  955. DWORD bytes;
  956. DWORD written;
  957. DWORD size;
  958. DWORD ticks;
  959. ticks = GetTickCount();
  960. hFile = CreateFile(Source,
  961. GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  962. hFileOut = CreateFile(Dest,
  963. GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  964. size = 0;
  965. if ((hFile != INVALID_HANDLE_VALUE) && (hFileOut != INVALID_HANDLE_VALUE))
  966. {
  967. do
  968. {
  969. ReadFile(hFile, buffer, BUFFER_SIZE, &bytes, NULL);
  970. if (hFileOut)
  971. WriteFile(hFileOut, buffer, bytes, &written, NULL);
  972. size += bytes;
  973. } while (bytes == BUFFER_SIZE);
  974. CloseHandle(hFile);
  975. if (hFileOut)
  976. {
  977. FlushFileBuffers(hFileOut);
  978. CloseHandle(hFileOut);
  979. }
  980. ticks = (GetTickCount() - ticks);
  981. // If less then a second, assume 1 second.
  982. if (ticks == 0)
  983. {
  984. ticks = 1;
  985. }
  986. ticks = (size/ticks);
  987. }
  988. else
  989. {
  990. if (hFile != INVALID_HANDLE_VALUE)
  991. CloseHandle(hFile);
  992. if (hFileOut != INVALID_HANDLE_VALUE)
  993. CloseHandle(hFileOut);
  994. // Failed to open/create one of the files. Assume a through put of 5KB/msec
  995. ticks = DEFAULT_IO_THROUGHPUT;
  996. }
  997. return ticks;
  998. }
  999. // Copy txtsetup.sif from the sources to %windir%\$win_nt$.~ls
  1000. // and determine the throughput for this.
  1001. // Then copy txtsetup.sif in the local folder to testfile.000 and
  1002. // calc the throughput for that.
  1003. // Remove the folder.
  1004. void CalcThroughput()
  1005. {
  1006. TCHAR SrcFolder[MAX_PATH];
  1007. TCHAR DestFolder[MAX_PATH];
  1008. TCHAR Folder[MAX_PATH];
  1009. MyGetWindowsDirectory(Folder, sizeof(DestFolder)/sizeof(TCHAR));
  1010. // Only use the driver
  1011. Folder[3] = TEXT('\0');
  1012. ConcatenatePaths( Folder, LOCAL_SOURCE_DIR, MAX_PATH);
  1013. if (CreateMultiLevelDirectory(Folder) == NO_ERROR)
  1014. {
  1015. lstrcpy(DestFolder, Folder);
  1016. ConcatenatePaths( DestFolder, TEXTMODE_INF, MAX_PATH);
  1017. lstrcpy(SrcFolder, NativeSourcePaths[0]);
  1018. ConcatenatePaths( SrcFolder, TEXTMODE_INF, MAX_PATH);
  1019. dwThroughPutSrcToDest = GetThroughput(SrcFolder, DestFolder);
  1020. //
  1021. lstrcpy(SrcFolder, DestFolder);
  1022. lstrcpy(DestFolder, Folder);
  1023. ConcatenatePaths( DestFolder, TEXT("testfile.000"), MAX_PATH);
  1024. dwThroughPutHDToHD = GetThroughput(SrcFolder, DestFolder);
  1025. MyDelnode(Folder);
  1026. wsprintf(Folder, TEXT("SrcToDest: %d bytes/msec HDtoHD: %d bytes/msec"),dwThroughPutSrcToDest, dwThroughPutHDToHD);
  1027. DebugLog(Winnt32LogInformation,Folder,0 );
  1028. }
  1029. }
  1030. #ifdef UNICODE
  1031. #define NB10_SIG ((DWORD)'01BN')
  1032. #define RSDS_SIG ((DWORD)'SDSR')
  1033. typedef struct _NB10I // NB10 debug info
  1034. {
  1035. DWORD dwSig; // NB10
  1036. DWORD dwOffset; // offset, always 0
  1037. ULONG sig;
  1038. ULONG age;
  1039. char szPdb[_MAX_PATH];
  1040. } NB10I, *PNB10I;
  1041. typedef struct _NB10I_HEADER // NB10 debug info
  1042. {
  1043. DWORD dwSig; // NB10
  1044. DWORD dwOffset; // offset, always 0
  1045. ULONG sig;
  1046. ULONG age;
  1047. } NB10IH, *PNB10IH;
  1048. typedef struct _RSDSI // RSDS debug info
  1049. {
  1050. DWORD dwSig; // RSDS
  1051. GUID guidSig;
  1052. DWORD age;
  1053. char szPdb[_MAX_PATH * 3];
  1054. } RSDSI, *PRSDSI;
  1055. typedef struct _RSDSI_HEADER // RSDS debug info
  1056. {
  1057. DWORD dwSig; // RSDS
  1058. GUID guidSig;
  1059. DWORD age;
  1060. } RSDSIH, *PRSDSIH;
  1061. typedef union _CVDD
  1062. {
  1063. DWORD dwSig;
  1064. NB10I nb10i;
  1065. RSDSI rsdsi;
  1066. NB10IH nb10ih;
  1067. RSDSIH rsdsih;
  1068. } CVDD, *PCVDD;
  1069. BOOL
  1070. ExtractFileName(PCHAR pName, PCHAR pFileName)
  1071. {
  1072. // Extract the name part of the filename.
  1073. PCHAR pStartName, pEndName;
  1074. pEndName = pName + strlen(pName);
  1075. while ((*pEndName != '.') && (pEndName != pName)) {
  1076. pEndName--;
  1077. }
  1078. if (pEndName == pName) {
  1079. return FALSE;
  1080. }
  1081. // String consist of just '.' or no periods at all?
  1082. if ((pEndName == pName) ||
  1083. ((pEndName-1) == pName))
  1084. {
  1085. return FALSE;
  1086. }
  1087. pStartName = pEndName-1;
  1088. while ((*pStartName != '\\') && (pStartName != pName)) {
  1089. pStartName--;
  1090. }
  1091. // Found either the start of the string (filename.pdb) or the first backslash
  1092. // path\filename.pdb.
  1093. if (*pStartName == '\\')
  1094. pStartName++;
  1095. // Someone pass us \\.?
  1096. if (pStartName == pEndName) {
  1097. return FALSE;
  1098. }
  1099. CopyMemory(pFileName, pStartName, pEndName - pStartName);
  1100. return TRUE;
  1101. }
  1102. CHAR HalName[_MAX_FNAME];
  1103. PCHAR
  1104. FindRealHalName(TCHAR *pHalFileName)
  1105. {
  1106. HINSTANCE hHal = NULL;
  1107. PIMAGE_DEBUG_DIRECTORY pDebugData;
  1108. DWORD DebugSize, i;
  1109. BOOL NameFound = FALSE;
  1110. __try {
  1111. hHal = LoadLibraryEx(pHalFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
  1112. if (!hHal) {
  1113. __leave;
  1114. }
  1115. pDebugData = RtlImageDirectoryEntryToData(hHal, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugSize);
  1116. // verify we have debug data and it's a reasonable size.
  1117. if (!pDebugData ||
  1118. (DebugSize < sizeof(IMAGE_DEBUG_DIRECTORY)) ||
  1119. (DebugSize % sizeof(IMAGE_DEBUG_DIRECTORY)))
  1120. {
  1121. __leave;
  1122. }
  1123. ZeroMemory(HalName, sizeof(HalName));
  1124. // See if we have CV or MISC debug data.
  1125. for (i = 0; i < DebugSize/sizeof(IMAGE_DEBUG_DIRECTORY); i++) {
  1126. if (pDebugData->Type == IMAGE_DEBUG_TYPE_MISC) {
  1127. // Misc data.
  1128. PIMAGE_DEBUG_MISC pMisc = (PIMAGE_DEBUG_MISC)((PCHAR)(hHal) - 1 + pDebugData->AddressOfRawData);
  1129. PCHAR pName = pMisc->Data;
  1130. NameFound = ExtractFileName(pName, HalName);
  1131. __leave;
  1132. }
  1133. if (pDebugData->Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
  1134. // got cv, see if it's nb10 (pdb) or rsds (v7 pdb)
  1135. PCVDD pCodeView = (PCVDD)((PCHAR)(hHal) - 1 + pDebugData->AddressOfRawData);
  1136. if (pCodeView->dwSig == NB10_SIG) {
  1137. NameFound = ExtractFileName(pCodeView->nb10i.szPdb, HalName);
  1138. __leave;
  1139. }
  1140. if (pCodeView->dwSig == RSDS_SIG) {
  1141. NameFound = ExtractFileName(pCodeView->rsdsi.szPdb, HalName);
  1142. __leave;
  1143. }
  1144. }
  1145. }
  1146. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  1147. if (hHal) {
  1148. FreeLibrary(hHal);
  1149. }
  1150. if (NameFound) {
  1151. return HalName;
  1152. } else {
  1153. return NULL;
  1154. }
  1155. }
  1156. #endif