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.

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