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.

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