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.

1898 lines
53 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <bootfat.h>
  4. #include <bootf32.h>
  5. #include <boot98f.h>
  6. #include <boot98f2.h>
  7. #include <patchbc.h>
  8. //
  9. // Define name of file we use to contain the auxiliary boot sector.
  10. //
  11. #define AUX_BOOT_SECTOR_NAME_A "BOOTSECT.DAT"
  12. #define AUX_BOOT_SECTOR_NAME_W L"BOOTSECT.DAT"
  13. #ifdef UNICODE
  14. #define AUX_BOOT_SECTOR_NAME AUX_BOOT_SECTOR_NAME_W
  15. #else
  16. #define AUX_BOOT_SECTOR_NAME AUX_BOOT_SECTOR_NAME_A
  17. #endif
  18. BOOL CleanUpBootCode;
  19. DWORD CleanUpBootIni;
  20. BOOL
  21. HandleBootFilesWorker_NEC98(
  22. IN TCHAR *SourceDir,
  23. IN TCHAR *DestDir,
  24. IN PTSTR File,
  25. IN BOOL Flag
  26. );
  27. LONG
  28. CalcHiddenSector95(
  29. IN TCHAR DriveLetter
  30. );
  31. BOOL
  32. LoadBootIniString(
  33. IN HINSTANCE ModuleHandle,
  34. IN DWORD MsgId,
  35. OUT PSTR Buffer,
  36. IN DWORD Size
  37. );
  38. //
  39. //
  40. BOOL
  41. CheckSysPartAndReadBootCode(
  42. IN HWND ParentWindow,
  43. OUT WINNT32_SYSPART_FILESYSTEM *Filesystem,
  44. OUT BYTE BootCode[WINNT32_MAX_BOOT_SIZE],
  45. OUT PUINT BootCodeSectorCount
  46. )
  47. /*++
  48. Routine Description:
  49. This routine does some inspection on the x86 system partition
  50. to determine its filesystem and sector size. We only support
  51. 512-byte sectors, and there are code depedencies all over the place
  52. based on this.
  53. If the sector size is wrong or there's a filesystem we don't recognize
  54. then the user is informed.
  55. Arguments:
  56. ParentWindow - supplies window handle of window to be used as
  57. parent/owner in case this routine puts up UI.
  58. Filesystem - if successful, receives the filesystem of the system partition.
  59. BootCode - if successful, receives a copy of the boot code currently
  60. on the disk.
  61. BootCodeSectorCount - if successful, receives the size in 512-byte sectors
  62. of the boot code area for the filesystem on the system partition.
  63. Return Value:
  64. Boolean value indicating whether the system partition is acceptable.
  65. If not, the user will have been informed as to why.
  66. --*/
  67. {
  68. TCHAR DrivePath[4];
  69. DWORD DontCare;
  70. DWORD SectorSize;
  71. TCHAR NameBuffer[100];
  72. BOOL b;
  73. //
  74. // Form root path
  75. //
  76. DrivePath[0] = SystemPartitionDriveLetter;
  77. DrivePath[1] = TEXT(':');
  78. DrivePath[2] = TEXT('\\');
  79. DrivePath[3] = 0;
  80. //
  81. // Check sector size
  82. //
  83. if(!GetDiskFreeSpace(DrivePath,&DontCare,&SectorSize,&DontCare,&DontCare)
  84. || (SectorSize != WINNT32_SECTOR_SIZE)) {
  85. if (!(IsNEC98() && (SectorSize > WINNT32_SECTOR_SIZE))) {
  86. MessageBoxFromMessage(
  87. ParentWindow,
  88. MSG_UNSUPPORTED_SECTOR_SIZE,
  89. FALSE,
  90. AppTitleStringId,
  91. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  92. SystemPartitionDriveLetter
  93. );
  94. return(FALSE);
  95. }
  96. }
  97. //
  98. // Determine file system.
  99. //
  100. b = GetVolumeInformation(
  101. DrivePath,
  102. NULL,0, // don't care about volume name
  103. NULL, // ...or serial #
  104. &DontCare, // ...or max component length
  105. &DontCare, // ... or flags
  106. NameBuffer,
  107. sizeof(NameBuffer)/sizeof(TCHAR)
  108. );
  109. if(!b) {
  110. MessageBoxFromMessage(
  111. ParentWindow,
  112. MSG_UNKNOWN_FS,
  113. FALSE,
  114. AppTitleStringId,
  115. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  116. SystemPartitionDriveLetter
  117. );
  118. return(FALSE);
  119. }
  120. if(!lstrcmpi(NameBuffer,TEXT("NTFS"))) {
  121. *Filesystem = Winnt32FsNtfs;
  122. *BootCodeSectorCount = WINNT32_NTFS_BOOT_SECTOR_COUNT;
  123. b = ReadDiskSectors(
  124. SystemPartitionDriveLetter,
  125. 0,
  126. WINNT32_NTFS_BOOT_SECTOR_COUNT,
  127. WINNT32_SECTOR_SIZE,
  128. BootCode
  129. );
  130. if(!b) {
  131. MessageBoxFromMessage(
  132. ParentWindow,
  133. MSG_DASD_ACCESS_FAILURE,
  134. FALSE,
  135. AppTitleStringId,
  136. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  137. SystemPartitionDriveLetter
  138. );
  139. return(FALSE);
  140. }
  141. } else {
  142. if(!lstrcmpi(NameBuffer,TEXT("FAT")) || !lstrcmpi(NameBuffer,TEXT("FAT32"))) {
  143. //
  144. // Read 1 sector.
  145. //
  146. b = ReadDiskSectors(
  147. SystemPartitionDriveLetter,
  148. 0,
  149. WINNT32_FAT_BOOT_SECTOR_COUNT,
  150. WINNT32_SECTOR_SIZE,
  151. BootCode
  152. );
  153. if(!b) {
  154. MessageBoxFromMessage(
  155. ParentWindow,
  156. MSG_DASD_ACCESS_FAILURE,
  157. FALSE,
  158. AppTitleStringId,
  159. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  160. SystemPartitionDriveLetter
  161. );
  162. return(FALSE);
  163. }
  164. *Filesystem = NameBuffer[3] ? Winnt32FsFat32 : Winnt32FsFat;
  165. *BootCodeSectorCount = WINNT32_FAT_BOOT_SECTOR_COUNT;
  166. } else {
  167. MessageBoxFromMessage(
  168. ParentWindow,
  169. MSG_UNKNOWN_FS,
  170. FALSE,
  171. AppTitleStringId,
  172. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  173. SystemPartitionDriveLetter
  174. );
  175. return(FALSE);
  176. }
  177. }
  178. return(TRUE);
  179. }
  180. BOOL
  181. IsNtBootCode(
  182. IN WINNT32_SYSPART_FILESYSTEM Filesystem,
  183. IN LPBYTE BootCode
  184. )
  185. /*++
  186. Routine Description:
  187. Determine if boot code is for NT by examining the filesystem and
  188. the code itself, looking for the NTLDR string that must be present
  189. in all NT boot code.
  190. If the filesystem is NTFS then it's NT boot code.
  191. If not then we scan backwards in the boot sector looking for the
  192. NTLDR string.
  193. Arguments:
  194. Filesystem - supplies the filesystem on the drive.
  195. BootCode - supplies the boot code read from the drive. Only the first
  196. sector (512 bytes) are examined.
  197. Return Value:
  198. Boolean value indicating whether the boot code is for NT.
  199. There is no error return.
  200. --*/
  201. {
  202. UINT i;
  203. //
  204. // Because the last 2 bytes are the 55aa signature we can
  205. // skip them in the scan.
  206. //
  207. if(Filesystem == Winnt32FsNtfs) {
  208. return(TRUE);
  209. }
  210. for(i=WINNT32_SECTOR_SIZE-7; i>62; --i) {
  211. if(!memcmp("NTLDR",BootCode+i,5)) {
  212. return(TRUE);
  213. }
  214. }
  215. return(FALSE);
  216. }
  217. BOOL
  218. __inline
  219. WriteToBootIni(
  220. IN HANDLE Handle,
  221. IN PCHAR Line
  222. )
  223. {
  224. DWORD bw,l;
  225. l = lstrlenA(Line);
  226. return(WriteFile(Handle,Line,l,&bw,NULL) && (bw == l));
  227. }
  228. BOOL
  229. MungeBootIni(
  230. IN HWND ParentWindow,
  231. IN BOOL SetPreviousOs
  232. )
  233. {
  234. TCHAR BootIniName[16];
  235. TCHAR BootIniBackup[16];
  236. UCHAR BootSectorImageSpec[29];
  237. CHAR HeadlessRedirectSwitches[160];
  238. TCHAR ParamsFile[MAX_PATH];
  239. HANDLE h;
  240. DWORD BootIniSize;
  241. PUCHAR Buffer;
  242. PTCHAR DebugLogBuffer=NULL;
  243. DWORD BytesRead = 0;
  244. BOOL b;
  245. PUCHAR p,next;
  246. BOOL InOsSection;
  247. CHAR c;
  248. CHAR Text[256];
  249. DWORD OldAttributes;
  250. DWORD d;
  251. BOOL UpgradeOSPresent = FALSE;
  252. DWORD attribs;
  253. PUCHAR DefSwitches;
  254. PUCHAR DefSwEnd;
  255. UCHAR temp;
  256. //
  257. // Determine the size of boot.ini, allocate a buffer,
  258. // and read it in. If it isn't there then it will be created.
  259. //
  260. wsprintf(BootIniName,TEXT("%c:\\BOOT.INI"),SystemPartitionDriveLetter);
  261. wsprintf(BootIniBackup,TEXT("%c:\\BOOT.BAK"),SystemPartitionDriveLetter);
  262. h = CreateFile(BootIniName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
  263. if(h == INVALID_HANDLE_VALUE) {
  264. if ( Upgrade && ISNT() ) {
  265. // This is an error that the setup team should probably want
  266. // to look at. If we got this far, then there was a boot.ini
  267. // during pre-copy (look at InspectFileSystems for proof of
  268. // this), but one is missing after doing the copy.
  269. #ifdef PRERELEASE
  270. MessageBox(
  271. ParentWindow,
  272. TEXT("You have encountered a problem the setup team would like to look at.\n\nYou are missing a boot.ini file after the copy step (during MungeBootIni), but there was one much earlier in setup. Something happened between then and now that the setup team (mailto:setuphot) would like to know about."),
  273. TEXT("Winnt32"),
  274. MB_OK | MB_ICONERROR | MB_TASKMODAL);
  275. #else
  276. MessageBoxFromMessage(
  277. ParentWindow,
  278. MSG_UPGRADE_BOOT_INI_MUNGE_MISSING_BOOT_INI,
  279. FALSE,
  280. AppTitleStringId,
  281. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  282. BootIniName);
  283. #endif
  284. b = FALSE;
  285. d = GetLastError();
  286. goto c0;
  287. }
  288. //
  289. // Assume the file does not exist. Allocate a buffer large enough
  290. // to hold a single terminating nul byte.
  291. //
  292. BootIniSize = 0;
  293. Buffer = MALLOC(1);
  294. if(!Buffer) {
  295. b = FALSE;
  296. d = ERROR_NOT_ENOUGH_MEMORY;
  297. goto c0;
  298. }
  299. } else {
  300. //
  301. // Figure out how big the file is.
  302. // Allocate 3 extra characters for final NUL we'll add to make
  303. // parsing easier, and a cr/lf in case the last line is incomplete.
  304. //
  305. BootIniSize = GetFileSize(h,NULL);
  306. if(BootIniSize == (DWORD)(-1)) {
  307. d = GetLastError();
  308. CloseHandle(h);
  309. b = FALSE;
  310. goto c0;
  311. }
  312. Buffer = MALLOC(BootIniSize+3);
  313. DebugLogBuffer = MALLOC( (BootIniSize+3) * sizeof(TCHAR));
  314. if(!Buffer) {
  315. CloseHandle(h);
  316. b = FALSE;
  317. d = ERROR_NOT_ENOUGH_MEMORY;
  318. goto c0;
  319. }
  320. b = ReadFile(h,Buffer,BootIniSize,&BytesRead,NULL);
  321. d = GetLastError();
  322. CloseHandle(h);
  323. if( b && (BootIniSize != BytesRead) ){
  324. // Code to check if due to certain randomness we don't read everything and as a result
  325. // endup overwriting boot.ini
  326. DebugLog( Winnt32LogError, TEXT("Error: BOOT.INI wasn't read properly expected %1: read %2"), 0, BootIniSize, BytesRead);
  327. b = FALSE;
  328. }
  329. if( b && DebugLogBuffer ){
  330. // Log what we read
  331. #ifdef UNICODE
  332. MultiByteToWideChar(
  333. CP_ACP,
  334. 0,
  335. Buffer,
  336. BootIniSize,
  337. DebugLogBuffer,
  338. BootIniSize
  339. );
  340. #else
  341. memcpy( DebugLogBuffer, Buffer, BootIniSize*sizeof(TCHAR));
  342. #endif
  343. DebugLogBuffer[BootIniSize] = 0;
  344. DebugLog( Winnt32LogInformation, TEXT("BOOT.INI record - \n\n%1"), 0, DebugLogBuffer);
  345. }
  346. if(!b) {
  347. goto c1;
  348. }
  349. }
  350. //
  351. // Make sure the last line is properly terminated, and add a terminating nul
  352. // to make parsing a little easier.
  353. //
  354. if(BootIniSize && (Buffer[BootIniSize-1] != '\n') && (Buffer[BootIniSize-1] != '\r')) {
  355. Buffer[BootIniSize++] = '\r';
  356. Buffer[BootIniSize++] = '\n';
  357. }
  358. Buffer[BootIniSize] = 0;
  359. //
  360. // Truncate at control-z if any.
  361. //
  362. if(p = strchr(Buffer,26)) {
  363. if((p > Buffer) && (*(p - 1) != '\n') && (*(p - 1) != '\r')) {
  364. *(p++) = '\r';
  365. *(p++) = '\n';
  366. }
  367. *p = 0;
  368. BootIniSize = (DWORD)(p - Buffer);
  369. }
  370. //
  371. // Make sure we can write boot.ini, and make a backup copy.
  372. // (We do not procede unless we can make a backup copy.)
  373. // Then recreate boot.ini.
  374. //
  375. OldAttributes = GetFileAttributes(BootIniName);
  376. SetFileAttributes(BootIniBackup,FILE_ATTRIBUTE_NORMAL);
  377. if(OldAttributes == (DWORD)(-1)) {
  378. //
  379. // Boot.ini didn't exist before. Nothing to do.
  380. //
  381. } else {
  382. //
  383. // Make a backup copy.
  384. //
  385. if(CopyFile(BootIniName,BootIniBackup,FALSE)) {
  386. //
  387. // Attributes could be 0 but not -1. Adding 1 thus allows us to
  388. // use non-0 to mean that we have a backup file.
  389. //
  390. CleanUpBootIni = OldAttributes+1;
  391. } else {
  392. d = GetLastError();
  393. b = FALSE;
  394. goto c1;
  395. }
  396. }
  397. SetFileAttributes(BootIniName,FILE_ATTRIBUTE_NORMAL);
  398. h = CreateFile(
  399. BootIniName,
  400. GENERIC_WRITE,
  401. FILE_SHARE_READ,
  402. NULL,
  403. CREATE_ALWAYS,
  404. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  405. NULL
  406. );
  407. if(h == INVALID_HANDLE_VALUE) {
  408. d = GetLastError();
  409. b = FALSE;
  410. goto c2;
  411. }
  412. //
  413. // Regardless of the actual drive letter of the system partition,
  414. // the spec in boot.ini is always C:\...
  415. //
  416. wsprintfA(BootSectorImageSpec,"C:\\%hs\\%hs",LOCAL_BOOT_DIR_A,AUX_BOOT_SECTOR_NAME_A);
  417. //
  418. // Scan the Buffer to see if there is a DefSwitches line,
  419. // to move into new boot.ini in the [boot loader] section.
  420. // If no DefSwitches, just point to a null string to be moved.
  421. // Only process boot.ini up to [operating systems].
  422. //
  423. temp = '\0';
  424. DefSwitches = &temp;
  425. DefSwEnd = NULL;
  426. for(p=Buffer; *p && (p < Buffer+BootIniSize - (sizeof("[operating systems]")-1)); p++) {
  427. if(!_strnicmp(p,"DefSwitches",sizeof("DefSwitches")-1)) {
  428. DefSwEnd = strstr(p, "\n");
  429. if(DefSwEnd){
  430. DefSwEnd++;
  431. if(*DefSwEnd == '\r'){
  432. DefSwEnd++;
  433. }
  434. DefSwitches = p;
  435. temp = *DefSwEnd;
  436. *DefSwEnd = '\0';
  437. }
  438. break;
  439. } else {
  440. if(!_strnicmp(p,"[operating systems]",sizeof("[operating systems]")-1)) {
  441. break;
  442. }
  443. }
  444. }
  445. //
  446. // Take care of the headless setings.
  447. //
  448. HeadlessRedirectSwitches[0] = '\0';
  449. if( HeadlessSelection[0] != TEXT('\0') ) {
  450. //
  451. // They told winnt32.exe some specific headless settings.
  452. // Use these.
  453. //
  454. //
  455. // Convert the user's request into ASCII.
  456. //
  457. #ifdef UNICODE
  458. {
  459. CHAR tmp[80];
  460. WideCharToMultiByte( CP_ACP,
  461. 0,
  462. HeadlessSelection,
  463. -1,
  464. tmp,
  465. sizeof(tmp),
  466. NULL,
  467. NULL );
  468. wsprintfA( HeadlessRedirectSwitches,
  469. "redirect=%s\r\n",
  470. tmp );
  471. }
  472. #else
  473. wsprintfA( HeadlessRedirectSwitches,
  474. "redirect=%s\r\n",
  475. HeadlessSelection );
  476. #endif
  477. } else {
  478. //
  479. // They didn't give us any settings, so see if we can pick
  480. // something up from boot.ini
  481. //
  482. //
  483. // Parse through boot.ini, looking for any 'redirect=' lines.
  484. //
  485. for( p = Buffer; *p && (p < Buffer+BootIniSize - (sizeof("redirect=")-1)); p++ ) {
  486. if(!_strnicmp(p,"[Operat",sizeof("[Operat")-1)) {
  487. //
  488. // We're past the [Boot Loader] section. Stop looking.
  489. //
  490. break;
  491. }
  492. if(!_strnicmp(p,"redirect=",sizeof("redirect=")-1)) {
  493. PUCHAR q = p;
  494. UCHAR temp;
  495. while ((*p != '\r') && (*p != '\n') && *p) {
  496. p++;
  497. }
  498. temp = *p;
  499. *p = '\0';
  500. strcpy(HeadlessRedirectSwitches, q);
  501. //
  502. // We want to make sure that this setting gets put into
  503. // the unattend file too so that textmode will redirect.
  504. // We need to set the global 'HeadlessSelection' so that
  505. // he will get written to winnt.sif after this block.
  506. //
  507. #ifdef UNICODE
  508. MultiByteToWideChar( CP_ACP,
  509. MB_ERR_INVALID_CHARS,
  510. strchr(HeadlessRedirectSwitches, '=')+1,
  511. -1,
  512. HeadlessSelection,
  513. MAX_PATH );
  514. #else
  515. strcpy( HeadlessSelection, strchr(HeadlessRedirectSwitches, '=')+1 );
  516. #endif
  517. strcat(HeadlessRedirectSwitches, "\r\n" );
  518. *p = temp;
  519. }
  520. }
  521. }
  522. //
  523. // Now take care of the 'redirectbaudrate=X' setting.
  524. //
  525. if( HeadlessRedirectSwitches[0] != TEXT('\0') ) {
  526. //
  527. // We got got a direction to redirect. Now see about
  528. // the baudrate.
  529. //
  530. if( HeadlessBaudRate != 0 ) {
  531. CHAR MyHeadlessRedirectBaudRateLine[80] = {0};
  532. wsprintfA( MyHeadlessRedirectBaudRateLine,
  533. "redirectbaudrate=%d\r\n",
  534. HeadlessBaudRate );
  535. strcat( HeadlessRedirectSwitches, MyHeadlessRedirectBaudRateLine );
  536. } else {
  537. //
  538. // They didn't give us any settings, so see if we can pick
  539. // something up from boot.ini
  540. //
  541. //
  542. // Parse through boot.ini, looking for any 'redirectbaudrate=' lines.
  543. //
  544. for( p = Buffer; *p && (p < Buffer+BootIniSize - (sizeof("redirectbaudrate=")-1)); p++ ) {
  545. if(!_strnicmp(p,"[Operat",sizeof("[Operat")-1)) {
  546. //
  547. // We're past the [Boot Loader] section. Stop looking.
  548. //
  549. break;
  550. }
  551. if(!_strnicmp(p,"redirectbaudrate=",sizeof("redirectbaudrate=")-1)) {
  552. PUCHAR q = p;
  553. UCHAR temp;
  554. while ((*p != '\r') && (*p != '\n') && *p) {
  555. p++;
  556. }
  557. temp = *p;
  558. *p = '\0';
  559. strcat(HeadlessRedirectSwitches, q);
  560. strcat(HeadlessRedirectSwitches, "\r\n" );
  561. *p = temp;
  562. //
  563. // Now set the global HeadlessBaudRate variable so
  564. // we'll know what to write in winnt.sif when the time
  565. // comes.
  566. //
  567. p = strchr( q, '=' );
  568. if( p ) {
  569. p++;
  570. HeadlessBaudRate = atoi( p );
  571. }
  572. }
  573. }
  574. }
  575. }
  576. //
  577. // Now generate the name of the parameters file
  578. // and write our headless settings out.
  579. //
  580. BuildSystemPartitionPathToFile( LOCAL_BOOT_DIR,
  581. ParamsFile,
  582. MAX_PATH );
  583. ConcatenatePaths(ParamsFile,WINNT_SIF_FILE,MAX_PATH);
  584. WriteHeadlessParameters( ParamsFile );
  585. wsprintfA(
  586. Text,
  587. "[Boot Loader]\r\nTimeout=5\r\nDefault=%hs\r\n%hs[Operating Systems]\r\n",
  588. BootSectorImageSpec,
  589. HeadlessRedirectSwitches
  590. );
  591. //
  592. // If there were DefSwitches, set the Buffer back to original state
  593. //
  594. if(DefSwEnd){
  595. *DefSwEnd = temp;
  596. }
  597. if(!WriteToBootIni(h,Text)) {
  598. d = GetLastError();
  599. b = FALSE;
  600. DebugLog( Winnt32LogError, TEXT("Error: BOOT.INI wasn't written to properly : LastError - %1"), 0, d);
  601. goto c3;
  602. }
  603. //
  604. // Process each line in boot.ini.
  605. // If it's the setup boot sector line, we'll throw it out.
  606. // For comparison with lines in boot.ini, the drive letter
  607. // is always C even if the system partition is not actually C:.
  608. //
  609. InOsSection = FALSE;
  610. b = TRUE;
  611. for(p=Buffer; *p && b; p=next) {
  612. while((*p==' ') || (*p=='\t')) {
  613. p++;
  614. }
  615. if(*p) {
  616. //
  617. // Find first byte of next line.
  618. //
  619. for(next=p; *next && (*next++ != '\n'); );
  620. //
  621. // Look for start of [operating systems] section
  622. // or at each line in that section.
  623. //
  624. if(InOsSection) {
  625. switch(*p) {
  626. case '[': // end of section.
  627. *p=0; // force break out of loop
  628. break;
  629. case 'C':
  630. case 'c': // potential start of c:\ line
  631. //
  632. // See if it's a line for setup boot.
  633. // If so, ignore it.
  634. //
  635. if(!_strnicmp(p,BootSectorImageSpec,lstrlenA(BootSectorImageSpec))) {
  636. break;
  637. }
  638. //
  639. // If we're supposed to set the previous OS and this is
  640. // a line for the previous OS, ignore it.
  641. //
  642. if(SetPreviousOs && (p[1] == ':') && (p[2] == '\\')
  643. && ((p[3] == '=') || (p[3] == ' ') || (p[3] == '\t'))) {
  644. break;
  645. }
  646. //
  647. // Not a special line, FALL THROUGH to write it out as-is.
  648. //
  649. default:
  650. //
  651. // Random line. write it out.
  652. //
  653. if( Upgrade && ISNT() ){
  654. //
  655. //Check to make sure that in the NT upgrade case we atleast have one valid line
  656. //Using 4 chars as the check as at minimum a valid line should have x=y<CRLF>
  657. //
  658. if( (next - p ) > 4 )
  659. UpgradeOSPresent = TRUE;
  660. }
  661. c = *next;
  662. *next = 0;
  663. b = WriteToBootIni(h,p);
  664. *next = c;
  665. break;
  666. }
  667. } else {
  668. if(!_strnicmp(p,"[operating systems]",19)) {
  669. InOsSection = TRUE;
  670. }
  671. }
  672. }
  673. }
  674. if( ISNT() && Upgrade && !UpgradeOSPresent ){
  675. #ifdef PRERELEASE
  676. //On internal builds we want setuphot to be informed
  677. //when we encounter this
  678. MessageBox(
  679. ParentWindow,
  680. TEXT("You have encountered an error the Setup Team needs to investigate. Send email to SetupHot.(Boot Ini Error)"),
  681. TEXT("Winnt32"),
  682. MB_OK | MB_ICONERROR | MB_TASKMODAL
  683. );
  684. #endif
  685. b = FALSE;
  686. SetLastError( ERROR_INVALID_PARAMETER );
  687. }
  688. //
  689. // Write out our line.
  690. //
  691. if(b) {
  692. CHAR *AnsiStrs[] = {
  693. "Microsoft Windows XP 64-Bit Edition Version 2003 Setup",
  694. "Microsoft Windows Server 2003, Standard Edition Setup",
  695. "Microsoft Windows Server 2003, Enterprise Edition Setup",
  696. "Microsoft Windows Server 2003, Datacenter Edition Setup",
  697. "Microsoft Windows Server 2003, Web Edition Setup",
  698. "Microsoft Windows Server 2003 for Small Business Server Setup",
  699. "Microsoft Windows XP Setup"
  700. };
  701. DWORD Index = -1;
  702. if (!LoadBootIniString(hInst, AppTitleStringId, Text, sizeof(Text))) {
  703. switch (AppTitleStringId) {
  704. case IDS_APPTITLE_WKS:
  705. Index = 0;
  706. break;
  707. case IDS_APPTITLE_SRV:
  708. Index = 1;
  709. break;
  710. case IDS_APPTITLE_ASRV:
  711. Index = 2;
  712. break;
  713. case IDS_APPTITLE_DAT:
  714. Index = 3;
  715. break;
  716. case IDS_APPTITLE_BLADE:
  717. Index = 4;
  718. break;
  719. case IDS_APPTITLE_SBS:
  720. Index = 5;
  721. break;
  722. default:
  723. Index = 6;
  724. break;
  725. }
  726. strcpy(Text, AnsiStrs[Index]);
  727. }
  728. if((b=WriteToBootIni(h,BootSectorImageSpec))
  729. && (b=WriteToBootIni(h,"=\""))
  730. && (b=WriteToBootIni(h,Text))) {
  731. b = WriteToBootIni(h,"\"\r\n");
  732. }else{
  733. DebugLog( Winnt32LogError, TEXT("Error: Textmode line was not written properly to BOOT.INI"), 0);
  734. }
  735. }
  736. //
  737. // Write out previous OS line if directed to do so.
  738. //
  739. if(b && SetPreviousOs) {
  740. if(b = WriteToBootIni(h,"C:\\=\"")) {
  741. LoadStringA(hInst, Upgrade ? IDS_CANCEL_SETUP:IDS_MICROSOFT_WINDOWS,Text,sizeof(Text));
  742. if(b = WriteToBootIni(h,Text)) {
  743. b = WriteToBootIni(h,"\"\r\n");
  744. }
  745. }
  746. }
  747. if(!b) {
  748. d = GetLastError();
  749. goto c3;
  750. }
  751. d = NO_ERROR;
  752. c3:
  753. CloseHandle(h);
  754. c2:
  755. //
  756. // Restore boot.ini.
  757. //
  758. if(!b && (OldAttributes != (DWORD)(-1))) {
  759. SetFileAttributes(BootIniName,FILE_ATTRIBUTE_NORMAL);
  760. CopyFile(BootIniBackup,BootIniName,FALSE);
  761. SetFileAttributes(BootIniName,OldAttributes);
  762. SetFileAttributes(BootIniBackup,FILE_ATTRIBUTE_NORMAL);
  763. DeleteFile(BootIniBackup);
  764. DebugLog( Winnt32LogError, TEXT("Error processing boot.ini and restored"), 0);
  765. }
  766. c1:
  767. FREE(Buffer);
  768. c0:
  769. if(!b) {
  770. MessageBoxFromMessageAndSystemError(
  771. ParentWindow,
  772. MSG_BOOT_FILE_ERROR,
  773. d,
  774. AppTitleStringId,
  775. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  776. BootIniName
  777. );
  778. }
  779. return(b);
  780. }
  781. VOID
  782. MigrateBootIniData(
  783. VOID
  784. )
  785. {
  786. TCHAR BootIniName[16];
  787. //
  788. // Determine the size of boot.ini, allocate a buffer,
  789. // and read it in. If it isn't there then it will be created.
  790. //
  791. wsprintf(BootIniName,TEXT("%c:\\BOOT.INI"),SystemPartitionDriveLetter);
  792. GetPrivateProfileString(
  793. TEXT("Boot Loader"),
  794. TEXT("Timeout"),
  795. TEXT(""),
  796. Timeout,
  797. sizeof(Timeout)/sizeof(TCHAR),
  798. BootIniName);
  799. }
  800. BOOL
  801. LayNtBootCode(
  802. IN HWND ParentWindow,
  803. IN WINNT32_SYSPART_FILESYSTEM Filesystem,
  804. IN OUT LPBYTE BootCode
  805. )
  806. /*++
  807. Routine Description:
  808. Copy existing boot sector into bootsect.dos and lay down NT boot code.
  809. THIS ROUTINE DOES NOT CHECK THE EXISTING BOOT CODE. The caller must
  810. do that, and not call this routine if the existing boot code is
  811. already for NT. This routine should never be called for an NTFS drive
  812. since by definition that's NT boot code.
  813. Arguments:
  814. ParentWindow - supplies window handle of window to be used as
  815. owner/parent in case this routine puts up UI.
  816. Filesystem - supplies filesystem for system partition, as determined
  817. earlier by CheckSysPartAndReadBootCode(). Either Fat or Fat32.
  818. BootCode - on input, supplies copy of existing boot code read from
  819. the drive. On output, receives copy of new boot code that was
  820. was written to the drive.
  821. Return Value:
  822. Boolean value indicating outcome. If FALSE then the user will have been
  823. informed as to why.
  824. --*/
  825. {
  826. UINT i;
  827. HANDLE h;
  828. TCHAR FileName[] = TEXT("?:\\BOOTSECT.DOS");
  829. DWORD d;
  830. BOOL b = TRUE;
  831. //
  832. // Nt 3.51 will bugcheck here if they have an adaptec
  833. // 2940 card. Return if we're on 3.51. Note that
  834. // if any of the APIs fail, or anything goes wrong
  835. // in here, we just continue, assuming we're not
  836. // on NT 3.51.
  837. //
  838. if(!IsNEC98() && ISNT() && (BuildNumber <= NT351)) {
  839. return TRUE;
  840. }
  841. //
  842. // We may want to update the boot sector even if it
  843. // is NT boot code. In that case, we don't want to
  844. // go blast out a new bootsect.dos. Check first.
  845. //
  846. // If this process is called during /cmdcons,
  847. // the BOOTSECT.DOS should not be created on NEC98
  848. //
  849. if((IsNEC98() && !(BuildCmdcons)) || !(ISNT() || IsNtBootCode(Filesystem,BootCode)) ) {
  850. //
  851. // Write out existing boot sector to bootsect.dos.
  852. // We only move a single sector, which is correct in Fat
  853. // and Fat32 cases. The NT Fat32 boot code looks in sector
  854. // 12 for its second sector, so no special casing is required.
  855. //
  856. FileName[0] = SystemPartitionDriveLetter;
  857. SetFileAttributes(FileName,FILE_ATTRIBUTE_NORMAL);
  858. h = CreateFile(
  859. FileName,
  860. GENERIC_WRITE,
  861. FILE_SHARE_READ,
  862. NULL,
  863. CREATE_ALWAYS,
  864. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_SEQUENTIAL_SCAN,
  865. NULL
  866. );
  867. if(h == INVALID_HANDLE_VALUE) {
  868. MessageBoxFromMessageAndSystemError(
  869. ParentWindow,
  870. MSG_BOOT_FILE_ERROR,
  871. GetLastError(),
  872. AppTitleStringId,
  873. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  874. FileName
  875. );
  876. return(FALSE);
  877. }
  878. b = WriteFile(h,BootCode,WINNT32_SECTOR_SIZE,&d,NULL);
  879. d = GetLastError();
  880. CloseHandle(h);
  881. if(!b) {
  882. MessageBoxFromMessageAndSystemError(
  883. ParentWindow,
  884. MSG_BOOT_FILE_ERROR,
  885. d,
  886. AppTitleStringId,
  887. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  888. FileName
  889. );
  890. return(FALSE);
  891. }
  892. }
  893. //
  894. // While upgrading Win9X with FAT32 system partition installations,
  895. // update the BPB's heads value to reflect the actual value
  896. //
  897. if (!ISNT() && (Filesystem == Winnt32FsFat32)) {
  898. if (!PatchBootCode(Filesystem,
  899. SystemPartitionDriveLetter,
  900. (PUCHAR)BootCode,
  901. sizeof(Fat32BootCode))) {
  902. //
  903. // for failure case just log a winnt32.log error message
  904. // indicating the error
  905. //
  906. DebugLog(Winnt32LogError,
  907. TEXT("Could not update the FAT32 system partition's boot sector's\r\n")
  908. TEXT(" Bios Parameter Block's heads value"),
  909. 0);
  910. }
  911. }
  912. //
  913. // Now lay the NT code itself down onto the disk. We copy the non-BPB parts
  914. // of the appropriate template code into the caller's bootcode buffer.
  915. // Take advantage of the offset part of the jump instruction at the start
  916. // of the boot code (like eb 3c 90) to tell us where the BPB ends and
  917. // the code begins.
  918. //
  919. switch(Filesystem) {
  920. case Winnt32FsFat:
  921. {
  922. BYTE BootCodeBuffer[WINNT32_MAX_BOOT_SIZE];
  923. if (IsNEC98())
  924. {
  925. CopyMemory(BootCodeBuffer,PC98FatBootCode,sizeof(PC98FatBootCode));
  926. // NEC98 need set to HiddenSector(Bpb Index 0x011) value in BPB.
  927. // Hiddensector value is how many sectors from sector 0
  928. // This spec is NEC98 only.
  929. *(LONG *)&BootCodeBuffer[0x011 + 11]
  930. = CalcHiddenSector(SystemPartitionDriveLetter,
  931. *(SHORT *)&BootCodeBuffer[11]);
  932. } else {
  933. CopyMemory(BootCodeBuffer,FatBootCode,sizeof(FatBootCode));
  934. }
  935. CopyMemory(BootCode,BootCodeBuffer,3);
  936. CopyMemory(
  937. BootCode + BootCodeBuffer[1] + 2,
  938. BootCodeBuffer + BootCodeBuffer[1] + 2,
  939. WINNT32_SECTOR_SIZE - (BootCodeBuffer[1] + 2)
  940. );
  941. }
  942. break;
  943. case Winnt32FsFat32:
  944. //
  945. // In the FAT32 case we also lay down NT's second sector at sector 12.
  946. //
  947. {
  948. BYTE BootCodeBuffer[WINNT32_MAX_BOOT_SIZE];
  949. if (IsNEC98())
  950. {
  951. CopyMemory(BootCodeBuffer,PC98Fat32BootCode,sizeof(PC98Fat32BootCode));
  952. } else {
  953. CopyMemory(BootCodeBuffer,Fat32BootCode,sizeof(Fat32BootCode));
  954. }
  955. b = WriteDiskSectors( SystemPartitionDriveLetter,
  956. 12,
  957. 1,
  958. WINNT32_SECTOR_SIZE,
  959. BootCodeBuffer+1024 );
  960. if(b) {
  961. CopyMemory(BootCode,BootCodeBuffer,3);
  962. CopyMemory( BootCode + BootCodeBuffer[1] + 2,
  963. BootCodeBuffer + BootCodeBuffer[1] + 2,
  964. WINNT32_SECTOR_SIZE - (BootCodeBuffer[1] + 2) );
  965. }
  966. }
  967. break;
  968. default:
  969. //
  970. // We should never get here.
  971. //
  972. b = FALSE;
  973. break;
  974. }
  975. if(b) {
  976. b = WriteDiskSectors(
  977. SystemPartitionDriveLetter,
  978. 0,
  979. 1,
  980. WINNT32_SECTOR_SIZE,
  981. BootCode
  982. );
  983. if(b) {
  984. CleanUpBootCode = TRUE;
  985. }
  986. }
  987. if(!b) {
  988. MessageBoxFromMessage(
  989. ParentWindow,
  990. MSG_DASD_ACCESS_FAILURE,
  991. FALSE,
  992. AppTitleStringId,
  993. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  994. SystemPartitionDriveLetter
  995. );
  996. }
  997. return(b);
  998. }
  999. BOOL
  1000. CreateAuxiliaryBootSector(
  1001. IN HWND ParentWindow,
  1002. IN WINNT32_SYSPART_FILESYSTEM Filesystem,
  1003. IN LPBYTE BootCode,
  1004. IN UINT BootCodeSectorCount
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. When ntldr sees an entry in boot.ini that starts with the magic text "C:\"
  1009. it will look to see if the item specifies a filename, and if so it will
  1010. assume that the file is a boot sector, load it, and jump to it.
  1011. We place an entry in boot.ini for C:\$WIN_NT$.~BT\BOOTSECT.DAT, and place
  1012. our special boot sector(s) in that file. Our sector is special because it
  1013. loads $LDR$ instead of NTLDR, allowing us to boot into setup without
  1014. disturbing the "standard" ntldr-based boot.
  1015. This routine exmaines the boot code on the disk, changes NTLDR to $LDR$
  1016. and writes the result out to x:\$WIN_NT$.~BT\BOOTSECT.DAT.
  1017. This code assumes a sector size of 512 bytes.
  1018. Arguments:
  1019. ParentWindow - supplies a window handle for a window to act as parent/owner
  1020. for any ui that gets displayed by this routine.
  1021. Filesystem - supplies a value that indicates the filesystem on the
  1022. system partition.
  1023. BootCode - supplies a buffer containing a copy of the boot code that is
  1024. actually on the disk.
  1025. BootCodeSectorCount - supplies the number of sectors the boot code
  1026. occupies on-disk (and thus indicates the size of the BootCode buffer).
  1027. Return Value:
  1028. Boolean value indicating outcome. If FALSE, the user will have been
  1029. informed about why".
  1030. --*/
  1031. {
  1032. UINT i;
  1033. TCHAR NameBuffer[MAX_PATH];
  1034. HANDLE hFile;
  1035. BOOL b;
  1036. DWORD DontCare;
  1037. //
  1038. // Change NTLDR to $LDR$. NTFS stores it in unicode in its boot sector
  1039. // so 2 separate algorithms are needed.
  1040. //
  1041. if(Filesystem == Winnt32FsNtfs) {
  1042. for(i=1014; i>62; i-=2) {
  1043. if(!memcmp("N\000T\000L\000D\000R\000",BootCode+i,10)) {
  1044. //
  1045. // Do NOT use _lstrcpynW here since there is no
  1046. // way to get it to do the right thing without overwriting
  1047. // the word after $LDR$ with a terminating 0. Doing that
  1048. // breaks boot.
  1049. //
  1050. CopyMemory(BootCode+i,AUX_BS_NAME_W,10);
  1051. break;
  1052. }
  1053. }
  1054. } else {
  1055. for(i=505; i>62; --i) {
  1056. //
  1057. // Scan for full name with spaces so we don't find a boot message
  1058. // by accident.
  1059. //
  1060. if(!memcmp("NTLDR ",BootCode+i,11)) {
  1061. strncpy(BootCode+i,AUX_BS_NAME_A,5);
  1062. break;
  1063. }
  1064. }
  1065. }
  1066. //
  1067. // Form name of boot sector image file.
  1068. //
  1069. wsprintf(
  1070. NameBuffer,
  1071. TEXT("%c:\\%s\\%s"),
  1072. SystemPartitionDriveLetter,
  1073. LOCAL_BOOT_DIR,
  1074. AUX_BOOT_SECTOR_NAME
  1075. );
  1076. //
  1077. // Write boot sector image into file.
  1078. //
  1079. SetFileAttributes(NameBuffer,FILE_ATTRIBUTE_NORMAL);
  1080. hFile = CreateFile(NameBuffer,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
  1081. if(hFile == INVALID_HANDLE_VALUE) {
  1082. MessageBoxFromMessageAndSystemError(
  1083. ParentWindow,
  1084. MSG_BOOT_FILE_ERROR,
  1085. GetLastError(),
  1086. AppTitleStringId,
  1087. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1088. NameBuffer
  1089. );
  1090. return(FALSE);
  1091. }
  1092. //
  1093. // We have a timing bug that we're going to workaround for the
  1094. // time being...
  1095. //
  1096. i = 0;
  1097. b = FALSE;
  1098. while( (i < 10) && (b == FALSE) ) {
  1099. Sleep( 500 );
  1100. b = WriteFile(hFile,BootCode,BootCodeSectorCount*WINNT32_SECTOR_SIZE,&DontCare,NULL);
  1101. if( !b ) {
  1102. DontCare = GetLastError();
  1103. }
  1104. i++;
  1105. }
  1106. if(!b) {
  1107. MessageBoxFromMessageAndSystemError(
  1108. ParentWindow,
  1109. MSG_BOOT_FILE_ERROR,
  1110. DontCare,
  1111. AppTitleStringId,
  1112. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1113. NameBuffer
  1114. );
  1115. //
  1116. // Set this back before we ship Beta2!
  1117. // -matth
  1118. //
  1119. #if 1
  1120. //
  1121. // Now try again.
  1122. //
  1123. b = WriteFile(hFile,BootCode,BootCodeSectorCount*WINNT32_SECTOR_SIZE,&DontCare,NULL);
  1124. #endif
  1125. }
  1126. CloseHandle(hFile);
  1127. //
  1128. // Success if we get here.
  1129. //
  1130. return(b);
  1131. }
  1132. BOOL
  1133. DoX86BootStuff(
  1134. IN HWND ParentWindow
  1135. )
  1136. {
  1137. WINNT32_SYSPART_FILESYSTEM Filesystem;
  1138. BYTE BootCode[WINNT32_MAX_BOOT_SIZE];
  1139. UINT BootCodeSectorCount;
  1140. BOOL AlreadyNtBoot;
  1141. TCHAR Filename[13];
  1142. WIN32_FIND_DATA FindData;
  1143. HANDLE FindHandle;
  1144. BOOL b;
  1145. //
  1146. // On Win95, make sure we have NTLDR on the system partition,
  1147. // otherwise it makes no sense to lay NT boot code. This is
  1148. // a robustness thing to catch the case where an error occurred
  1149. // copying that file and the user skipped, etc. Otherwise we could
  1150. // end up getting the user into a situation where he can't boot.
  1151. //
  1152. if(!ISNT()) {
  1153. wsprintf(Filename,TEXT("%c:\\NTLDR"),SystemPartitionDriveLetter);
  1154. FindHandle = FindFirstFile(Filename,&FindData);
  1155. if(FindHandle == INVALID_HANDLE_VALUE) {
  1156. b = FALSE;
  1157. } else {
  1158. FindClose(FindHandle);
  1159. if((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || !FindData.nFileSizeLow) {
  1160. b = FALSE;
  1161. } else {
  1162. b = TRUE;
  1163. }
  1164. }
  1165. if(!b) {
  1166. MessageBoxFromMessage(
  1167. ParentWindow,
  1168. MSG_NTLDR_NOT_COPIED,
  1169. FALSE,
  1170. AppTitleStringId,
  1171. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1172. SystemPartitionDriveLetter
  1173. );
  1174. return(FALSE);
  1175. }
  1176. }
  1177. //
  1178. // Check out C:. Sector size must be 512 bytes and it has to be
  1179. // formatted in a filesystem we recognize -- FAT, FAT32, or NTFS
  1180. // (NT 3.51 also supported HPFS, but we assume we would not have
  1181. // gotten here if the drive is HPFS).
  1182. //
  1183. if(!CheckSysPartAndReadBootCode(ParentWindow,&Filesystem,BootCode,&BootCodeSectorCount)) {
  1184. return(FALSE);
  1185. }
  1186. //
  1187. // If we're running on Win95 check the existing boot code to see whether
  1188. // it's already for NT. If on NT assume the boot code is correct.
  1189. // That assumption could be bogus in some marginal cases (such as when
  1190. // the user boots from a floppy with ntldr on it and C: is corrupt
  1191. // or has been re-sys'ed, etc), but we ignore these issues.
  1192. //
  1193. AlreadyNtBoot = ISNT() ? TRUE : IsNtBootCode(Filesystem,BootCode);
  1194. //
  1195. // Munge boot.ini. We do this before laying NT boot code. If we did it
  1196. // afterwards and it failed, then the user could have NT boot code but no
  1197. // boot.ini, which would be bad news.
  1198. //
  1199. if(!MungeBootIni(ParentWindow,!AlreadyNtBoot)) {
  1200. return(FALSE);
  1201. }
  1202. //
  1203. // If BOOTSEC.DOS exist, We Need save BOOTSEC.DOS on NEC98 System.
  1204. //Some case, It is different to Now boot sector. It is created by
  1205. //NT4.
  1206. // NEC970725
  1207. // If this process is called during /cmdcons,
  1208. // the BOOTSECT.DOS should not be renamed "BOOTSECT.NEC" on NEC98
  1209. //
  1210. if (IsNEC98() && !(BuildCmdcons)){
  1211. TCHAR FileNameOld[16],FileNameNew[163];
  1212. FileNameOld[0] = FileNameNew[0] = SystemPartitionDriveLetter;
  1213. FileNameOld[1] = FileNameNew[1] = TEXT(':');
  1214. FileNameOld[2] = FileNameNew[2] = TEXT('\\');
  1215. lstrcpy(FileNameOld+3,TEXT("BOOTSECT.DOS"));
  1216. lstrcpy(FileNameNew+3,TEXT("BOOTSECT.NEC"));
  1217. SetFileAttributes(FileNameOld,FILE_ATTRIBUTE_NORMAL);
  1218. DeleteFile(FileNameNew);
  1219. MoveFile(FileNameOld, FileNameNew);
  1220. }
  1221. //
  1222. // If not already NT boot, copy existing boot code into bootsect.dos
  1223. // and lay down NT boot code.
  1224. //
  1225. // We're going to start writing new boot code if we're on anything
  1226. // but an NTFS drive.
  1227. //
  1228. if( (!AlreadyNtBoot) || (Filesystem != Winnt32FsNtfs) ) {
  1229. if( !LayNtBootCode(ParentWindow,Filesystem,BootCode) ) {
  1230. return(FALSE);
  1231. }
  1232. }
  1233. //
  1234. // Create the auxiliary boot code file, which is a copy of the NT
  1235. // boot code for the drive, with NTLDR changed to $LDR$.
  1236. //
  1237. if( (ForcedSystemPartition) &&
  1238. (UserSpecifiedLocalSourceDrive) &&
  1239. (ForcedSystemPartition == UserSpecifiedLocalSourceDrive) ) {
  1240. TCHAR FileNameOld[32],FileNameNew[32];
  1241. //
  1242. // The OEM is making a bootable disk with local source for a
  1243. // preinstall scenario. We can avoid any drive geometry dependence
  1244. // by simply booting the setupldr instead of using the ntldr->
  1245. // bootsect.dat->setupldr. To do this, we'll simply copy setupldr
  1246. // over ntldr. Note that we're removing his ability to boot anything
  1247. // other than textmode setup here, so be aware.
  1248. //
  1249. //
  1250. // Unlock ntldr.
  1251. //
  1252. FileNameOld[0] = FileNameNew[0] = ForcedSystemPartition;
  1253. FileNameOld[1] = FileNameNew[1] = TEXT(':');
  1254. FileNameOld[2] = FileNameNew[2] = TEXT('\\');
  1255. lstrcpy(FileNameOld+3,TEXT("$LDR$"));
  1256. lstrcpy(FileNameNew+3,TEXT("NTLDR"));
  1257. SetFileAttributes(FileNameNew,FILE_ATTRIBUTE_NORMAL);
  1258. //
  1259. // Move $LDR$ to NTLDR
  1260. //
  1261. DeleteFile(FileNameNew);
  1262. MoveFile(FileNameOld, FileNameNew);
  1263. } else {
  1264. if(!CreateAuxiliaryBootSector(ParentWindow,Filesystem,BootCode,BootCodeSectorCount)) {
  1265. return(FALSE);
  1266. }
  1267. }
  1268. return(TRUE);
  1269. }
  1270. BOOL
  1271. RestoreBootSector(
  1272. VOID
  1273. )
  1274. {
  1275. TCHAR Name[MAX_PATH];
  1276. BYTE Buffer[WINNT32_MAX_BOOT_SIZE];
  1277. DWORD BytesRead;
  1278. BOOL b;
  1279. HANDLE h;
  1280. //
  1281. // If we didn't get to the point of writing new boot code,
  1282. // then there's nothing to do.
  1283. //
  1284. if(!CleanUpBootCode) {
  1285. return(TRUE);
  1286. }
  1287. //
  1288. // Try to put bootsect.dos back onto the boot sector.
  1289. //
  1290. wsprintf(
  1291. Name,
  1292. TEXT("%c:\\%s\\BOOTSECT.DOS"),
  1293. SystemPartitionDriveLetter,
  1294. LOCAL_BOOT_DIR
  1295. );
  1296. h = CreateFile(Name,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
  1297. if(h == INVALID_HANDLE_VALUE) {
  1298. b = FALSE;
  1299. } else {
  1300. b = ReadFile(h,Buffer,WINNT32_SECTOR_SIZE,&BytesRead,NULL);
  1301. CloseHandle(h);
  1302. if(b) {
  1303. b = WriteDiskSectors(
  1304. SystemPartitionDriveLetter,
  1305. 0,
  1306. 1,
  1307. WINNT32_SECTOR_SIZE,
  1308. Buffer
  1309. );
  1310. if(b) {
  1311. //
  1312. // If this worked then we don't need ntldr, ntdetect.com, or boot.ini.
  1313. // If is possible that these files were there already before
  1314. // and we're thus "overcleaning" but we shouldn't get here
  1315. // unless we overwrote non-nt boot code with nt boot code.
  1316. // Thus putting back bootsect.dos restores non-NT boot code,
  1317. // so this shouldn't be too destructive.
  1318. //
  1319. Name[0] = SystemPartitionDriveLetter;
  1320. Name[1] = TEXT(':');
  1321. Name[2] = TEXT('\\');
  1322. lstrcpy(Name+3,TEXT("NTLDR"));
  1323. SetFileAttributes(Name,FILE_ATTRIBUTE_NORMAL);
  1324. DeleteFile(Name);
  1325. lstrcpy(Name+3,TEXT("NTDETECT.COM"));
  1326. SetFileAttributes(Name,FILE_ATTRIBUTE_NORMAL);
  1327. DeleteFile(Name);
  1328. wsprintf(Name+3,TEXT("BOOT.INI"));
  1329. SetFileAttributes(Name,FILE_ATTRIBUTE_NORMAL);
  1330. DeleteFile(Name);
  1331. }
  1332. }
  1333. }
  1334. return(b);
  1335. }
  1336. BOOL
  1337. RestoreBootIni(
  1338. VOID
  1339. )
  1340. {
  1341. BOOL b = TRUE;
  1342. TCHAR BootIniFile[12] = TEXT("X:\\BOOT.INI");
  1343. TCHAR BackupFile[12] = TEXT("X:\\BOOT.BAK");
  1344. if(CleanUpBootIni) {
  1345. CleanUpBootIni--;
  1346. BootIniFile[0] = SystemPartitionDriveLetter;
  1347. BackupFile[0] = SystemPartitionDriveLetter;
  1348. SetFileAttributes(BootIniFile,FILE_ATTRIBUTE_NORMAL);
  1349. if(CopyFile(BackupFile,BootIniFile,FALSE)) {
  1350. SetFileAttributes(BackupFile,FILE_ATTRIBUTE_NORMAL);
  1351. DeleteFile(BackupFile);
  1352. SetFileAttributes(BootIniFile,CleanUpBootIni);
  1353. } else {
  1354. b = FALSE;
  1355. }
  1356. }
  1357. return(b);
  1358. }
  1359. BOOL
  1360. SaveRestoreBootFiles_NEC98(
  1361. IN UCHAR Flag
  1362. )
  1363. {
  1364. PTSTR BackupFiles[] = { TEXT("\\BOOT.INI"),
  1365. TEXT("\\NTDETECT.COM"),
  1366. TEXT("\\NTLDR"),
  1367. NULL
  1368. };
  1369. PTSTR BackupFiles2[] = { TEXT("\\") AUX_BS_NAME, TEXT("\\") TEXTMODE_INF, NULL };
  1370. UINT i;
  1371. TCHAR SystemDir[3];
  1372. SystemDir[0] = SystemPartitionDriveLetter;
  1373. SystemDir[1] = TEXT(':');
  1374. SystemDir[2] = 0;
  1375. if (Flag == NEC98RESTOREBOOTFILES){
  1376. //
  1377. // Restore boot files.
  1378. //
  1379. for(i=0; BackupFiles[i] ; i++) {
  1380. HandleBootFilesWorker_NEC98(
  1381. LocalBackupDirectory,
  1382. SystemDir,
  1383. BackupFiles[i],
  1384. TRUE
  1385. );
  1386. }
  1387. //
  1388. // Delete tmp files.
  1389. //
  1390. for(i=0; BackupFiles2[i] ; i++) {
  1391. HandleBootFilesWorker_NEC98(
  1392. NULL,
  1393. SystemDir,
  1394. BackupFiles2[i],
  1395. FALSE
  1396. );
  1397. }
  1398. } else {
  1399. if (CreateDirectory(LocalBackupDirectory, NULL))
  1400. for (i = 0; BackupFiles[i] ; i++) {
  1401. HandleBootFilesWorker_NEC98(SystemDir,
  1402. LocalBackupDirectory,
  1403. BackupFiles[i],
  1404. TRUE);
  1405. }
  1406. }
  1407. return(TRUE);
  1408. }
  1409. BOOL
  1410. HandleBootFilesWorker_NEC98(
  1411. IN TCHAR *SourceDir,
  1412. IN TCHAR *DestDir,
  1413. IN PTSTR File,
  1414. IN BOOL Flag
  1415. )
  1416. {
  1417. TCHAR SourceFile[MAX_PATH];
  1418. TCHAR TargetFile[MAX_PATH];
  1419. DWORD OldAttributes;
  1420. if ((!DestDir) || ((!SourceDir)&&Flag)) {
  1421. return(FALSE);
  1422. }
  1423. lstrcpy(TargetFile, DestDir);
  1424. lstrcat(TargetFile, File);
  1425. if (SourceDir) {
  1426. lstrcpy(SourceFile, SourceDir);
  1427. lstrcat(SourceFile, File);
  1428. }
  1429. if (Flag) {
  1430. OldAttributes = GetFileAttributes(TargetFile);
  1431. SetFileAttributes(TargetFile,FILE_ATTRIBUTE_NORMAL);
  1432. if (!CopyFile(SourceFile,TargetFile,FALSE)) {
  1433. Sleep(500);
  1434. if (!CopyFile(SourceFile,TargetFile,FALSE)) {
  1435. return(FALSE);
  1436. }
  1437. }
  1438. if (OldAttributes != (DWORD)(-1)) {
  1439. SetFileAttributes(TargetFile,OldAttributes & ~FILE_ATTRIBUTE_COMPRESSED);
  1440. }
  1441. } else {
  1442. SetFileAttributes(TargetFile,FILE_ATTRIBUTE_NORMAL);
  1443. DeleteFile(TargetFile);
  1444. }
  1445. return(TRUE);
  1446. }
  1447. BOOL
  1448. PatchTextIntoBootCode(
  1449. VOID
  1450. )
  1451. {
  1452. BOOLEAN b;
  1453. CHAR Missing[100];
  1454. CHAR DiskErr[100];
  1455. CHAR PressKey[100];
  1456. if(LoadStringA(hInst,IDS_BOOTMSG_FAT_NTLDR_MISSING,Missing,sizeof(Missing))
  1457. && LoadStringA(hInst,IDS_BOOTMSG_FAT_DISKERROR,DiskErr,sizeof(DiskErr))
  1458. && LoadStringA(hInst,IDS_BOOTMSG_FAT_PRESSKEY,PressKey,sizeof(PressKey))) {
  1459. CharToOemA(Missing,Missing);
  1460. CharToOemA(DiskErr,DiskErr);
  1461. CharToOemA(PressKey,PressKey);
  1462. if(b = PatchMessagesIntoFatBootCode(FatBootCode,FALSE,Missing,DiskErr,PressKey)) {
  1463. b = PatchMessagesIntoFatBootCode(Fat32BootCode,TRUE,Missing,DiskErr,PressKey);
  1464. }
  1465. } else {
  1466. b = FALSE;
  1467. }
  1468. return((BOOL)b);
  1469. }
  1470. LONG
  1471. CalcHiddenSector(
  1472. IN TCHAR DriveLetter,
  1473. IN SHORT Bps
  1474. )
  1475. {
  1476. TCHAR HardDiskName[] = TEXT("\\\\.\\?:");
  1477. HANDLE hDisk;
  1478. PARTITION_INFORMATION partition_info;
  1479. DWORD DataSize;
  1480. if (!ISNT()){
  1481. return(CalcHiddenSector95(DriveLetter));
  1482. } else {
  1483. HardDiskName[4] = DriveLetter;
  1484. hDisk = CreateFileW((const unsigned short *)HardDiskName,
  1485. GENERIC_READ | GENERIC_WRITE,
  1486. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1487. NULL,
  1488. OPEN_EXISTING,
  1489. FILE_ATTRIBUTE_NORMAL,
  1490. NULL
  1491. );
  1492. if(hDisk == INVALID_HANDLE_VALUE) {
  1493. return 0L;
  1494. }
  1495. DeviceIoControl(hDisk,
  1496. IOCTL_DISK_GET_PARTITION_INFO,
  1497. NULL,
  1498. 0,
  1499. &partition_info,
  1500. sizeof(PARTITION_INFORMATION),
  1501. &DataSize,
  1502. NULL);
  1503. CloseHandle(hDisk);
  1504. return(LONG)(partition_info.StartingOffset.QuadPart / Bps);
  1505. }
  1506. }
  1507. LONG
  1508. CalcHiddenSector95(
  1509. IN TCHAR DriveLetter
  1510. )
  1511. {
  1512. #define WINNT_WIN95HLP_GET1STSECTOR_W L"GetFirstSectorNo32"
  1513. #define WINNT_WIN95HLP_GET1STSECTOR_A "GetFirstSectorNo32"
  1514. #define NEC98_DLL_NAME_W L"98PTN32.DLL"
  1515. #define NEC98_DLL_NAME_A "98PTN32.DLL"
  1516. #ifdef UNICODE
  1517. #define WINNT_WIN95HLP_GET1STSECTOR WINNT_WIN95HLP_GET1STSECTOR_W
  1518. #define NEC98_DLL_NAME NEC98_DLL_NAME_W
  1519. #else
  1520. #define WINNT_WIN95HLP_GET1STSECTOR WINNT_WIN95HLP_GET1STSECTOR_A
  1521. #define NEC98_DLL_NAME NEC98_DLL_NAME_A
  1522. #endif
  1523. typedef DWORD (CALLBACK WINNT32_PLUGIN_WIN95_GET1STSECTOR_PROTOTYPE)(int, WORD);
  1524. typedef WINNT32_PLUGIN_WIN95_GET1STSECTOR_PROTOTYPE * PWINNT32_PLUGIN_WIN95_GET1STSECTOR;
  1525. TCHAR ModuleName[MAX_PATH], *p;
  1526. HINSTANCE Pc98ModuleHandle;
  1527. PWINNT32_PLUGIN_WIN95_GET1STSECTOR Get1stSector;
  1528. LONG NumSectors = 0; // indicates failure
  1529. if(!MyGetModuleFileName (NULL, ModuleName, MAX_PATH) ||
  1530. (!(p=_tcsrchr(ModuleName, TEXT('\\')))) ) {
  1531. return 0;
  1532. }
  1533. *p= 0;
  1534. ConcatenatePaths (ModuleName, NEC98_DLL_NAME, MAX_PATH);
  1535. //
  1536. // Load library
  1537. //
  1538. Pc98ModuleHandle = LoadLibraryEx(
  1539. ModuleName,
  1540. NULL,
  1541. LOAD_WITH_ALTERED_SEARCH_PATH
  1542. );
  1543. if (Pc98ModuleHandle) {
  1544. //
  1545. // Get entry point
  1546. //
  1547. Get1stSector= (PWINNT32_PLUGIN_WIN95_GET1STSECTOR)
  1548. GetProcAddress (Pc98ModuleHandle,
  1549. (const char *)WINNT_WIN95HLP_GET1STSECTOR);
  1550. if (Get1stSector) {
  1551. //
  1552. // the second parameter must be 0.
  1553. // if 0 is returned, it indicates the function failed.
  1554. //
  1555. NumSectors = (LONG)Get1stSector((int)DriveLetter, (WORD)0);
  1556. }
  1557. FreeLibrary(Pc98ModuleHandle);
  1558. }
  1559. return NumSectors;
  1560. }