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.

1214 lines
30 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. // cmdcons boot dir
  4. #ifndef CMDCONS_BOOT_DIR_A
  5. #define CMDCONS_BOOT_DIR_A "CMDCONS"
  6. #endif
  7. #ifndef CMDCONS_BOOT_DIR_W
  8. #define CMDCONS_BOOT_DIR_W L"CMDCONS"
  9. #endif
  10. #ifndef AUX_BOOT_SECTOR_NAME_A
  11. #define AUX_BOOT_SECTOR_NAME_A "BOOTSECT.DAT"
  12. #endif
  13. #ifndef AUX_BOOT_SECTOR_NAME_W
  14. #define AUX_BOOT_SECTOR_NAME_W L"BOOTSECT.DAT"
  15. #endif
  16. #define FLEXBOOT_SECTION1 "[flexboot]"
  17. #define FLEXBOOT_SECTION2 "[boot loader]"
  18. #define FLEXBOOT_SECTION3 "[multiboot]"
  19. #define BOOTINI_OS_SECTION "[operating systems]"
  20. #define TIMEOUT "timeout"
  21. #define DEFAULT "default"
  22. #define CRLF "\r\n"
  23. #define EQUALS "="
  24. //
  25. // NOTE : Use a single string which can take care of XP and Whistler branding
  26. //
  27. #define BOOTINI_RECOVERY_CONSOLE_STR "Microsoft Windows Recovery Console"
  28. #define BOOTINI_WINPE_DESCRIPTION "\"Microsoft XP Preinstall Environment\" /cmdcons"
  29. #define BOOTINI_WINPE_ENTRY "c:\\cmdcons\\bootsect.dat"
  30. #define BOOTINI_WINPE_TIMEOUT "5"
  31. // prototypes
  32. #ifdef _X86_
  33. VOID
  34. PatchBootIni(
  35. VOID
  36. );
  37. VOID
  38. PatchBootSectDat(
  39. VOID
  40. );
  41. #endif
  42. #define BOOTFONTBIN_SIGNATURE 0x5465644d
  43. typedef struct _st_BOOTFONT_LANG {
  44. ULONG Signature;
  45. ULONG LangId;
  46. } BOOTFONT_LANG, * PBOOTFONT_LANG;
  47. BOOL
  48. LoadBootIniString(
  49. IN HINSTANCE ModuleHandle,
  50. IN DWORD MsgId,
  51. OUT PSTR Buffer,
  52. IN DWORD Size
  53. )
  54. /*++
  55. Routine Description:
  56. Loads the appropriate string needed for writing into boot.ini
  57. file. Does so, by looking for bootfont.bin file. If bootfont.bin
  58. file is present a simple LoadStringA(...) should give us the
  59. appropriate string (in most of the cases).
  60. Arguments:
  61. ModuleHandle - The module handle where resources are present
  62. MsgId - String resource identifier
  63. Buffer - Buffer to copy the string into
  64. Size - Size of the buffer (in characters)
  65. Return Value:
  66. TRUE, if localized string was loaded using LoadStringA(...)
  67. otherwise FALSE. FALSE indicates that english version of the string
  68. resource needs to be written into boot.ini
  69. --*/
  70. {
  71. BOOL Result = FALSE;
  72. static BOOL BootFontPresent = FALSE;
  73. static BOOL Initialized = FALSE;
  74. if (!Initialized) {
  75. TCHAR BootFontFile[MAX_PATH];
  76. HANDLE BootFontHandle;
  77. Initialized = TRUE;
  78. //
  79. // Open the bootfont.bin file
  80. //
  81. wsprintf(BootFontFile, TEXT("%s"), NativeSourcePaths[0]);
  82. ConcatenatePaths(BootFontFile,
  83. TEXT("bootfont.bin"),
  84. sizeof(BootFontFile)/sizeof(TCHAR));
  85. BootFontHandle = CreateFile(BootFontFile,
  86. GENERIC_READ,
  87. FILE_SHARE_READ | FILE_SHARE_WRITE,
  88. 0,
  89. OPEN_EXISTING,
  90. FILE_ATTRIBUTE_NORMAL,
  91. 0);
  92. if (BootFontHandle != INVALID_HANDLE_VALUE) {
  93. BOOTFONT_LANG BootFontHdr;
  94. DWORD BytesRead = 0;
  95. //
  96. // Verify the bootfont.bin file header
  97. //
  98. ZeroMemory(&BootFontHdr, sizeof(BOOTFONT_LANG));
  99. if (ReadFile(BootFontHandle, &BootFontHdr, sizeof(BOOTFONT_LANG),
  100. &BytesRead, NULL)) {
  101. if ((BytesRead == sizeof(BOOTFONT_LANG)) &&
  102. (BootFontHdr.Signature == BOOTFONTBIN_SIGNATURE)) {
  103. BootFontPresent = TRUE;
  104. }
  105. }
  106. CloseHandle(BootFontHandle);
  107. }
  108. }
  109. //
  110. // Load the message if bootfont is present
  111. //
  112. if (BootFontPresent) {
  113. Result = (LoadStringA(ModuleHandle, MsgId, Buffer, Size) != 0);
  114. }
  115. return Result;
  116. }
  117. DWORD
  118. MapFileForReadWrite(
  119. IN LPCTSTR FileName,
  120. OUT PDWORD FileSize,
  121. OUT PHANDLE FileHandle,
  122. OUT PHANDLE MappingHandle,
  123. OUT PVOID *BaseAddress
  124. );
  125. //
  126. // routine that builds the cmdcons installation
  127. //
  128. VOID
  129. DoBuildCmdcons(
  130. VOID
  131. )
  132. {
  133. DWORD rc;
  134. TCHAR buffer[MAX_PATH];
  135. TCHAR buffer2[MAX_PATH];
  136. BOOLEAN bSilentInstall = (BOOLEAN) UnattendedOperation;
  137. //
  138. // NT5 ntdetect.com is not compatible NT4's on NEC98 system.
  139. // We need check setup OS Version if Command console is
  140. // setuped on NEC98.
  141. //
  142. #ifdef _X86_ //NEC98
  143. if (IsNEC98() && (!ISNT() || OsVersion.dwMajorVersion < 5)){
  144. return;
  145. }
  146. #endif
  147. //
  148. // Don't popup the confirmation dialog box if install
  149. // is running in silent mode
  150. //
  151. if (!bSilentInstall) {
  152. rc = MessageBoxFromMessage(
  153. NULL,
  154. MSG_CMDCONS_ASK,
  155. FALSE,
  156. AppTitleStringId,
  157. MB_YESNO | MB_ICONWARNING
  158. );
  159. if( rc == IDNO ) {
  160. return;
  161. }
  162. }
  163. //
  164. // we don't want a local source
  165. //
  166. UserSpecifiedLocalSourceDrive = FALSE;
  167. //
  168. // use unattended to force winnt32 to build a ~bt
  169. //
  170. UnattendedOperation = TRUE;
  171. if( UnattendedScriptFile ) {
  172. FREE( UnattendedScriptFile );
  173. UnattendedScriptFile = NULL;
  174. }
  175. //
  176. // make sure we're not upgrading
  177. //
  178. Upgrade = FALSE;
  179. //
  180. // We don't want a local source.
  181. //
  182. MakeLocalSource = FALSE;
  183. //
  184. // do it.
  185. //
  186. Wizard();
  187. if(GlobalResult) {
  188. //
  189. // delete the current CMDCONS directory
  190. //
  191. BuildSystemPartitionPathToFile (TEXT("cmdcons"), buffer, MAX_PATH);
  192. MyDelnode( buffer );
  193. //
  194. // delete the current CMLDR
  195. //
  196. BuildSystemPartitionPathToFile (TEXT("cmldr"), buffer, MAX_PATH);
  197. SetFileAttributes( buffer, FILE_ATTRIBUTE_NORMAL );
  198. DeleteFile( buffer );
  199. #ifdef _X86_
  200. //
  201. // delete the new boot.ini
  202. //
  203. BuildSystemPartitionPathToFile (TEXT("boot.ini"), buffer, MAX_PATH);
  204. SetFileAttributes( buffer, FILE_ATTRIBUTE_NORMAL );
  205. DeleteFile( buffer );
  206. //
  207. // restore the old boot.ini and patch it
  208. //
  209. BuildSystemPartitionPathToFile (TEXT("boot.bak"), buffer2, MAX_PATH);
  210. CopyFile( buffer2, buffer, FALSE );
  211. PatchBootIni();
  212. #endif
  213. //
  214. // rename $LDR$ to CMLDR
  215. //
  216. BuildSystemPartitionPathToFile (TEXT("$LDR$"), buffer, MAX_PATH);
  217. BuildSystemPartitionPathToFile (TEXT("cmldr"), buffer2, MAX_PATH);
  218. MoveFile( buffer, buffer2 );
  219. //
  220. // flag CMLDR +r +s +h
  221. //
  222. SetFileAttributes( buffer2,
  223. FILE_ATTRIBUTE_HIDDEN |
  224. FILE_ATTRIBUTE_SYSTEM |
  225. FILE_ATTRIBUTE_READONLY );
  226. //
  227. // rename \$WIN_NT$.~BT to \CMDCONS
  228. //
  229. BuildSystemPartitionPathToFile (TEXT("$WIN_NT$.~BT"), buffer, MAX_PATH);
  230. BuildSystemPartitionPathToFile (TEXT("cmdcons"), buffer2, MAX_PATH);
  231. MoveFile( buffer, buffer2 );
  232. #ifdef _X86_
  233. //
  234. // fix \cmdcons\bootsect.dat
  235. //
  236. PatchBootSectDat();
  237. #endif
  238. // flag \CMDCONS +r +s +h
  239. SetFileAttributes( buffer2,
  240. FILE_ATTRIBUTE_HIDDEN |
  241. FILE_ATTRIBUTE_SYSTEM |
  242. FILE_ATTRIBUTE_READONLY );
  243. //
  244. // delete TXTSETUP.SIF
  245. //
  246. BuildSystemPartitionPathToFile (TEXT("TXTSETUP.SIF"), buffer, MAX_PATH);
  247. SetFileAttributes( buffer, FILE_ATTRIBUTE_NORMAL );
  248. DeleteFile( buffer );
  249. }
  250. //
  251. // popup completion status only if not a silent install
  252. //
  253. if (!bSilentInstall) {
  254. if(GlobalResult) {
  255. //
  256. // popup success dialog box
  257. //
  258. rc = MessageBoxFromMessage(
  259. NULL,
  260. MSG_CMDCONS_DONE,
  261. FALSE,
  262. AppTitleStringId,
  263. MB_OK | MB_ICONINFORMATION
  264. );
  265. } else {
  266. //
  267. // popup failure dialog box
  268. //
  269. rc = MessageBoxFromMessage(
  270. NULL,
  271. MSG_CMDCONS_DID_NOT_FINISH,
  272. FALSE,
  273. AppTitleStringId,
  274. MB_OK | MB_ICONERROR
  275. );
  276. }
  277. }
  278. //
  279. // make sure the machine does not reboot automatically.
  280. //
  281. AutomaticallyShutDown = FALSE;
  282. return;
  283. }
  284. BOOL
  285. __inline
  286. WriteToBootIni(
  287. IN HANDLE Handle,
  288. IN PCHAR Line
  289. )
  290. {
  291. DWORD bw,l;
  292. l = lstrlenA(Line);
  293. return(WriteFile(Handle,Line,l,&bw,NULL) && (bw == l));
  294. }
  295. #ifdef _X86_
  296. DWORD
  297. InitBootIni(
  298. IN PCTSTR BootIniName,
  299. IN PCSTR DefaultEntry,
  300. IN PCSTR DefaultEntryDescription,
  301. IN PCSTR Timeout
  302. )
  303. /*++
  304. Routine Description:
  305. Initializes a boot.ini file for e.g. while installing
  306. WinPE on to harddisk a dummy boot.ini is created for WinPE.
  307. Arguments:
  308. BootIniName - Fully qualified boot.ini file name
  309. DefaultEntry - The default entry string that points
  310. to an installation.
  311. DefaultEntryDescription - The description for the default
  312. boot entry.
  313. Timeout - The timeout value (in secs)
  314. Return Value:
  315. Appropriate Win32 error code.
  316. --*/
  317. {
  318. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  319. if (BootIniName && DefaultEntry && DefaultEntryDescription) {
  320. HANDLE BootIniHandle = CreateFile(BootIniName,
  321. GENERIC_READ | GENERIC_WRITE,
  322. FILE_SHARE_READ | FILE_SHARE_WRITE,
  323. NULL,
  324. CREATE_ALWAYS,
  325. 0,
  326. NULL);
  327. if (BootIniHandle != INVALID_HANDLE_VALUE) {
  328. //
  329. // write the [boot loader section]
  330. //
  331. BOOL Result = WriteToBootIni(BootIniHandle,
  332. FLEXBOOT_SECTION2);
  333. Result = Result && WriteToBootIni(BootIniHandle,
  334. CRLF);
  335. //
  336. // write the timeout value
  337. //
  338. if (Timeout) {
  339. Result = Result && WriteToBootIni(BootIniHandle,
  340. TIMEOUT);
  341. Result = Result && WriteToBootIni(BootIniHandle,
  342. EQUALS);
  343. Result = Result && WriteToBootIni(BootIniHandle,
  344. (PSTR)Timeout);
  345. Result = Result && WriteToBootIni(BootIniHandle,
  346. CRLF);
  347. }
  348. //
  349. // write the default installation
  350. //
  351. Result = Result && WriteToBootIni(BootIniHandle,
  352. DEFAULT);
  353. Result = Result && WriteToBootIni(BootIniHandle,
  354. EQUALS);
  355. Result = Result && WriteToBootIni(BootIniHandle,
  356. (PSTR)DefaultEntry);
  357. Result = Result && WriteToBootIni(BootIniHandle,
  358. CRLF);
  359. //
  360. // write the [operating systems] section
  361. //
  362. Result = Result && WriteToBootIni(BootIniHandle,
  363. BOOTINI_OS_SECTION);
  364. Result = Result && WriteToBootIni(BootIniHandle,
  365. CRLF);
  366. //
  367. // write the cmdcons entry
  368. //
  369. Result = Result && WriteToBootIni(BootIniHandle,
  370. (PSTR)DefaultEntry);
  371. Result = Result && WriteToBootIni(BootIniHandle,
  372. EQUALS);
  373. Result = Result && WriteToBootIni(BootIniHandle,
  374. (PSTR)DefaultEntryDescription);
  375. Result = Result && WriteToBootIni(BootIniHandle,
  376. CRLF);
  377. if (!Result) {
  378. ErrorCode = GetLastError();
  379. } else {
  380. ErrorCode = NO_ERROR;
  381. }
  382. CloseHandle(BootIniHandle);
  383. } else {
  384. ErrorCode = GetLastError();
  385. }
  386. }
  387. return ErrorCode;
  388. }
  389. VOID
  390. PatchBootIni(
  391. VOID
  392. )
  393. {
  394. CHAR c;
  395. CHAR Text[256];
  396. TCHAR BootIniName[MAX_PATH];
  397. TCHAR BootIniBackup[MAX_PATH];
  398. UCHAR temp;
  399. UCHAR BootSectorImageSpec[29];
  400. PUCHAR Buffer;
  401. PUCHAR pszBLoader = NULL;
  402. PUCHAR p,next;
  403. PUCHAR DefSwitches;
  404. PUCHAR DefSwEnd;
  405. HANDLE h;
  406. DWORD BootIniSize;
  407. DWORD BytesRead;
  408. DWORD OldAttributes;
  409. DWORD d;
  410. BOOL b;
  411. BOOL InOsSection;
  412. CHAR HeadlessRedirectSwitches[160] = {0};
  413. //
  414. // Determine the size of boot.ini, allocate a buffer,
  415. // and read it in. If it isn't there then it will be created.
  416. //
  417. BuildSystemPartitionPathToFile (TEXT("BOOT.INI"), BootIniName, MAX_PATH);
  418. BuildSystemPartitionPathToFile (TEXT("BOOT.BAK"), BootIniBackup, MAX_PATH);
  419. h = CreateFile(BootIniName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
  420. if(h == INVALID_HANDLE_VALUE) {
  421. //
  422. // If the file doesn't exist -- create one in WinPE
  423. //
  424. if (IsWinPEMode()) {
  425. CHAR Buffer[MAX_PATH] = {0};
  426. PSTR WinPEDescription = Buffer;
  427. if (!LoadBootIniString(hInst,
  428. IDS_WINPE_INSTALLATION,
  429. Buffer,
  430. sizeof(Buffer))) {
  431. WinPEDescription = BOOTINI_WINPE_DESCRIPTION;
  432. }
  433. if (InitBootIni(BootIniName,
  434. BOOTINI_WINPE_ENTRY,
  435. WinPEDescription,
  436. BOOTINI_WINPE_TIMEOUT) == NO_ERROR) {
  437. return;
  438. }
  439. }
  440. //
  441. // Yikes. Setup should have already created one of these for us.
  442. //
  443. d = GetLastError();
  444. b = FALSE;
  445. goto c0;
  446. } else {
  447. //
  448. // Figure out how big the file is.
  449. // Allocate 3 extra characters for final NUL we'll add to make
  450. // parsing easier, and a cr/lf in case the last line is incomplete.
  451. //
  452. BootIniSize = GetFileSize(h,NULL);
  453. if(BootIniSize == (DWORD)(-1)) {
  454. d = GetLastError();
  455. CloseHandle(h);
  456. b = FALSE;
  457. goto c0;
  458. }
  459. OldAttributes = GetFileAttributes( BootIniName );
  460. Buffer = MALLOC(BootIniSize+3);
  461. if(!Buffer) {
  462. CloseHandle(h);
  463. b = FALSE;
  464. d = ERROR_NOT_ENOUGH_MEMORY;
  465. goto c0;
  466. }
  467. b = ReadFile(h,Buffer,BootIniSize,&BytesRead,NULL);
  468. d = GetLastError();
  469. CloseHandle(h);
  470. if(!b) {
  471. goto c1;
  472. }
  473. }
  474. //
  475. // Make sure the last line is properly terminated, and add a terminating nul
  476. // to make parsing a little easier.
  477. //
  478. if(BootIniSize && (Buffer[BootIniSize-1] != '\n') && (Buffer[BootIniSize-1] != '\r')) {
  479. Buffer[BootIniSize++] = '\r';
  480. Buffer[BootIniSize++] = '\n';
  481. }
  482. Buffer[BootIniSize] = 0;
  483. //
  484. // Truncate at control-z if any.
  485. //
  486. if(p = strchr(Buffer,26)) {
  487. if((p > Buffer) && (*(p - 1) != '\n') && (*(p - 1) != '\r')) {
  488. *(p++) = '\r';
  489. *(p++) = '\n';
  490. }
  491. *p = 0;
  492. BootIniSize = p - Buffer;
  493. }
  494. //
  495. // Make sure we can write boot.ini.
  496. //
  497. SetFileAttributes(BootIniName,FILE_ATTRIBUTE_NORMAL);
  498. h = CreateFile(
  499. BootIniName,
  500. GENERIC_WRITE,
  501. FILE_SHARE_READ,
  502. NULL,
  503. CREATE_ALWAYS,
  504. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  505. NULL
  506. );
  507. if(h == INVALID_HANDLE_VALUE) {
  508. d = GetLastError();
  509. b = FALSE;
  510. goto c2;
  511. }
  512. //
  513. // Regardless of the actual drive letter of the system partition,
  514. // the spec in boot.ini is always C:\...
  515. //
  516. wsprintfA(BootSectorImageSpec,"C:\\%hs\\%hs",CMDCONS_BOOT_DIR_A,AUX_BOOT_SECTOR_NAME_A);
  517. // write out the first section unchanged
  518. for(p=Buffer; *p && (p < Buffer+BootIniSize - (sizeof("[operating systems]")-1)); p++) {
  519. if(!_strnicmp(p,"[operating systems]",sizeof("[operating systems]")-1)) {
  520. break;
  521. }
  522. }
  523. pszBLoader = MALLOC( (UINT_PTR)p - (UINT_PTR)Buffer + 1 );
  524. pszBLoader[(UINT_PTR)p - (UINT_PTR)Buffer ] = 0;
  525. if( pszBLoader ) {
  526. strncpy( pszBLoader, Buffer, (UINT_PTR)p - (UINT_PTR)Buffer );
  527. if(!WriteToBootIni(h,pszBLoader)) {
  528. d = GetLastError();
  529. b = FALSE;
  530. goto c3;
  531. }
  532. FREE( pszBLoader );
  533. } else {
  534. d = GetLastError();
  535. b = FALSE;
  536. goto c3;
  537. }
  538. //
  539. // Do headless stuff. We want to set the "redirect=comX"
  540. // entry in boot.ini. Make sure the user really asked
  541. // us to add this in though.
  542. //
  543. if( HeadlessSelection[0] != TEXT('\0') ) {
  544. CHAR tmp[80];
  545. BOOLEAN PreviousRedirectLine = FALSE;
  546. //
  547. // They told winnt32.exe some specific headless settings.
  548. // Use these.
  549. //
  550. //
  551. // Convert the user's request into ASCII.
  552. //
  553. #ifdef UNICODE
  554. WideCharToMultiByte( CP_ACP,
  555. 0,
  556. HeadlessSelection,
  557. -1,
  558. tmp,
  559. sizeof(tmp),
  560. NULL,
  561. NULL );
  562. wsprintfA( HeadlessRedirectSwitches,
  563. "redirect=%s\r\n",
  564. tmp );
  565. #else
  566. wsprintfA( HeadlessRedirectSwitches,
  567. "redirect=%s\r\n",
  568. HeadlessSelection );
  569. #endif
  570. } else {
  571. //
  572. // They didn't give us any settings, so see if we can pick
  573. // something up from boot.ini
  574. //
  575. for( p = Buffer; *p && (p < Buffer+BootIniSize - (sizeof("redirect=")-1)); p++ ) {
  576. if(!_strnicmp(p,"[Operat",sizeof("[Operat")-1)) {
  577. //
  578. // We're past the [Boot Loader] section. Stop looking.
  579. //
  580. break;
  581. }
  582. if(!_strnicmp(p,"redirect=",sizeof("redirect=")-1)) {
  583. PUCHAR q = p;
  584. UCHAR temp;
  585. while (*p) {
  586. p++;
  587. }
  588. temp = *p;
  589. *p = '\0';
  590. strcpy(HeadlessRedirectSwitches, q);
  591. *p = temp;
  592. break;
  593. }
  594. }
  595. }
  596. if( HeadlessRedirectSwitches[0] != '\0' ) {
  597. //
  598. // We got some 'redirect' setting, either from a command-line parameter
  599. // or from boot.ini. Write it out, and go dig up a baudrate setting.
  600. //
  601. if(!WriteToBootIni(h,HeadlessRedirectSwitches)) {
  602. d = GetLastError();
  603. b = FALSE;
  604. goto c3;
  605. }
  606. //
  607. // Now do the "redirectbaudrate=..." line.
  608. //
  609. HeadlessRedirectSwitches[0] = '\0';
  610. if( HeadlessBaudRate != 0 ) {
  611. //
  612. // Convert the user's request into ASCII.
  613. //
  614. wsprintfA( HeadlessRedirectSwitches,
  615. "redirectbaudrate=%d\r\n",
  616. HeadlessBaudRate );
  617. } else {
  618. //
  619. // They didn't give us any settings, so see if we can pick
  620. // something up from boot.ini
  621. //
  622. for( p = Buffer; *p && (p < Buffer+BootIniSize - (sizeof("redirectbaudrate=")-1)); p++ ) {
  623. if(!_strnicmp(p,"[Operat",sizeof("[Operat")-1)) {
  624. //
  625. // We're past the [Boot Loader] section. Stop looking.
  626. //
  627. break;
  628. }
  629. if(!_strnicmp(p,"redirectbaudrate=",sizeof("redirectbaudrate=")-1)) {
  630. PUCHAR q = p;
  631. UCHAR temp;
  632. while (*p) {
  633. p++;
  634. }
  635. temp = *p;
  636. *p = '\0';
  637. strcat(HeadlessRedirectSwitches, q);
  638. *p = temp;
  639. }
  640. }
  641. }
  642. if( HeadlessRedirectSwitches[0] != '\0' ) {
  643. if(!WriteToBootIni(h,HeadlessRedirectSwitches)) {
  644. d = GetLastError();
  645. b = FALSE;
  646. goto c3;
  647. }
  648. }
  649. }
  650. //
  651. // Now write out the [Operating Systems] section name.
  652. //
  653. if(!WriteToBootIni(h,"[operating systems]\r\n")) {
  654. d = GetLastError();
  655. b = FALSE;
  656. goto c3;
  657. }
  658. //
  659. // Process each line in boot.ini.
  660. // If it's the setup boot sector line, we'll throw it out.
  661. // For comparison with lines in boot.ini, the drive letter
  662. // is always C even if the system partition is not actually C:.
  663. //
  664. InOsSection = FALSE;
  665. b = TRUE;
  666. for(p=Buffer; *p && b; p=next) {
  667. while((*p==' ') || (*p=='\t')) {
  668. p++;
  669. }
  670. if(*p) {
  671. //
  672. // Find first byte of next line.
  673. //
  674. for(next=p; *next && (*next++ != '\n'); );
  675. //
  676. // Look for start of [operating systems] section
  677. // or at each line in that section.
  678. //
  679. if(InOsSection) {
  680. switch(*p) {
  681. case '[': // end of section.
  682. *p=0; // force break out of loop
  683. break;
  684. case 'C':
  685. case 'c': // potential start of c:\ line
  686. //
  687. // See if it's a line for setup boot.
  688. // If so, ignore it.
  689. //
  690. if(!_strnicmp(p,BootSectorImageSpec,lstrlenA(BootSectorImageSpec))) {
  691. break;
  692. }
  693. //
  694. // Not a special line, FALL THROUGH to write it out as-is.
  695. //
  696. default:
  697. //
  698. // Random line. write it out.
  699. //
  700. c = *next;
  701. *next = 0;
  702. b = WriteToBootIni(h,p);
  703. *next = c;
  704. break;
  705. }
  706. } else {
  707. if(!_strnicmp(p,"[operating systems]",19)) {
  708. InOsSection = TRUE;
  709. }
  710. }
  711. }
  712. }
  713. //
  714. // Write out our line.
  715. //
  716. if(b) {
  717. //
  718. // NOTE : This is intentional. If we have a boot font then we convert the unicode
  719. // string we got from message resoure to DBCS using LoadStringA(...) else we just
  720. // write English string out in boot.ini for recovery console.
  721. //
  722. if (!LoadBootIniString(hInst, IDS_RECOVERY_CONSOLE, Text, sizeof(Text))) {
  723. strcpy(Text, BOOTINI_RECOVERY_CONSOLE_STR);
  724. }
  725. if((b=WriteToBootIni(h,BootSectorImageSpec))
  726. && (b=WriteToBootIni(h,"=\""))
  727. && (b=WriteToBootIni(h,Text))
  728. && (b=WriteToBootIni(h,"\" /cmdcons" ))) {
  729. b = WriteToBootIni(h,"\r\n");
  730. }
  731. }
  732. #if 0
  733. //
  734. // Write out previous OS line if directed to do so.
  735. //
  736. if(b && SetPreviousOs) {
  737. if(b = WriteToBootIni(h,"C:\\=\"")) {
  738. LoadStringA(hInst,IDS_MICROSOFT_WINDOWS,Text,sizeof(Text));
  739. if(b = WriteToBootIni(h,Text)) {
  740. b = WriteToBootIni(h,"\"\r\n");
  741. }
  742. }
  743. }
  744. #endif
  745. if(!b) {
  746. d = GetLastError();
  747. goto c3;
  748. }
  749. d = NO_ERROR;
  750. c3:
  751. CloseHandle(h);
  752. c2:
  753. //
  754. // Restore boot.ini.
  755. //
  756. if(!b && (OldAttributes != (DWORD)(-1))) {
  757. SetFileAttributes(BootIniName,FILE_ATTRIBUTE_NORMAL);
  758. CopyFile(BootIniBackup,BootIniName,FALSE);
  759. SetFileAttributes(BootIniName,OldAttributes);
  760. SetFileAttributes(BootIniBackup,FILE_ATTRIBUTE_NORMAL);
  761. DeleteFile(BootIniBackup);
  762. }
  763. c1:
  764. FREE(Buffer);
  765. c0:
  766. if(!b) {
  767. MessageBoxFromMessageAndSystemError(
  768. NULL,
  769. MSG_BOOT_FILE_ERROR,
  770. d,
  771. AppTitleStringId,
  772. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  773. BootIniName
  774. );
  775. GlobalResult = FALSE;
  776. }
  777. }
  778. VOID
  779. PatchBootSectDat(
  780. VOID
  781. )
  782. {
  783. TCHAR buffer[MAX_PATH];
  784. DWORD rc;
  785. DWORD fileSize;
  786. DWORD curpos;
  787. HANDLE fileHandle;
  788. HANDLE mappingHandle;
  789. LPBYTE bootSectDat;
  790. TCHAR DrivePath[MAX_PATH];
  791. DWORD DontCare;
  792. TCHAR NameBuffer[100];
  793. BOOL Ntfs = FALSE;
  794. //
  795. // find out what the file system is
  796. //
  797. BuildSystemPartitionPathToFile (TEXT(""), DrivePath, MAX_PATH);
  798. //BUGBUG
  799. rc = GetVolumeInformation(
  800. DrivePath,
  801. NULL,
  802. 0,
  803. NULL,
  804. &DontCare,
  805. &DontCare,
  806. NameBuffer,
  807. sizeof(NameBuffer)/sizeof(TCHAR)
  808. );
  809. if (rc == 0) {
  810. return;
  811. }
  812. if (!lstrcmpi(NameBuffer,TEXT("NTFS"))) {
  813. Ntfs = TRUE;
  814. }
  815. //
  816. // form the path
  817. //
  818. BuildSystemPartitionPathToFile (TEXT("CMDCONS\\BOOTSECT.DAT"), buffer, MAX_PATH);
  819. //
  820. // map the file into RAM
  821. //
  822. rc = MapFileForReadWrite( buffer,
  823. &fileSize,
  824. &fileHandle,
  825. &mappingHandle,
  826. (PVOID*)&bootSectDat
  827. );
  828. if( rc == NO_ERROR ) {
  829. __try {
  830. for (curpos = 0; curpos < fileSize; curpos++) {
  831. if (Ntfs) {
  832. if( bootSectDat[curpos] == '$' &&
  833. bootSectDat[curpos+2] == 'L' &&
  834. bootSectDat[curpos+4] == 'D' &&
  835. bootSectDat[curpos+6] == 'R' &&
  836. bootSectDat[curpos+8] == '$' ) {
  837. // patch CMLDR
  838. bootSectDat[curpos] = 'C';
  839. bootSectDat[curpos+2] = 'M';
  840. bootSectDat[curpos+4] = 'L';
  841. bootSectDat[curpos+6] = 'D';
  842. bootSectDat[curpos+8] = 'R';
  843. break;
  844. }
  845. } else {
  846. if( bootSectDat[curpos] == '$' &&
  847. bootSectDat[curpos+1] == 'L' &&
  848. bootSectDat[curpos+2] == 'D' &&
  849. bootSectDat[curpos+3] == 'R' &&
  850. bootSectDat[curpos+4] == '$' ) {
  851. // patch CMLDR
  852. bootSectDat[curpos] = 'C';
  853. bootSectDat[curpos+1] = 'M';
  854. bootSectDat[curpos+2] = 'L';
  855. bootSectDat[curpos+3] = 'D';
  856. bootSectDat[curpos+4] = 'R';
  857. break;
  858. }
  859. }
  860. }
  861. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  862. }
  863. }
  864. FlushViewOfFile( (PVOID)bootSectDat, 0 );
  865. UnmapFile( mappingHandle, (PVOID)bootSectDat );
  866. CloseHandle( fileHandle );
  867. }
  868. #endif
  869. DWORD
  870. MapFileForReadWrite(
  871. IN LPCTSTR FileName,
  872. OUT PDWORD FileSize,
  873. OUT PHANDLE FileHandle,
  874. OUT PHANDLE MappingHandle,
  875. OUT PVOID *BaseAddress
  876. )
  877. /*++
  878. Routine Description:
  879. Open and map an entire file for read access. The file must
  880. not be 0-length or the routine fails.
  881. Arguments:
  882. FileName - supplies pathname to file to be mapped.
  883. FileSize - receives the size in bytes of the file.
  884. FileHandle - receives the win32 file handle for the open file.
  885. The file will be opened for generic read access.
  886. MappingHandle - receives the win32 handle for the file mapping
  887. object. This object will be for read access. This value is
  888. undefined if the file being opened is 0 length.
  889. BaseAddress - receives the address where the file is mapped. This
  890. value is undefined if the file being opened is 0 length.
  891. Return Value:
  892. NO_ERROR if the file was opened and mapped successfully.
  893. The caller must unmap the file with UnmapFile when
  894. access to the file is no longer desired.
  895. Win32 error code if the file was not successfully mapped.
  896. --*/
  897. {
  898. DWORD rc;
  899. //
  900. // Open the file -- fail if it does not exist.
  901. //
  902. *FileHandle = CreateFile(
  903. FileName,
  904. GENERIC_READ | GENERIC_WRITE,
  905. 0, // exclusive access
  906. NULL,
  907. OPEN_EXISTING,
  908. 0,
  909. NULL
  910. );
  911. if(*FileHandle == INVALID_HANDLE_VALUE) {
  912. rc = GetLastError();
  913. } else {
  914. //
  915. // Get the size of the file.
  916. //
  917. *FileSize = GetFileSize(*FileHandle,NULL);
  918. if(*FileSize == (DWORD)(-1)) {
  919. rc = GetLastError();
  920. } else {
  921. //
  922. // Create file mapping for the whole file.
  923. //
  924. *MappingHandle = CreateFileMapping(
  925. *FileHandle,
  926. NULL,
  927. PAGE_READWRITE,
  928. 0,
  929. *FileSize,
  930. NULL
  931. );
  932. if(*MappingHandle) {
  933. //
  934. // Map the whole file.
  935. //
  936. *BaseAddress = MapViewOfFile(
  937. *MappingHandle,
  938. FILE_MAP_ALL_ACCESS,
  939. 0,
  940. 0,
  941. *FileSize
  942. );
  943. if(*BaseAddress) {
  944. return(NO_ERROR);
  945. }
  946. rc = GetLastError();
  947. CloseHandle(*MappingHandle);
  948. } else {
  949. rc = GetLastError();
  950. }
  951. }
  952. CloseHandle(*FileHandle);
  953. }
  954. return(rc);
  955. }