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.

1289 lines
33 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 Preinstall Environment\" /cmdcons"
  29. #define BOOTINI_WINPE_ENTRY "c:\\cmdcons\\bootsect.dat"
  30. #define BOOTINI_WINPE_TIMEOUT "5"
  31. // prototypes
  32. #if defined(_AMD64_) || defined(_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. #if defined(_AMD64_) || defined(_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. if (!MoveFile( buffer, buffer2 )){
  232. TCHAR tempbuffer[MAX_PATH];
  233. GlobalResult = FALSE;
  234. //
  235. // Delete the ~BT folder and cmldr file in case of failure.
  236. // Blow away the local boot dir.
  237. //
  238. if(LocalBootDirectory[0]) {
  239. MyDelnode(LocalBootDirectory);
  240. }
  241. //
  242. // Blow away cmldr off the root of the system partition.
  243. //
  244. if (BuildSystemPartitionPathToFile (TEXT("cmldr"), tempbuffer, MAX_PATH)){
  245. if (SetFileAttributes(tempbuffer,FILE_ATTRIBUTE_NORMAL)){
  246. DeleteFile(tempbuffer);
  247. }
  248. }
  249. }else{
  250. #if defined(_AMD64_) || defined(_X86_)
  251. //
  252. // fix \cmdcons\bootsect.dat
  253. //
  254. PatchBootSectDat();
  255. #endif
  256. // flag \CMDCONS +r +s +h
  257. SetFileAttributes( buffer2,
  258. FILE_ATTRIBUTE_HIDDEN |
  259. FILE_ATTRIBUTE_SYSTEM |
  260. FILE_ATTRIBUTE_READONLY );
  261. }
  262. //
  263. // delete TXTSETUP.SIF
  264. //
  265. BuildSystemPartitionPathToFile (TEXT("TXTSETUP.SIF"), buffer, MAX_PATH);
  266. SetFileAttributes( buffer, FILE_ATTRIBUTE_NORMAL );
  267. DeleteFile( buffer );
  268. }
  269. //
  270. // popup completion status only if not a silent install
  271. //
  272. if (!bSilentInstall) {
  273. if(GlobalResult) {
  274. //
  275. // popup success dialog box
  276. //
  277. rc = MessageBoxFromMessage(
  278. NULL,
  279. MSG_CMDCONS_DONE,
  280. FALSE,
  281. AppTitleStringId,
  282. MB_OK | MB_ICONINFORMATION
  283. );
  284. } else {
  285. //
  286. // popup failure dialog box
  287. //
  288. rc = MessageBoxFromMessage(
  289. NULL,
  290. MSG_CMDCONS_DID_NOT_FINISH,
  291. FALSE,
  292. AppTitleStringId,
  293. MB_OK | MB_ICONERROR
  294. );
  295. }
  296. }
  297. //
  298. // make sure the machine does not reboot automatically.
  299. //
  300. AutomaticallyShutDown = FALSE;
  301. return;
  302. }
  303. BOOL
  304. __inline
  305. WriteToBootIni(
  306. IN HANDLE Handle,
  307. IN PCHAR Line
  308. )
  309. {
  310. DWORD bw,l;
  311. l = lstrlenA(Line);
  312. return(WriteFile(Handle,Line,l,&bw,NULL) && (bw == l));
  313. }
  314. #if defined(_AMD64_) || defined(_X86_)
  315. DWORD
  316. InitBootIni(
  317. IN PCTSTR BootIniName,
  318. IN PCSTR DefaultEntry,
  319. IN PCSTR DefaultEntryDescription,
  320. IN PCSTR Timeout
  321. )
  322. /*++
  323. Routine Description:
  324. Initializes a boot.ini file for e.g. while installing
  325. WinPE on to harddisk a dummy boot.ini is created for WinPE.
  326. Arguments:
  327. BootIniName - Fully qualified boot.ini file name
  328. DefaultEntry - The default entry string that points
  329. to an installation.
  330. DefaultEntryDescription - The description for the default
  331. boot entry.
  332. Timeout - The timeout value (in secs)
  333. Return Value:
  334. Appropriate Win32 error code.
  335. --*/
  336. {
  337. DWORD ErrorCode = ERROR_INVALID_PARAMETER;
  338. if (BootIniName && DefaultEntry && DefaultEntryDescription) {
  339. HANDLE BootIniHandle = CreateFile(BootIniName,
  340. GENERIC_READ | GENERIC_WRITE,
  341. FILE_SHARE_READ | FILE_SHARE_WRITE,
  342. NULL,
  343. CREATE_ALWAYS,
  344. 0,
  345. NULL);
  346. if (BootIniHandle != INVALID_HANDLE_VALUE) {
  347. //
  348. // write the [boot loader section]
  349. //
  350. BOOL Result = WriteToBootIni(BootIniHandle,
  351. FLEXBOOT_SECTION2);
  352. Result = Result && WriteToBootIni(BootIniHandle,
  353. CRLF);
  354. //
  355. // write the timeout value
  356. //
  357. if (Timeout) {
  358. Result = Result && WriteToBootIni(BootIniHandle,
  359. TIMEOUT);
  360. Result = Result && WriteToBootIni(BootIniHandle,
  361. EQUALS);
  362. Result = Result && WriteToBootIni(BootIniHandle,
  363. (PSTR)Timeout);
  364. Result = Result && WriteToBootIni(BootIniHandle,
  365. CRLF);
  366. }
  367. //
  368. // write the default installation
  369. //
  370. Result = Result && WriteToBootIni(BootIniHandle,
  371. DEFAULT);
  372. Result = Result && WriteToBootIni(BootIniHandle,
  373. EQUALS);
  374. Result = Result && WriteToBootIni(BootIniHandle,
  375. (PSTR)DefaultEntry);
  376. Result = Result && WriteToBootIni(BootIniHandle,
  377. CRLF);
  378. //
  379. // write the [operating systems] section
  380. //
  381. Result = Result && WriteToBootIni(BootIniHandle,
  382. BOOTINI_OS_SECTION);
  383. Result = Result && WriteToBootIni(BootIniHandle,
  384. CRLF);
  385. //
  386. // write the cmdcons entry
  387. //
  388. Result = Result && WriteToBootIni(BootIniHandle,
  389. (PSTR)DefaultEntry);
  390. Result = Result && WriteToBootIni(BootIniHandle,
  391. EQUALS);
  392. Result = Result && WriteToBootIni(BootIniHandle,
  393. (PSTR)DefaultEntryDescription);
  394. Result = Result && WriteToBootIni(BootIniHandle,
  395. CRLF);
  396. if (!Result) {
  397. ErrorCode = GetLastError();
  398. } else {
  399. ErrorCode = NO_ERROR;
  400. }
  401. CloseHandle(BootIniHandle);
  402. } else {
  403. ErrorCode = GetLastError();
  404. }
  405. }
  406. return ErrorCode;
  407. }
  408. VOID
  409. PatchBootIni(
  410. VOID
  411. )
  412. {
  413. CHAR c;
  414. CHAR Text[256];
  415. TCHAR BootIniName[MAX_PATH] = {0};
  416. TCHAR BootIniBackup[MAX_PATH] = {0};
  417. UCHAR temp;
  418. UCHAR BootSectorImageSpec[29];
  419. PUCHAR Buffer;
  420. PUCHAR pszBLoader = NULL;
  421. PUCHAR p,next;
  422. PUCHAR DefSwitches;
  423. PUCHAR DefSwEnd;
  424. HANDLE h;
  425. DWORD BootIniSize;
  426. DWORD BytesRead;
  427. DWORD OldAttributes;
  428. DWORD d;
  429. BOOL b;
  430. BOOL InOsSection;
  431. CHAR HeadlessRedirectSwitches[160] = {0};
  432. //
  433. // Determine the size of boot.ini, allocate a buffer,
  434. // and read it in. If it isn't there then it will be created.
  435. //
  436. BuildSystemPartitionPathToFile (TEXT("BOOT.INI"), BootIniName, MAX_PATH);
  437. BuildSystemPartitionPathToFile (TEXT("BOOT.BAK"), BootIniBackup, MAX_PATH);
  438. h = CreateFile(BootIniName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
  439. if(h == INVALID_HANDLE_VALUE) {
  440. //
  441. // If the file doesn't exist -- create one in WinPE
  442. //
  443. if (IsWinPEMode()) {
  444. CHAR Buffer[MAX_PATH] = {0};
  445. PSTR WinPEDescription = Buffer;
  446. if (!LoadBootIniString(hInst,
  447. IDS_WINPE_INSTALLATION,
  448. Buffer,
  449. sizeof(Buffer))) {
  450. WinPEDescription = BOOTINI_WINPE_DESCRIPTION;
  451. }
  452. if (InitBootIni(BootIniName,
  453. BOOTINI_WINPE_ENTRY,
  454. WinPEDescription,
  455. BOOTINI_WINPE_TIMEOUT) == NO_ERROR) {
  456. return;
  457. }
  458. }
  459. //
  460. // Yikes. Setup should have already created one of these for us.
  461. //
  462. d = GetLastError();
  463. b = FALSE;
  464. goto c0;
  465. } else {
  466. //
  467. // Figure out how big the file is.
  468. // Allocate 3 extra characters for final NUL we'll add to make
  469. // parsing easier, and a cr/lf in case the last line is incomplete.
  470. //
  471. BootIniSize = GetFileSize(h,NULL);
  472. if(BootIniSize == (DWORD)(-1)) {
  473. d = GetLastError();
  474. CloseHandle(h);
  475. b = FALSE;
  476. goto c0;
  477. }
  478. OldAttributes = GetFileAttributes( BootIniName );
  479. Buffer = MALLOC(BootIniSize+3);
  480. if(!Buffer) {
  481. CloseHandle(h);
  482. b = FALSE;
  483. d = ERROR_NOT_ENOUGH_MEMORY;
  484. goto c0;
  485. }
  486. b = ReadFile(h,Buffer,BootIniSize,&BytesRead,NULL);
  487. d = GetLastError();
  488. CloseHandle(h);
  489. if(!b) {
  490. goto c1;
  491. }
  492. }
  493. //
  494. // Make sure the last line is properly terminated, and add a terminating nul
  495. // to make parsing a little easier.
  496. //
  497. if(BootIniSize && (Buffer[BootIniSize-1] != '\n') && (Buffer[BootIniSize-1] != '\r')) {
  498. Buffer[BootIniSize++] = '\r';
  499. Buffer[BootIniSize++] = '\n';
  500. }
  501. Buffer[BootIniSize] = 0;
  502. //
  503. // Truncate at control-z if any.
  504. //
  505. if(p = strchr(Buffer,26)) {
  506. if((p > Buffer) && (*(p - 1) != '\n') && (*(p - 1) != '\r')) {
  507. *(p++) = '\r';
  508. *(p++) = '\n';
  509. }
  510. *p = 0;
  511. BootIniSize = (DWORD)(p - Buffer);
  512. }
  513. //
  514. // Make sure we can write boot.ini.
  515. //
  516. SetFileAttributes(BootIniName,FILE_ATTRIBUTE_NORMAL);
  517. h = CreateFile(
  518. BootIniName,
  519. GENERIC_WRITE,
  520. FILE_SHARE_READ,
  521. NULL,
  522. CREATE_ALWAYS,
  523. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  524. NULL
  525. );
  526. if(h == INVALID_HANDLE_VALUE) {
  527. d = GetLastError();
  528. b = FALSE;
  529. goto c2;
  530. }
  531. //
  532. // Regardless of the actual drive letter of the system partition,
  533. // the spec in boot.ini is always C:\...
  534. //
  535. wsprintfA(BootSectorImageSpec,"C:\\%hs\\%hs",CMDCONS_BOOT_DIR_A,AUX_BOOT_SECTOR_NAME_A);
  536. // write out the first section unchanged
  537. for(p=Buffer; *p && (p < Buffer+BootIniSize - (sizeof("[operating systems]")-1)); p++) {
  538. //
  539. // Headless 'redirect' setting.
  540. //
  541. if(!_strnicmp(p,"redirect=",sizeof("redirect=")-1)) {
  542. PUCHAR q, r;
  543. UCHAR Temp;
  544. //
  545. // Jump over the headless settings, but record them if the
  546. // user didn't give us any specific settings.
  547. //
  548. q = p + strlen("redirect=");
  549. r = q;
  550. while( (*r != '\n') &&
  551. (*r != '\r') &&
  552. (*r) &&
  553. (*r != '[') ) {
  554. r++;
  555. }
  556. //
  557. // Now jump over the whitespace too.
  558. //
  559. while( (*r == '\n') ||
  560. (*r == '\r') ) {
  561. r++;
  562. }
  563. if( *r ) {
  564. Temp = *r;
  565. *r = '\0';
  566. if( HeadlessSelection[0] == TEXT('\0') ) {
  567. //
  568. // Record this headless setting because the user
  569. // didn't specify any headless setting.
  570. //
  571. #ifdef UNICODE
  572. swprintf( HeadlessSelection, TEXT("%s"), q );
  573. #else
  574. strcpy( HeadlessSelection, q );
  575. #endif
  576. }
  577. *r = Temp;
  578. //
  579. // Now copy the remaining buffer ontop of this
  580. // headless setting.
  581. //
  582. strcpy( p, r );
  583. }
  584. }
  585. //
  586. // Headless 'redirectbaudrate' setting.
  587. //
  588. if(!_strnicmp(p,"redirectbaudrate=",sizeof("redirectbaudrate=")-1)) {
  589. PUCHAR q, r;
  590. UCHAR Temp;
  591. //
  592. // Jump over the headless settings, but record them if the
  593. // user didn't give us any specific settings.
  594. //
  595. q = p + strlen("redirectbaudrate=");
  596. r = q;
  597. while( (*r != '\n') &&
  598. (*r != '\r') &&
  599. (*r) &&
  600. (*r != '[') ) {
  601. r++;
  602. }
  603. //
  604. // Now jump over the whitespace too.
  605. //
  606. while( (*r == '\n') ||
  607. (*r == '\r') ) {
  608. r++;
  609. }
  610. if( *r ) {
  611. Temp = *r;
  612. *r = '\0';
  613. if( HeadlessBaudRate == 0 ) {
  614. //
  615. // Record this headless setting because the user
  616. // didn't specify any headless setting.
  617. //
  618. HeadlessBaudRate = atoi(q);
  619. }
  620. *r = Temp;
  621. //
  622. // Now copy the remaining buffer ontop of this
  623. // headless setting.
  624. //
  625. strcpy( p, r );
  626. }
  627. }
  628. if(!_strnicmp(p,"[operating systems]",sizeof("[operating systems]")-1)) {
  629. break;
  630. }
  631. }
  632. pszBLoader = MALLOC( (UINT_PTR)p - (UINT_PTR)Buffer + 1 );
  633. pszBLoader[(UINT_PTR)p - (UINT_PTR)Buffer ] = 0;
  634. if( pszBLoader ) {
  635. strncpy( pszBLoader, Buffer, (UINT_PTR)p - (UINT_PTR)Buffer );
  636. if(!WriteToBootIni(h,pszBLoader)) {
  637. d = GetLastError();
  638. b = FALSE;
  639. goto c3;
  640. }
  641. FREE( pszBLoader );
  642. } else {
  643. d = GetLastError();
  644. b = FALSE;
  645. goto c3;
  646. }
  647. //
  648. // Do headless stuff. We want to set the "redirect=comX"
  649. // entry in boot.ini. Make sure the user really asked
  650. // us to add this in though.
  651. //
  652. if( HeadlessSelection[0] != TEXT('\0') ) {
  653. CHAR tmp[80];
  654. BOOLEAN PreviousRedirectLine = FALSE;
  655. //
  656. // They told winnt32.exe some specific headless settings.
  657. // Use these.
  658. //
  659. //
  660. // Convert the user's request into ASCII.
  661. //
  662. #ifdef UNICODE
  663. WideCharToMultiByte( CP_ACP,
  664. 0,
  665. HeadlessSelection,
  666. -1,
  667. tmp,
  668. sizeof(tmp),
  669. NULL,
  670. NULL );
  671. wsprintfA( HeadlessRedirectSwitches,
  672. "redirect=%s\r\n",
  673. tmp );
  674. #else
  675. wsprintfA( HeadlessRedirectSwitches,
  676. "redirect=%s\r\n",
  677. HeadlessSelection );
  678. #endif
  679. }
  680. if( HeadlessRedirectSwitches[0] != '\0' ) {
  681. //
  682. // We got some 'redirect' setting, either from a command-line parameter
  683. // or from boot.ini. Write it out, and go dig up a baudrate setting.
  684. //
  685. if(!WriteToBootIni(h,HeadlessRedirectSwitches)) {
  686. d = GetLastError();
  687. b = FALSE;
  688. goto c3;
  689. }
  690. //
  691. // Now do the "redirectbaudrate=..." line.
  692. //
  693. HeadlessRedirectSwitches[0] = '\0';
  694. if( HeadlessBaudRate != 0 ) {
  695. //
  696. // Convert the user's request into ASCII.
  697. //
  698. wsprintfA( HeadlessRedirectSwitches,
  699. "redirectbaudrate=%d\r\n",
  700. HeadlessBaudRate );
  701. }
  702. if( HeadlessRedirectSwitches[0] != '\0' ) {
  703. if(!WriteToBootIni(h,HeadlessRedirectSwitches)) {
  704. d = GetLastError();
  705. b = FALSE;
  706. goto c3;
  707. }
  708. }
  709. }
  710. //
  711. // Now write out the [Operating Systems] section name.
  712. //
  713. if(!WriteToBootIni(h,"[operating systems]\r\n")) {
  714. d = GetLastError();
  715. b = FALSE;
  716. goto c3;
  717. }
  718. //
  719. // Process each line in boot.ini.
  720. // If it's the setup boot sector line, we'll throw it out.
  721. // For comparison with lines in boot.ini, the drive letter
  722. // is always C even if the system partition is not actually C:.
  723. //
  724. InOsSection = FALSE;
  725. b = TRUE;
  726. for(p=Buffer; *p && b; p=next) {
  727. while((*p==' ') || (*p=='\t')) {
  728. p++;
  729. }
  730. if(*p) {
  731. //
  732. // Find first byte of next line.
  733. //
  734. for(next=p; *next && (*next++ != '\n'); );
  735. //
  736. // Look for start of [operating systems] section
  737. // or at each line in that section.
  738. //
  739. if(InOsSection) {
  740. switch(*p) {
  741. case '[': // end of section.
  742. *p=0; // force break out of loop
  743. break;
  744. case 'C':
  745. case 'c': // potential start of c:\ line
  746. //
  747. // See if it's a line for setup boot.
  748. // If so, ignore it.
  749. //
  750. if(!_strnicmp(p,BootSectorImageSpec,lstrlenA(BootSectorImageSpec))) {
  751. break;
  752. }
  753. //
  754. // Not a special line, FALL THROUGH to write it out as-is.
  755. //
  756. default:
  757. //
  758. // Random line. write it out.
  759. //
  760. c = *next;
  761. *next = 0;
  762. b = WriteToBootIni(h,p);
  763. *next = c;
  764. break;
  765. }
  766. } else {
  767. if(!_strnicmp(p,"[operating systems]",19)) {
  768. InOsSection = TRUE;
  769. }
  770. }
  771. }
  772. }
  773. //
  774. // Write out our line.
  775. //
  776. if(b) {
  777. //
  778. // NOTE : This is intentional. If we have a boot font then we convert the unicode
  779. // string we got from message resoure to DBCS using LoadStringA(...) else we just
  780. // write English string out in boot.ini for recovery console.
  781. //
  782. if (!LoadBootIniString(hInst, IDS_RECOVERY_CONSOLE, Text, sizeof(Text))) {
  783. strcpy(Text, BOOTINI_RECOVERY_CONSOLE_STR);
  784. }
  785. if((b=WriteToBootIni(h,BootSectorImageSpec))
  786. && (b=WriteToBootIni(h,"=\""))
  787. && (b=WriteToBootIni(h,Text))
  788. && (b=WriteToBootIni(h,"\" /cmdcons" ))) {
  789. b = WriteToBootIni(h,"\r\n");
  790. }
  791. }
  792. #if 0
  793. //
  794. // Write out previous OS line if directed to do so.
  795. //
  796. if(b && SetPreviousOs) {
  797. if(b = WriteToBootIni(h,"C:\\=\"")) {
  798. LoadStringA(hInst,IDS_MICROSOFT_WINDOWS,Text,sizeof(Text));
  799. if(b = WriteToBootIni(h,Text)) {
  800. b = WriteToBootIni(h,"\"\r\n");
  801. }
  802. }
  803. }
  804. #endif
  805. if(!b) {
  806. d = GetLastError();
  807. goto c3;
  808. }
  809. d = NO_ERROR;
  810. c3:
  811. CloseHandle(h);
  812. c2:
  813. //
  814. // Restore boot.ini.
  815. //
  816. if(!b && (OldAttributes != (DWORD)(-1))) {
  817. SetFileAttributes(BootIniName,FILE_ATTRIBUTE_NORMAL);
  818. CopyFile(BootIniBackup,BootIniName,FALSE);
  819. SetFileAttributes(BootIniName,OldAttributes);
  820. SetFileAttributes(BootIniBackup,FILE_ATTRIBUTE_NORMAL);
  821. DeleteFile(BootIniBackup);
  822. }
  823. c1:
  824. FREE(Buffer);
  825. c0:
  826. if(!b) {
  827. MessageBoxFromMessageAndSystemError(
  828. NULL,
  829. MSG_BOOT_FILE_ERROR,
  830. d,
  831. AppTitleStringId,
  832. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  833. BootIniName
  834. );
  835. GlobalResult = FALSE;
  836. }
  837. }
  838. VOID
  839. PatchBootSectDat(
  840. VOID
  841. )
  842. {
  843. TCHAR buffer[MAX_PATH];
  844. DWORD rc;
  845. DWORD fileSize;
  846. DWORD curpos;
  847. HANDLE fileHandle;
  848. HANDLE mappingHandle;
  849. LPBYTE bootSectDat;
  850. TCHAR DrivePath[MAX_PATH];
  851. DWORD DontCare;
  852. TCHAR NameBuffer[100];
  853. BOOL Ntfs = FALSE;
  854. //
  855. // find out what the file system is
  856. //
  857. BuildSystemPartitionPathToFile (TEXT(""), DrivePath, MAX_PATH);
  858. //BUGBUG
  859. rc = GetVolumeInformation(
  860. DrivePath,
  861. NULL,
  862. 0,
  863. NULL,
  864. &DontCare,
  865. &DontCare,
  866. NameBuffer,
  867. sizeof(NameBuffer)/sizeof(TCHAR)
  868. );
  869. if (rc == 0) {
  870. return;
  871. }
  872. if (!lstrcmpi(NameBuffer,TEXT("NTFS"))) {
  873. Ntfs = TRUE;
  874. }
  875. //
  876. // form the path
  877. //
  878. BuildSystemPartitionPathToFile (TEXT("CMDCONS\\BOOTSECT.DAT"), buffer, MAX_PATH);
  879. //
  880. // map the file into RAM
  881. //
  882. rc = MapFileForReadWrite( buffer,
  883. &fileSize,
  884. &fileHandle,
  885. &mappingHandle,
  886. (PVOID*)&bootSectDat
  887. );
  888. if( rc == NO_ERROR ) {
  889. __try {
  890. for (curpos = 0; curpos < fileSize; curpos++) {
  891. if (Ntfs) {
  892. if( bootSectDat[curpos] == '$' &&
  893. bootSectDat[curpos+2] == 'L' &&
  894. bootSectDat[curpos+4] == 'D' &&
  895. bootSectDat[curpos+6] == 'R' &&
  896. bootSectDat[curpos+8] == '$' ) {
  897. // patch CMLDR
  898. bootSectDat[curpos] = 'C';
  899. bootSectDat[curpos+2] = 'M';
  900. bootSectDat[curpos+4] = 'L';
  901. bootSectDat[curpos+6] = 'D';
  902. bootSectDat[curpos+8] = 'R';
  903. break;
  904. }
  905. } else {
  906. if( bootSectDat[curpos] == '$' &&
  907. bootSectDat[curpos+1] == 'L' &&
  908. bootSectDat[curpos+2] == 'D' &&
  909. bootSectDat[curpos+3] == 'R' &&
  910. bootSectDat[curpos+4] == '$' ) {
  911. // patch CMLDR
  912. bootSectDat[curpos] = 'C';
  913. bootSectDat[curpos+1] = 'M';
  914. bootSectDat[curpos+2] = 'L';
  915. bootSectDat[curpos+3] = 'D';
  916. bootSectDat[curpos+4] = 'R';
  917. break;
  918. }
  919. }
  920. }
  921. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  922. }
  923. }
  924. FlushViewOfFile( (PVOID)bootSectDat, 0 );
  925. UnmapFile( mappingHandle, (PVOID)bootSectDat );
  926. CloseHandle( fileHandle );
  927. }
  928. #endif
  929. DWORD
  930. MapFileForReadWrite(
  931. IN LPCTSTR FileName,
  932. OUT PDWORD FileSize,
  933. OUT PHANDLE FileHandle,
  934. OUT PHANDLE MappingHandle,
  935. OUT PVOID *BaseAddress
  936. )
  937. /*++
  938. Routine Description:
  939. Open and map an entire file for read access. The file must
  940. not be 0-length or the routine fails.
  941. Arguments:
  942. FileName - supplies pathname to file to be mapped.
  943. FileSize - receives the size in bytes of the file.
  944. FileHandle - receives the win32 file handle for the open file.
  945. The file will be opened for generic read access.
  946. MappingHandle - receives the win32 handle for the file mapping
  947. object. This object will be for read access. This value is
  948. undefined if the file being opened is 0 length.
  949. BaseAddress - receives the address where the file is mapped. This
  950. value is undefined if the file being opened is 0 length.
  951. Return Value:
  952. NO_ERROR if the file was opened and mapped successfully.
  953. The caller must unmap the file with UnmapFile when
  954. access to the file is no longer desired.
  955. Win32 error code if the file was not successfully mapped.
  956. --*/
  957. {
  958. DWORD rc;
  959. //
  960. // Open the file -- fail if it does not exist.
  961. //
  962. *FileHandle = CreateFile(
  963. FileName,
  964. GENERIC_READ | GENERIC_WRITE,
  965. 0, // exclusive access
  966. NULL,
  967. OPEN_EXISTING,
  968. 0,
  969. NULL
  970. );
  971. if(*FileHandle == INVALID_HANDLE_VALUE) {
  972. rc = GetLastError();
  973. } else {
  974. //
  975. // Get the size of the file.
  976. //
  977. *FileSize = GetFileSize(*FileHandle,NULL);
  978. if(*FileSize == (DWORD)(-1)) {
  979. rc = GetLastError();
  980. } else {
  981. //
  982. // Create file mapping for the whole file.
  983. //
  984. *MappingHandle = CreateFileMapping(
  985. *FileHandle,
  986. NULL,
  987. PAGE_READWRITE,
  988. 0,
  989. *FileSize,
  990. NULL
  991. );
  992. if(*MappingHandle) {
  993. //
  994. // Map the whole file.
  995. //
  996. *BaseAddress = MapViewOfFile(
  997. *MappingHandle,
  998. FILE_MAP_ALL_ACCESS,
  999. 0,
  1000. 0,
  1001. *FileSize
  1002. );
  1003. if(*BaseAddress) {
  1004. return(NO_ERROR);
  1005. }
  1006. rc = GetLastError();
  1007. CloseHandle(*MappingHandle);
  1008. } else {
  1009. rc = GetLastError();
  1010. }
  1011. }
  1012. CloseHandle(*FileHandle);
  1013. }
  1014. return(rc);
  1015. }