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.

3125 lines
90 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. bootini.c
  5. Abstract:
  6. Code to lay boot blocks on x86, and to configure for boot loader,
  7. including munging/creating boot.ini and bootsect.dos.
  8. Author:
  9. Ted Miller (tedm) 12-November-1992
  10. Revision History:
  11. Sunil Pai ( sunilp ) 2-November-1993 rewrote for new text setup
  12. --*/
  13. #include "spprecmp.h"
  14. #pragma hdrstop
  15. #include "spboot.h"
  16. #include "bootvar.h"
  17. #include "spfile.h" //NEC98
  18. #include <hdlsblk.h>
  19. #include <hdlsterm.h>
  20. extern PDISK_REGION TargetRegion_Nec98; //NEC98
  21. SIGNATURED_PARTITIONS SignedBootVars;
  22. BOOLEAN
  23. SpHasMZHeader(
  24. IN PWSTR FileName
  25. );
  26. NTSTATUS
  27. Spx86WriteBootIni(
  28. IN PWCHAR BootIni,
  29. IN PWSTR **BootVars,
  30. IN ULONG Timeout,
  31. IN PWSTR Default,
  32. IN ULONG Count
  33. );
  34. //
  35. // DefSwitches support
  36. //
  37. UCHAR DefSwitches[128];
  38. UCHAR DefSwitchesNoRedirect[128];
  39. //
  40. // Routines
  41. //
  42. BOOLEAN
  43. Spx86InitBootVars(
  44. OUT PWSTR **BootVars,
  45. OUT PWSTR *Default,
  46. OUT PULONG Timeout
  47. )
  48. {
  49. WCHAR BootIni[512];
  50. HANDLE FileHandle;
  51. HANDLE SectionHandle;
  52. PVOID ViewBase;
  53. NTSTATUS Status;
  54. ULONG FileSize;
  55. PUCHAR BootIniBuf;
  56. PDISK_REGION CColonRegion;
  57. BOOTVAR i;
  58. PUCHAR p;
  59. ULONG index;
  60. //
  61. // Initialize the defaults
  62. //
  63. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  64. BootVars[i] = (PWSTR *)SpMemAlloc( sizeof ( PWSTR * ) );
  65. ASSERT( BootVars[i] );
  66. *BootVars[i] = NULL;
  67. }
  68. *Default = NULL;
  69. *Timeout = DEFAULT_TIMEOUT;
  70. //
  71. // See if there is a valid C: already. If not, then silently fail.
  72. //
  73. if (!IsNEC_98 // NEC98
  74. #if defined(REMOTE_BOOT)
  75. || RemoteBootSetup
  76. #endif // defined(REMOTE_BOOT)
  77. ) {
  78. #if defined(REMOTE_BOOT)
  79. if (RemoteBootSetup && !RemoteInstallSetup) {
  80. ASSERT(RemoteBootTargetRegion != NULL);
  81. CColonRegion = RemoteBootTargetRegion;
  82. } else
  83. #endif // defined(REMOTE_BOOT)
  84. {
  85. CColonRegion = SpPtValidSystemPartition();
  86. if(!CColonRegion) {
  87. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: no C:, no boot.ini!\n"));
  88. return(TRUE);
  89. }
  90. }
  91. //
  92. // Form name of file. Boot.ini better not be on a doublespace drive.
  93. //
  94. ASSERT(CColonRegion->Filesystem != FilesystemDoubleSpace);
  95. SpNtNameFromRegion(CColonRegion,BootIni,sizeof(BootIni),PartitionOrdinalCurrent);
  96. SpConcatenatePaths(BootIni,WBOOT_INI);
  97. //
  98. // Open and map the file.
  99. //
  100. FileHandle = 0;
  101. Status = SpOpenAndMapFile(BootIni,&FileHandle,&SectionHandle,&ViewBase,&FileSize,FALSE);
  102. if(!NT_SUCCESS(Status)) {
  103. return TRUE;
  104. }
  105. //
  106. // Allocate a buffer for the file.
  107. //
  108. BootIniBuf = SpMemAlloc(FileSize+1);
  109. ASSERT(BootIniBuf);
  110. RtlZeroMemory(BootIniBuf, FileSize+1);
  111. //
  112. // Transfer boot.ini into the buffer. We do this because we also
  113. // want to place a 0 byte at the end of the buffer to terminate
  114. // the file.
  115. //
  116. // Guard the RtlMoveMemory because if we touch the memory backed by boot.ini
  117. // and get an i/o error, the memory manager will raise an exception.
  118. try {
  119. RtlMoveMemory(BootIniBuf,ViewBase,FileSize);
  120. }
  121. except( IN_PAGE_ERROR ) {
  122. //
  123. // Do nothing, boot ini processing can proceed with whatever has been
  124. // read
  125. //
  126. }
  127. //
  128. // Not needed since buffer has already been zeroed, however just do this
  129. // just the same
  130. //
  131. BootIniBuf[FileSize] = 0;
  132. //
  133. // Cleanup
  134. //
  135. SpUnmapFile(SectionHandle,ViewBase);
  136. ZwClose(FileHandle);
  137. } else { //NEC98
  138. //
  139. // Serch for all drive which include boot.ini file.
  140. //
  141. FileSize = 0;
  142. BootIniBuf = SpCreateBootiniImage(&FileSize);
  143. if(BootIniBuf == NULL){
  144. return(TRUE);
  145. }
  146. } //NEC98
  147. //
  148. // Do the actual processing of the file.
  149. //
  150. SppProcessBootIni(BootIniBuf, BootVars, Default, Timeout);
  151. //
  152. // Dump the boot vars
  153. //
  154. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Spx86InitBootVars - Boot.ini entries:\n") );
  155. for( index = 0; BootVars[OSLOADPARTITION][index] ; index++ ) {
  156. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " BootVar: %d\n =========\n", index) );
  157. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " OsLoadpartition: %ws\n", BootVars[OSLOADPARTITION][index]) );
  158. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " OsLoadFileName: %ws\n\n", BootVars[OSLOADFILENAME][index]) );
  159. }
  160. //
  161. // Dump the signatures too...
  162. //
  163. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Spx86InitBootVars - Boot.ini signed entries:\n") );
  164. {
  165. SIGNATURED_PARTITIONS *my_ptr = &SignedBootVars;
  166. do{
  167. if( my_ptr->SignedString ) {
  168. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Signature entry:\n================\n") );
  169. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " %ws\n", my_ptr->SignedString) );
  170. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, " %ws\n", my_ptr->MultiString) );
  171. };
  172. my_ptr = my_ptr->Next;
  173. } while( my_ptr );
  174. }
  175. //
  176. // Scan the Buffer to see if there is a DefSwitches line,
  177. // to move into new boot.ini in the [boot loader] section.
  178. // If no DefSwitches, just point to a null string to be moved.
  179. //
  180. DefSwitches[0] = '\0';
  181. for(p=BootIniBuf; *p && (p < BootIniBuf+FileSize-(sizeof("DefSwitches")-1)); p++) {
  182. if(!_strnicmp(p,"DefSwitches",sizeof("DefSwitches")-1)) {
  183. index = 0;
  184. while ((*p != '\r') && (*p != '\n') && *p && (index < sizeof(DefSwitches)-4)) {
  185. DefSwitches[index++] = *p++;
  186. }
  187. DefSwitches[index++] = '\r';
  188. DefSwitches[index++] = '\n';
  189. DefSwitches[index] = '\0';
  190. break;
  191. }
  192. }
  193. //
  194. // get a copy of the defswitches without any redirection switches
  195. //
  196. strcpy(DefSwitchesNoRedirect, DefSwitches);
  197. //
  198. // Now add any headless parameters to the default switches.
  199. // Scan the Buffer to see if there's already a headless line.
  200. // If so, keep it.
  201. //
  202. for(p=BootIniBuf; *p && (p < BootIniBuf+FileSize-(sizeof("redirect=")-1)); p++) {
  203. if(!_strnicmp(p,"[Operat",sizeof("[Operat")-1)) {
  204. //
  205. // We're past the [Boot Loader] section. Stop looking.
  206. //
  207. break;
  208. }
  209. if(!_strnicmp(p,"redirect=",sizeof("redirect=")-1)) {
  210. PUCHAR q = p;
  211. UCHAR temp;
  212. while ((*p != '\r') && (*p != '\n') && *p) {
  213. p++;
  214. }
  215. temp = *p;
  216. *p = '\0';
  217. strcat(DefSwitches, q);
  218. strcat(DefSwitches, "\r\n");
  219. *p = temp;
  220. }
  221. }
  222. //
  223. // Now look for a 'redirectbaudrate' line.
  224. //
  225. for(p=BootIniBuf; *p && (p < BootIniBuf+FileSize-(sizeof("redirectbaudrate=")-1)); p++) {
  226. if(!_strnicmp(p,"[Operat",sizeof("[Operat")-1)) {
  227. //
  228. // We're past the [Boot Loader] section. Stop looking.
  229. //
  230. break;
  231. }
  232. if(!_strnicmp(p,"redirectbaudrate=",sizeof("redirectbaudrate=")-1)) {
  233. PUCHAR q = p;
  234. UCHAR temp;
  235. while ((*p != '\r') && (*p != '\n') && *p) {
  236. p++;
  237. }
  238. temp = *p;
  239. *p = '\0';
  240. strcat(DefSwitches, q);
  241. strcat(DefSwitches, "\r\n");
  242. *p = temp;
  243. }
  244. }
  245. SpMemFree(BootIniBuf);
  246. return( TRUE );
  247. }
  248. BOOLEAN
  249. Spx86FlushBootVars(
  250. IN PWSTR **BootVars,
  251. IN ULONG Timeout,
  252. IN PWSTR Default
  253. )
  254. {
  255. PDISK_REGION CColonRegion;
  256. WCHAR *BootIni;
  257. WCHAR *BootIniBak;
  258. BOOLEAN BootIniBackedUp = FALSE;
  259. NTSTATUS Status;
  260. //
  261. // See if there is a valid C: already. If not, then fail.
  262. //
  263. #if defined(REMOTE_BOOT)
  264. // On a remote boot machine, it's acceptable to have no local disk.
  265. //
  266. #endif // defined(REMOTE_BOOT)
  267. if (!IsNEC_98){ //NEC98
  268. CColonRegion = SpPtValidSystemPartition();
  269. if(!CColonRegion) {
  270. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: no C:, no boot.ini!\n"));
  271. #if defined(REMOTE_BOOT)
  272. if (RemoteBootSetup && !RemoteInstallSetup) {
  273. return(TRUE);
  274. }
  275. #endif // defined(REMOTE_BOOT)
  276. return(FALSE);
  277. }
  278. } else {
  279. //
  280. // CColonRegion equal TargetRegion on NEC98.
  281. //
  282. CColonRegion = TargetRegion_Nec98;
  283. } //NEC98
  284. //
  285. // Allocate the buffers to 2K worth of stack space.
  286. //
  287. BootIni = SpMemAlloc(512*sizeof(WCHAR));
  288. if (!BootIni) {
  289. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: No memory for boot.ini!\n"));
  290. return FALSE;
  291. }
  292. BootIniBak = SpMemAlloc(512*sizeof(WCHAR));
  293. if (!BootIniBak) {
  294. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: No memory for boot.ini.bak!\n"));
  295. SpMemFree(BootIni);
  296. return FALSE;
  297. }
  298. //
  299. // Form name of file. Boot.ini better not be on a doublespace drive.
  300. //
  301. ASSERT(CColonRegion->Filesystem != FilesystemDoubleSpace);
  302. SpNtNameFromRegion(CColonRegion,BootIni,512*sizeof(WCHAR),PartitionOrdinalCurrent);
  303. wcscpy(BootIniBak, BootIni);
  304. SpConcatenatePaths(BootIni,WBOOT_INI);
  305. SpConcatenatePaths(BootIniBak,WBOOT_INI_BAK);
  306. //
  307. // If Boot.ini already exists, delete any backup bootini
  308. // rename the existing bootini to the backup bootini, if unable
  309. // to rename, delete the file
  310. //
  311. if( SpFileExists( BootIni, FALSE ) ) {
  312. if( SpFileExists( BootIniBak, FALSE ) ) {
  313. SpDeleteFile( BootIniBak, NULL, NULL);
  314. }
  315. Status = SpRenameFile( BootIni, BootIniBak, FALSE );
  316. if (!(BootIniBackedUp = NT_SUCCESS( Status ))) {
  317. SpDeleteFile( BootIni, NULL, NULL );
  318. }
  319. }
  320. //
  321. // Write boot.ini.
  322. //
  323. Status = Spx86WriteBootIni(
  324. BootIni,
  325. BootVars,
  326. Timeout,
  327. Default,
  328. 0 // write all lines
  329. );
  330. if(!NT_SUCCESS( Status )) {
  331. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error writing boot.ini!\n"));
  332. goto cleanup;
  333. }
  334. cleanup:
  335. //
  336. // If we were unsuccessful in writing out boot ini then try recovering
  337. // the old boot ini from the backed up file, else delete the backed up
  338. // file.
  339. //
  340. if( !NT_SUCCESS(Status) ) {
  341. //
  342. // If the backup copy of boot ini exists then delete incomplete boot
  343. // ini and rename the backup copy of boot into bootini
  344. //
  345. if ( BootIniBackedUp ) {
  346. SpDeleteFile( BootIni, NULL, NULL );
  347. SpRenameFile( BootIniBak, BootIni, FALSE );
  348. }
  349. }
  350. else {
  351. SpDeleteFile( BootIniBak, NULL, NULL );
  352. }
  353. SpMemFree(BootIni);
  354. SpMemFree(BootIniBak);
  355. return( NT_SUCCESS(Status) );
  356. }
  357. PCHAR
  358. Spx86ConvertToSignatureArcName(
  359. IN PWSTR ArcPathIn,
  360. IN ULONG Signature
  361. )
  362. {
  363. PWSTR s,p,b;
  364. PWSTR UseSignatures;
  365. SIGNATURED_PARTITIONS *SignedEntries = &SignedBootVars;
  366. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Spx86ConvertToSignatureArcName - Incoming ArcPath: %ws\n\tIncoming Signature %lx\n", ArcPathIn, Signature ) );
  367. //
  368. // First, check for any boot.ini entries that already had a 'signature'
  369. // string.
  370. //
  371. do {
  372. if( (SignedEntries->MultiString) && (SignedEntries->SignedString) ) {
  373. if( !_wcsicmp( ArcPathIn, SignedEntries->MultiString ) ) {
  374. //
  375. // We hit. Convert the signatured string
  376. // to ASCII and return.
  377. //
  378. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Spx86ConvertToSignatureArcName - Matched a multi-signed boot.ini entry:\n") );
  379. KdPrintEx( (DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "\t%ws\n\t%ws\n", SignedEntries->MultiString, SignedEntries->SignedString) );
  380. return SpToOem( SignedEntries->SignedString );
  381. }
  382. }
  383. SignedEntries = SignedEntries->Next;
  384. } while( SignedEntries );
  385. #if 0
  386. //
  387. // Don't do this because winnt.exe and CDROM-boot installs won't
  388. // have this entry set, so we won't use signature entries, which
  389. // is a mistake.
  390. //
  391. UseSignatures = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,L"UseSignatures",0);
  392. if (UseSignatures == NULL || _wcsicmp(UseSignatures,WINNT_A_YES_W) != 0) {
  393. //
  394. // Just return the string we came in with.
  395. //
  396. return SpToOem(ArcPathIn);
  397. }
  398. #endif
  399. if (_wcsnicmp( ArcPathIn, L"scsi(", 5 ) != 0) {
  400. //
  401. // If he's anything but a "scsi(..." entry,
  402. // just return the string that was sent in.
  403. //
  404. return SpToOem(ArcPathIn);
  405. }
  406. if( Signature ) {
  407. b = (PWSTR)TemporaryBuffer;
  408. p = ArcPathIn;
  409. s = wcschr( p, L')' ) + 1;
  410. swprintf( b, L"signature(%x)%ws", Signature, s );
  411. return SpToOem( b );
  412. } else {
  413. //
  414. // Just return the string we came in with.
  415. //
  416. return SpToOem(ArcPathIn);
  417. }
  418. }
  419. NTSTATUS
  420. Spx86WriteBootIni(
  421. IN PWCHAR BootIni,
  422. IN PWSTR **BootVars,
  423. IN ULONG Timeout,
  424. IN PWSTR Default,
  425. IN ULONG Count
  426. )
  427. {
  428. IO_STATUS_BLOCK IoStatusBlock;
  429. UNICODE_STRING BootIni_U;
  430. HANDLE fh = NULL;
  431. PCHAR Default_O, Osloadpartition_O, Osloadfilename_O, Osloadoptions_O, Loadidentifier_O;
  432. FILE_BASIC_INFORMATION BasicInfo;
  433. OBJECT_ATTRIBUTES oa;
  434. ULONG i;
  435. NTSTATUS Status1;
  436. NTSTATUS Status;
  437. PWSTR s;
  438. PDISK_REGION Region;
  439. WCHAR _Default[MAX_PATH] = {0};
  440. extern ULONG DefaultSignature;
  441. //
  442. // Open Bootini file. Open if write through because we'll be shutting down
  443. // shortly (this is for safety).
  444. //
  445. RtlInitUnicodeString(&BootIni_U,BootIni);
  446. InitializeObjectAttributes(&oa,&BootIni_U,OBJ_CASE_INSENSITIVE,NULL,NULL);
  447. Status = ZwCreateFile(
  448. &fh,
  449. FILE_GENERIC_WRITE | DELETE,
  450. &oa,
  451. &IoStatusBlock,
  452. NULL,
  453. FILE_ATTRIBUTE_NORMAL,
  454. 0, // no sharing
  455. FILE_OVERWRITE_IF,
  456. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_WRITE_THROUGH,
  457. NULL,
  458. 0
  459. );
  460. if( !NT_SUCCESS( Status ) ) {
  461. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws for writing!\n", BootIni));
  462. goto cleanup;
  463. }
  464. //
  465. // make sure there is a Default specified before we use it.
  466. //
  467. if (Default != NULL) {
  468. //
  469. // use the temporary buffer to form the FLEXBOOT section.
  470. // and then write it out
  471. //
  472. s = NULL;
  473. s = wcschr( Default, L'\\' );
  474. if( s ) {
  475. //
  476. // Save off the Default string, then terminate
  477. // the Default string where the directory path starts.
  478. //
  479. wcscpy( _Default, Default );
  480. *s = L'\0';
  481. s = wcschr( _Default, L'\\' );
  482. }
  483. if( ForceBIOSBoot ) {
  484. //
  485. // If ForceBIOSBoot is TRUE, then we want to
  486. // force a "multi(..." string. Don't even bother calling
  487. // Spx86ConvertToSignatureArcName on the off chance
  488. // that we may get erroneously converted.
  489. //
  490. if (_wcsnicmp( Default, L"scsi(", 5 ) == 0) {
  491. PWSTR MyStringPointer = NULL;
  492. //
  493. // Darn! We have a string that the old standard
  494. // thought should be converted into a signature(...
  495. // string, but we didn't write out a miniport driver.
  496. // That can happen if someone asked us not to via
  497. // an unattend switch.
  498. //
  499. // We need to change the "scsi(" to "multi("
  500. //
  501. // We must preserve Default because we use it later
  502. // for comparison.
  503. //
  504. MyStringPointer = SpScsiArcToMultiArc( Default );
  505. if( MyStringPointer ) {
  506. Default_O = SpToOem( MyStringPointer );
  507. } else {
  508. //
  509. // We're in trouble. Take a shot though. Just
  510. // change the "scsi(" part to "multi(".
  511. //
  512. wcscpy( TemporaryBuffer, L"multi" );
  513. wcscat( TemporaryBuffer, &Default[4] );
  514. Default_O = SpToOem( TemporaryBuffer );
  515. }
  516. } else {
  517. //
  518. // Just convert to ANSI.
  519. //
  520. Default_O = SpToOem( Default );
  521. }
  522. } else {
  523. Default_O = Spx86ConvertToSignatureArcName( Default, DefaultSignature );
  524. }
  525. if( s ) {
  526. //
  527. // We need to append our directory path back on.
  528. //
  529. strcpy( (PCHAR)TemporaryBuffer, Default_O );
  530. SpMemFree( Default_O );
  531. Default_O = SpToOem( s );
  532. strcat( (PCHAR)TemporaryBuffer, Default_O );
  533. SpMemFree( Default_O );
  534. Default_O = SpDupString( (PCHAR)TemporaryBuffer );
  535. }
  536. if (Default_O == NULL) {
  537. Default_O = SpToOem( Default );
  538. }
  539. } else {
  540. //
  541. // the Default was not set, so make a null Default_O
  542. //
  543. Default_O = SpDupString("");
  544. }
  545. ASSERT( Default_O );
  546. //
  547. // See if we should use the loaded redirect switches,
  548. // if there were any, or insert user defined swithes
  549. //
  550. if(RedirectSwitchesMode != UseDefaultSwitches) {
  551. //
  552. // get a copy of the switches up to the [operat region
  553. //
  554. strcpy(DefSwitches, DefSwitchesNoRedirect);
  555. //
  556. // insert our custom switch(s) if appropriate
  557. //
  558. switch(RedirectSwitchesMode){
  559. case DisableRedirect: {
  560. //
  561. // we don't have to do anything here
  562. //
  563. break;
  564. }
  565. case UseUserDefinedRedirect: {
  566. sprintf((PUCHAR)TemporaryBuffer,
  567. "redirect=%s\r\n",
  568. RedirectSwitches.port
  569. );
  570. strcat(DefSwitches, (PUCHAR)TemporaryBuffer);
  571. break;
  572. }
  573. case UseUserDefinedRedirectAndBaudRate: {
  574. sprintf((PUCHAR)TemporaryBuffer,
  575. "redirect=%s\r\n",
  576. RedirectSwitches.port
  577. );
  578. strcat(DefSwitches, (PUCHAR)TemporaryBuffer);
  579. sprintf((PUCHAR)TemporaryBuffer,
  580. "redirectbaudrate=%s\r\n",
  581. RedirectSwitches.baudrate
  582. );
  583. strcat(DefSwitches, (PUCHAR)TemporaryBuffer);
  584. break;
  585. }
  586. default:{
  587. ASSERT(0);
  588. }
  589. }
  590. } else {
  591. //
  592. // Make sure the required headless settings are already in the DefSwitches string before
  593. // we write it out.
  594. //
  595. _strlwr( DefSwitches );
  596. if( !strstr(DefSwitches, "redirect") ) {
  597. PUCHAR p;
  598. HEADLESS_RSP_QUERY_INFO Response;
  599. SIZE_T Length;
  600. //
  601. // There are no headless settings. See if we need to add any.
  602. //
  603. Length = sizeof(HEADLESS_RSP_QUERY_INFO);
  604. Status = HeadlessDispatch(HeadlessCmdQueryInformation,
  605. NULL,
  606. 0,
  607. &Response,
  608. &Length
  609. );
  610. p=NULL;
  611. if (NT_SUCCESS(Status) &&
  612. (Response.PortType == HeadlessSerialPort) &&
  613. Response.Serial.TerminalAttached) {
  614. if (Response.Serial.UsedBiosSettings) {
  615. strcat(DefSwitches, "redirect=UseBiosSettings\r\n");
  616. } else {
  617. switch (Response.Serial.TerminalPort) {
  618. case ComPort1:
  619. p = "redirect=com1\r\n";
  620. break;
  621. case ComPort2:
  622. p = "redirect=com2\r\n";
  623. break;
  624. case ComPort3:
  625. p = "redirect=com3\r\n";
  626. break;
  627. case ComPort4:
  628. p = "redirect=com4\r\n";
  629. break;
  630. default:
  631. ASSERT(0);
  632. p = NULL;
  633. break;
  634. }
  635. if (p) {
  636. strcat(DefSwitches, p);
  637. }
  638. //
  639. // Now take care of the 'redirectbaudrate' entry.
  640. //
  641. switch (Response.Serial.TerminalBaudRate) {
  642. case 115200:
  643. p = "redirectbaudrate=115200\r\n";
  644. break;
  645. case 57600:
  646. p = "redirectbaudrate=57600\r\n";
  647. break;
  648. case 19200:
  649. p = "redirectbaudrate=19200\r\n";
  650. break;
  651. default:
  652. p = "redirectbaudrate=9600\r\n";
  653. break;
  654. }
  655. strcat(DefSwitches, p);
  656. }
  657. }
  658. }
  659. }
  660. sprintf(
  661. (PUCHAR)TemporaryBuffer,
  662. "%s%s%s%s%s%ld%s%s%s%s%s",
  663. FLEXBOOT_SECTION2,
  664. CRLF,
  665. DefSwitches,
  666. TIMEOUT,
  667. EQUALS,
  668. Timeout,
  669. CRLF,
  670. DEFAULT,
  671. EQUALS,
  672. Default_O,
  673. CRLF
  674. );
  675. SpMemFree( Default_O );
  676. Status = ZwWriteFile(
  677. fh,
  678. NULL,
  679. NULL,
  680. NULL,
  681. &IoStatusBlock,
  682. TemporaryBuffer,
  683. strlen((PUCHAR)TemporaryBuffer) * sizeof(UCHAR),
  684. NULL,
  685. NULL
  686. );
  687. if(!NT_SUCCESS( Status )) {
  688. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error writing %s section to %ws!\n", FLEXBOOT_SECTION2, BootIni));
  689. goto cleanup;
  690. }
  691. //
  692. // Now write the BOOTINI_OS_SECTION label to boot.ini
  693. //
  694. sprintf(
  695. (PUCHAR)TemporaryBuffer,
  696. "%s%s",
  697. BOOTINI_OS_SECTION,
  698. CRLF
  699. );
  700. Status = ZwWriteFile(
  701. fh,
  702. NULL,
  703. NULL,
  704. NULL,
  705. &IoStatusBlock,
  706. TemporaryBuffer,
  707. strlen((PUCHAR)TemporaryBuffer) * sizeof(UCHAR),
  708. NULL,
  709. NULL
  710. );
  711. if(!NT_SUCCESS( Status )) {
  712. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error writing %s section to %ws!\n", BOOTINI_OS_SECTION, BootIni));
  713. goto cleanup;
  714. }
  715. //
  716. // run through all the systems that we have and write them out
  717. //
  718. for( i = 0; BootVars[OSLOADPARTITION][i] ; i++ ) {
  719. //
  720. // If we were told to write a specified number of lines, exit
  721. // when we have done that.
  722. //
  723. if (Count && (i == Count)) {
  724. Status = STATUS_SUCCESS;
  725. goto cleanup;
  726. }
  727. ASSERT( BootVars[OSLOADFILENAME][i] );
  728. ASSERT( BootVars[OSLOADOPTIONS][i] );
  729. ASSERT( BootVars[LOADIDENTIFIER][i] );
  730. //
  731. // On some upgrades, if we're upgrading a "signature" entry,
  732. // then we may not have a DefaultSignature. I fixed that case over
  733. // in Spx86ConvertToSignatureArcName. The other case is where
  734. // we have a DefaultSignature, but there are also some "scsi(..."
  735. // entries in the boot.ini that don't pertain to the entry we're
  736. // upgrading. For that case, we need to send in a signature
  737. // of 0 here, which will force Spx86ConvertToSignatureArcName
  738. // to return us the correct item.
  739. //
  740. //
  741. // You thought the hack above was gross... This one's even
  742. // worse. Problem: we don't think we need a miniport to boot,
  743. // but there are some other boot.ini entries (that point to our
  744. // partition) that do. We always want to leave existing
  745. // boot.ini entries alone though, so we'll leave those broken.
  746. //
  747. // Solution: if the OSLOADPARTITION that we're translating ==
  748. // Default, && ForceBIOSBoot is TRUE && we're translating
  749. // the first OSLOADPARTITION (which is the one for our Default),
  750. // then just don't call Spx86ConvertToSignatureArcName.
  751. // This is bad because it assumes that our entry is the first,
  752. // which it is, but it's a shakey assumption.
  753. //
  754. if( !_wcsicmp( BootVars[OSLOADPARTITION][i], Default ) ) {
  755. //
  756. // This might be our Default entry. Make sure it
  757. // really is and if so, process it the same way.
  758. //
  759. if( i == 0 ) {
  760. //
  761. // It is.
  762. //
  763. if( ForceBIOSBoot ) {
  764. //
  765. // If ForceBIOSBoot is TRUE, then we want to
  766. // force a "multi(..." string. Don't even bother calling
  767. // Spx86ConvertToSignatureArcName on the off chance
  768. // that we may get erroneously converted.
  769. //
  770. if (_wcsnicmp( BootVars[OSLOADPARTITION][i], L"scsi(", 5 ) == 0) {
  771. PWSTR MyStringPointer = NULL;
  772. //
  773. // Darn! We have a string that the old standard
  774. // thought should be converted into a signature(...
  775. // string, but we didn't write out a miniport driver.
  776. // That can happen if someone asked us not to via
  777. // an unattend switch.
  778. //
  779. // We need to change the "scsi(" to "multi("
  780. //
  781. MyStringPointer = SpScsiArcToMultiArc( BootVars[OSLOADPARTITION][i] );
  782. if( MyStringPointer ) {
  783. Osloadpartition_O = SpToOem( MyStringPointer );
  784. } else {
  785. //
  786. // We're in trouble. Take a shot though. Just
  787. // change the "scsi(" part to "multi(".
  788. //
  789. wcscpy( TemporaryBuffer, L"multi" );
  790. wcscat( TemporaryBuffer, &BootVars[OSLOADPARTITION][i][4] );
  791. Osloadpartition_O = SpToOem( TemporaryBuffer );
  792. }
  793. } else {
  794. //
  795. // Just convert to ANSI.
  796. //
  797. Osloadpartition_O = SpToOem( BootVars[OSLOADPARTITION][i] );
  798. }
  799. } else {
  800. //
  801. // We may need to convert this entry.
  802. //
  803. Osloadpartition_O = Spx86ConvertToSignatureArcName( BootVars[OSLOADPARTITION][i], DefaultSignature );
  804. }
  805. } else {
  806. //
  807. // This entry looks just like our Default, but it's point
  808. // to a different installation. Just call Spx86ConvertToSignatureArcName
  809. //
  810. Osloadpartition_O = Spx86ConvertToSignatureArcName( BootVars[OSLOADPARTITION][i], DefaultSignature );
  811. }
  812. } else {
  813. //
  814. // This entry doesn't even look like our string. Send in a
  815. // 0x0 DefaultSignature so that it will only get translated if it
  816. // matches some entry that we know was signed in the original boot.ini.
  817. //
  818. Osloadpartition_O = Spx86ConvertToSignatureArcName( BootVars[OSLOADPARTITION][i], 0 );
  819. }
  820. //
  821. // Insurance...
  822. //
  823. if (Osloadpartition_O == NULL) {
  824. Osloadpartition_O = SpToOem( BootVars[OSLOADPARTITION][i] );
  825. }
  826. Osloadfilename_O = SpToOem( BootVars[OSLOADFILENAME][i] );
  827. Osloadoptions_O = SpToOem( BootVars[OSLOADOPTIONS][i] );
  828. Loadidentifier_O = SpToOem( BootVars[LOADIDENTIFIER][i] );
  829. sprintf(
  830. (PUCHAR)TemporaryBuffer,
  831. "%s%s%s%s %s%s",
  832. Osloadpartition_O,
  833. Osloadfilename_O,
  834. EQUALS,
  835. Loadidentifier_O,
  836. Osloadoptions_O,
  837. CRLF
  838. );
  839. SpMemFree( Osloadpartition_O );
  840. SpMemFree( Osloadfilename_O );
  841. SpMemFree( Osloadoptions_O );
  842. SpMemFree( Loadidentifier_O );
  843. Status = ZwWriteFile(
  844. fh,
  845. NULL,
  846. NULL,
  847. NULL,
  848. &IoStatusBlock,
  849. TemporaryBuffer,
  850. strlen((PUCHAR)TemporaryBuffer) * sizeof(UCHAR),
  851. NULL,
  852. NULL
  853. );
  854. if(!NT_SUCCESS( Status )) {
  855. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error writing %s section entry to %ws!\n", BOOTINI_OS_SECTION, BootIni));
  856. goto cleanup;
  857. }
  858. }
  859. //
  860. // Finally write the old operating system line to boot.ini
  861. // (but only if not installing on top of Win9x) and if it was
  862. // not specifically disabled
  863. //
  864. if (!DiscardOldSystemLine && (WinUpgradeType != UpgradeWin95)) {
  865. Status = ZwWriteFile(
  866. fh,
  867. NULL,
  868. NULL,
  869. NULL,
  870. &IoStatusBlock,
  871. OldSystemLine,
  872. strlen(OldSystemLine) * sizeof(UCHAR),
  873. NULL,
  874. NULL
  875. );
  876. if (!NT_SUCCESS(Status)) {
  877. KdPrintEx((DPFLTR_SETUP_ID,
  878. DPFLTR_ERROR_LEVEL,
  879. "SETUP: Error writing %s section line to %ws!\n",
  880. BOOTINI_OS_SECTION,
  881. BootIni));
  882. goto cleanup;
  883. }
  884. }
  885. cleanup:
  886. if( !NT_SUCCESS(Status) ) {
  887. if( fh ) {
  888. ZwClose( fh );
  889. }
  890. }
  891. else {
  892. //
  893. // Set the hidden, system, readonly attributes on bootini. ignore
  894. // error
  895. //
  896. RtlZeroMemory( &BasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
  897. BasicInfo.FileAttributes = FILE_ATTRIBUTE_READONLY |
  898. FILE_ATTRIBUTE_HIDDEN |
  899. FILE_ATTRIBUTE_SYSTEM |
  900. FILE_ATTRIBUTE_ARCHIVE
  901. ;
  902. Status1 = SpSetInformationFile(
  903. fh,
  904. FileBasicInformation,
  905. sizeof(BasicInfo),
  906. &BasicInfo
  907. );
  908. if(!NT_SUCCESS(Status1)) {
  909. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to change attribute of %ws. Status = (%lx). Ignoring error.\n",BootIni,Status1));
  910. }
  911. ZwClose( fh );
  912. }
  913. //
  914. // If we copied out the Default, then
  915. // put the original copy of Default back
  916. //
  917. if (Default != NULL) {
  918. wcscpy(Default, _Default);
  919. }
  920. return Status;
  921. }
  922. VOID
  923. SppProcessBootIni(
  924. IN PCHAR BootIni,
  925. OUT PWSTR **BootVars,
  926. OUT PWSTR *Default,
  927. OUT PULONG Timeout
  928. )
  929. /*++
  930. Routine Description:
  931. Look through the [operating systems] section and save all lines
  932. except the one for "C:\" (previous operating system) and one other
  933. optionally specified line.
  934. Filters out the local boot line (C:\$WIN_NT$.~BT) if present.
  935. Arguments:
  936. Return Value:
  937. --*/
  938. {
  939. PCHAR sect,s,p,n;
  940. PWSTR tmp;
  941. CHAR Key[MAX_PATH], Value[MAX_PATH], RestOfLine[MAX_PATH];
  942. ULONG NumComponents;
  943. BOOTVAR i;
  944. ULONG DiskSignature,digval;
  945. SIGNATURED_PARTITIONS *SignedBootIniVars = &SignedBootVars;;
  946. //
  947. // Process the flexboot section, extract timeout and default
  948. //
  949. sect = SppFindSectionInBootIni(BootIni, FLEXBOOT_SECTION1);
  950. if (!sect) {
  951. sect = SppFindSectionInBootIni(BootIni, FLEXBOOT_SECTION2);
  952. }
  953. if (!sect) {
  954. sect = SppFindSectionInBootIni(BootIni, FLEXBOOT_SECTION3);
  955. }
  956. if ( sect ) {
  957. while (sect = SppNextLineInSection(sect)) {
  958. if( SppProcessLine( sect, Key, Value, RestOfLine) ) {
  959. if ( !_stricmp( Key, TIMEOUT ) ) {
  960. *Timeout = atol( Value );
  961. }
  962. else if( !_stricmp( Key, DEFAULT ) ) {
  963. *Default = SpToUnicode( Value );
  964. }
  965. }
  966. }
  967. }
  968. //
  969. // Process the operating systems section
  970. //
  971. sect = SppFindSectionInBootIni(BootIni,BOOTINI_OS_SECTION);
  972. if(!sect) {
  973. return;
  974. }
  975. NumComponents = 0;
  976. while(sect = SppNextLineInSection(sect)) {
  977. if( SppProcessLine( sect, Key, Value, RestOfLine)) {
  978. PCHAR OsLoaddir;
  979. //
  980. // Check if the line is the old bootloader line in which case just
  981. // save it above, else add it to the BootVars structure
  982. //
  983. if (!IsNEC_98) { //NEC98
  984. if( !_stricmp( Key, "C:\\" ) ) {
  985. sprintf( OldSystemLine, "%s=%s %s\r\n", Key, Value, RestOfLine );
  986. } else {
  987. //
  988. // Ignore if local boot directory. This automatically
  989. // filters out that directory when boot.ini is later flushed.
  990. //
  991. if(_strnicmp(Key,"C:\\$WIN_NT$.~BT",15) && (OsLoaddir = strchr(Key,'\\'))) {
  992. //
  993. // Get the ARC name of the x86 system partition region.
  994. //
  995. PDISK_REGION SystemPartitionRegion;
  996. WCHAR SystemPartitionPath[256];
  997. NumComponents++;
  998. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  999. BootVars[i] = SpMemRealloc( BootVars[i], (NumComponents + 1) * sizeof( PWSTR * ) );
  1000. ASSERT( BootVars[i] );
  1001. BootVars[i][NumComponents] = NULL;
  1002. }
  1003. SystemPartitionRegion = SpPtValidSystemPartition();
  1004. #if defined(REMOTE_BOOT)
  1005. ASSERT(SystemPartitionRegion ||
  1006. (RemoteBootSetup && !RemoteInstallSetup));
  1007. #else
  1008. ASSERT(SystemPartitionRegion);
  1009. #endif // defined(REMOTE_BOOT)
  1010. if (SystemPartitionRegion) {
  1011. SpArcNameFromRegion(
  1012. SystemPartitionRegion,
  1013. SystemPartitionPath,
  1014. sizeof(SystemPartitionPath),
  1015. PartitionOrdinalOriginal,
  1016. PrimaryArcPath
  1017. );
  1018. BootVars[OSLOADER][NumComponents - 1] = SpMemAlloc((wcslen(SystemPartitionPath)*sizeof(WCHAR))+sizeof(L"ntldr")+sizeof(WCHAR));
  1019. wcscpy(BootVars[OSLOADER][NumComponents - 1],SystemPartitionPath);
  1020. SpConcatenatePaths(BootVars[OSLOADER][NumComponents - 1],L"ntldr");
  1021. BootVars[SYSTEMPARTITION][NumComponents - 1] = SpDupStringW( SystemPartitionPath );
  1022. }
  1023. BootVars[LOADIDENTIFIER][NumComponents - 1] = SpToUnicode( Value );
  1024. BootVars[OSLOADOPTIONS][NumComponents - 1] = SpToUnicode( RestOfLine );
  1025. *OsLoaddir = '\0';
  1026. //
  1027. // Now convert the signature entry into a 'multi...' entry.
  1028. //
  1029. s = strstr( Key, "signature(" );
  1030. if (s) {
  1031. s += 10;
  1032. p = strchr( s, ')' );
  1033. if (p) {
  1034. //
  1035. // We've got a boot.ini entry with a 'signature' string.
  1036. // Let's save it off before we convert it into a 'multi'
  1037. // string so we can convert back easily when we're ready
  1038. // to write out the boot.ini.
  1039. //
  1040. if( SignedBootIniVars->SignedString != NULL ) {
  1041. //
  1042. // We've used this entry, get another...
  1043. //
  1044. SignedBootIniVars->Next = SpMemAlloc(sizeof(SIGNATURED_PARTITIONS));
  1045. SignedBootIniVars = SignedBootIniVars->Next;
  1046. //
  1047. // Make sure...
  1048. //
  1049. SignedBootIniVars->Next = NULL;
  1050. SignedBootIniVars->SignedString = NULL;
  1051. SignedBootIniVars->MultiString = NULL;
  1052. }
  1053. SignedBootIniVars->SignedString = SpToUnicode( Key );
  1054. *p = 0;
  1055. DiskSignature = 0;
  1056. for (n=s; *n; n++) {
  1057. if (isdigit((int)(unsigned char)*n)) {
  1058. digval = *n - '0';
  1059. } else if (isxdigit((int)(unsigned char)*n)) {
  1060. digval = toupper(*n) - 'A' + 10;
  1061. } else {
  1062. digval = 0;
  1063. }
  1064. DiskSignature = DiskSignature * 16 + digval;
  1065. }
  1066. *p = ')';
  1067. //
  1068. // !!! ISSUE : 4/27/01 : vijayj !!!
  1069. //
  1070. // Sometimes we might map a arcname to wrong region on
  1071. // disk.
  1072. //
  1073. // Although we compute a new multi(0)... style arcname
  1074. // from the nt device name, we don't have an entry in
  1075. // the map which actually maps the scsi(0)... style
  1076. // arcname to nt device name.
  1077. //
  1078. // In a multi installation scenario, if the current installation
  1079. // is on a disk which is not visible by firmware and the
  1080. // boot.ini has scsi(...) entry for this installation we
  1081. // would convert it into multi(0)... format which could be
  1082. // similar to the actual multi(0) disk. If this is the case
  1083. // and another installation exists on the first disk also
  1084. // with the same partition number and WINDOWS directory
  1085. // then we would end up using the first disk region as the
  1086. // region to upgrade and fail subsequently while trying
  1087. // to match unique IDs. User will end up with "unable to
  1088. // locate installation to upgrade message".
  1089. //
  1090. // Since the probability of all this conditions being replicated
  1091. // on different machines is very very less, currently
  1092. // I am not going to fix this.
  1093. //
  1094. //
  1095. // We've isolated the signature. Now go find a disk
  1096. // with that signature and get his ARC path.
  1097. //
  1098. for(i=0; (ULONG)i<HardDiskCount; i++) {
  1099. if (HardDisks[i].Signature == DiskSignature) {
  1100. tmp = SpNtToArc( HardDisks[i].DevicePath, PrimaryArcPath );
  1101. if( tmp ) {
  1102. wcscpy( (PWSTR)TemporaryBuffer, tmp );
  1103. SpMemFree(tmp);
  1104. p = strstr( Key, "partition(" );
  1105. if( p ) {
  1106. tmp = SpToUnicode(p);
  1107. if( tmp ) {
  1108. wcscat( (PWSTR)TemporaryBuffer, tmp );
  1109. SpMemFree(tmp);
  1110. BootVars[OSLOADPARTITION][NumComponents - 1] = SpDupStringW( (PWSTR)TemporaryBuffer );
  1111. break;
  1112. }
  1113. }
  1114. }
  1115. }
  1116. }
  1117. if ((ULONG)i == HardDiskCount) {
  1118. BootVars[OSLOADPARTITION][NumComponents - 1] = SpToUnicode( Key );
  1119. }
  1120. //
  1121. // Save off the 'multi' entry in our list of signatures.
  1122. //
  1123. SignedBootIniVars->MultiString = SpDupStringW( BootVars[OSLOADPARTITION][NumComponents - 1] );
  1124. }
  1125. } else {
  1126. BootVars[OSLOADPARTITION][NumComponents - 1] = SpToUnicode( Key );
  1127. }
  1128. *OsLoaddir = '\\';
  1129. #if defined(REMOTE_BOOT)
  1130. if (RemoteBootSetup && !RemoteInstallSetup) {
  1131. BootVars[OSLOADFILENAME][NumComponents - 1] = SpToUnicode( strrchr(OsLoaddir,'\\') );
  1132. } else
  1133. #endif // defined(REMOTE_BOOT)
  1134. {
  1135. BootVars[OSLOADFILENAME][NumComponents - 1] = SpToUnicode( OsLoaddir );
  1136. }
  1137. }
  1138. }
  1139. } else { //NEC98
  1140. if (_strnicmp(Key,"C:\\$WIN_NT$.~BT",15) && (OsLoaddir = strchr( Key, '\\' ))) {
  1141. NumComponents++;
  1142. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  1143. BootVars[i] = SpMemRealloc( BootVars[i], (NumComponents + 1) * sizeof( PWSTR * ) );
  1144. ASSERT( BootVars[i] );
  1145. BootVars[i][NumComponents] = NULL;
  1146. }
  1147. BootVars[OSLOADER][NumComponents - 1] = SpMemAlloc(sizeof(L"ntldr")+sizeof(WCHAR));
  1148. wcscpy(BootVars[OSLOADER][NumComponents - 1],L"\\");
  1149. SpConcatenatePaths(BootVars[OSLOADER][NumComponents - 1],L"ntldr");
  1150. BootVars[SYSTEMPARTITION][NumComponents - 1] = SpToUnicode( Key );
  1151. BootVars[LOADIDENTIFIER][NumComponents - 1] = SpToUnicode( Value );
  1152. BootVars[OSLOADOPTIONS][NumComponents - 1] = SpToUnicode( RestOfLine );
  1153. *OsLoaddir = '\0';
  1154. BootVars[OSLOADPARTITION][NumComponents - 1] = SpToUnicode( Key );
  1155. *OsLoaddir = '\\';
  1156. BootVars[OSLOADFILENAME][NumComponents - 1] = SpToUnicode( OsLoaddir );
  1157. ASSERT( BootVars[OSLOADER][NumComponents - 1] );
  1158. ASSERT( BootVars[SYSTEMPARTITION][NumComponents - 1] );
  1159. ASSERT( BootVars[LOADIDENTIFIER][NumComponents - 1] );
  1160. ASSERT( BootVars[OSLOADOPTIONS][NumComponents - 1] );
  1161. ASSERT( BootVars[OSLOADPARTITION][NumComponents - 1] );
  1162. ASSERT( BootVars[OSLOADPARTITION][NumComponents - 1] );
  1163. }
  1164. } //NEC98
  1165. }
  1166. }
  1167. return;
  1168. }
  1169. PCHAR
  1170. SppNextLineInSection(
  1171. IN PCHAR p
  1172. )
  1173. {
  1174. //
  1175. // Find the next \n.
  1176. //
  1177. p = strchr(p,'\n');
  1178. if(!p) {
  1179. return(NULL);
  1180. }
  1181. //
  1182. // skip crs, lfs, spaces, and tabs.
  1183. //
  1184. while(*p && strchr("\r\n \t",*p)) {
  1185. p++;
  1186. }
  1187. // detect if at end of file or section
  1188. if(!(*p) || (*p == '[')) {
  1189. return(NULL);
  1190. }
  1191. return(p);
  1192. }
  1193. PCHAR
  1194. SppFindSectionInBootIni(
  1195. IN PCHAR p,
  1196. IN PCHAR Section
  1197. )
  1198. {
  1199. ULONG len = strlen(Section);
  1200. do {
  1201. //
  1202. // Skip space at front of line
  1203. //
  1204. while(*p && ((*p == ' ') || (*p == '\t'))) {
  1205. p++;
  1206. }
  1207. if(*p) {
  1208. //
  1209. // See if this line matches.
  1210. //
  1211. if(!_strnicmp(p,Section,len)) {
  1212. return(p);
  1213. }
  1214. //
  1215. // Advance to the start of the next line.
  1216. //
  1217. while(*p && (*p != '\n')) {
  1218. p++;
  1219. }
  1220. if(*p) { // skip nl if that terminated the loop.
  1221. p++;
  1222. }
  1223. }
  1224. } while(*p);
  1225. return(NULL);
  1226. }
  1227. BOOLEAN
  1228. SppProcessLine(
  1229. IN PCHAR Line,
  1230. IN OUT PCHAR Key,
  1231. IN OUT PCHAR Value,
  1232. IN OUT PCHAR RestOfLine
  1233. )
  1234. {
  1235. PCHAR p = Line, pLine = Line, pToken;
  1236. CHAR savec;
  1237. BOOLEAN Status = FALSE;
  1238. //
  1239. // Determine end of line
  1240. //
  1241. if(!p) {
  1242. return( Status );
  1243. }
  1244. while( *p && (*p != '\r') && (*p != '\n') ) {
  1245. p++;
  1246. }
  1247. //
  1248. // back up from this position to squeeze out any whitespaces at the
  1249. // end of the line
  1250. //
  1251. while( ((p - 1) >= Line) && strchr(" \t", *(p - 1)) ) {
  1252. p--;
  1253. }
  1254. //
  1255. // terminate the line with null temporarily
  1256. //
  1257. savec = *p;
  1258. *p = '\0';
  1259. //
  1260. // Start at beginning of line and pick out the key
  1261. //
  1262. if ( SppNextToken( pLine, &pToken, &pLine ) ) {
  1263. CHAR savec1 = *pLine;
  1264. *pLine = '\0';
  1265. strcpy( Key, pToken );
  1266. *pLine = savec1;
  1267. //
  1268. // Get next token, it should be a =
  1269. //
  1270. if ( SppNextToken( pLine, &pToken, &pLine ) && *pToken == '=') {
  1271. //
  1272. // Get next token, it will be the value
  1273. //
  1274. if( SppNextToken( pLine, &pToken, &pLine ) ) {
  1275. savec1 = *pLine;
  1276. *pLine = '\0';
  1277. strcpy( Value, pToken );
  1278. *pLine = savec1;
  1279. //
  1280. // if another token exists then take the whole remaining line
  1281. // and make it the RestOfLine token
  1282. //
  1283. if( SppNextToken( pLine, &pToken, &pLine ) ) {
  1284. strcpy( RestOfLine, pToken );
  1285. }
  1286. else {
  1287. *RestOfLine = '\0';
  1288. }
  1289. //
  1290. // We have a well formed line
  1291. //
  1292. Status = TRUE;
  1293. }
  1294. }
  1295. }
  1296. *p = savec;
  1297. return( Status );
  1298. }
  1299. BOOLEAN
  1300. SppNextToken(
  1301. PCHAR p,
  1302. PCHAR *pBegin,
  1303. PCHAR *pEnd
  1304. )
  1305. {
  1306. BOOLEAN Status = FALSE;
  1307. //
  1308. // Validate pointer
  1309. //
  1310. if( !p ) {
  1311. return( Status );
  1312. }
  1313. //
  1314. // Skip whitespace
  1315. //
  1316. while (*p && strchr( " \t", *p ) ) {
  1317. p++;
  1318. }
  1319. //
  1320. // Valid tokens are "=", space delimited strings, quoted strings
  1321. //
  1322. if (*p) {
  1323. *pBegin = p;
  1324. if ( *p == '=' ) {
  1325. *pEnd = p + 1;
  1326. Status = TRUE;
  1327. }
  1328. else if ( *p == '\"' ) {
  1329. if ( p = strchr( p + 1, '\"' ) ) {
  1330. *pEnd = p + 1;
  1331. Status = TRUE;
  1332. }
  1333. }
  1334. else {
  1335. while (*p && !strchr(" \t\"=", *p) ) {
  1336. p++;
  1337. }
  1338. *pEnd = p;
  1339. Status = TRUE;
  1340. }
  1341. }
  1342. return( Status );
  1343. }
  1344. //
  1345. // Boot code stuff.
  1346. //
  1347. NTSTATUS
  1348. pSpBootCodeIo(
  1349. IN PWSTR FilePath,
  1350. IN PWSTR AdditionalFilePath, OPTIONAL
  1351. IN ULONG BytesToRead,
  1352. IN OUT PUCHAR *Buffer,
  1353. IN ULONG OpenDisposition,
  1354. IN BOOLEAN Write,
  1355. IN ULONGLONG Offset,
  1356. IN ULONG BytesPerSector
  1357. )
  1358. {
  1359. PWSTR FullPath;
  1360. PUCHAR buffer = NULL;
  1361. NTSTATUS Status;
  1362. IO_STATUS_BLOCK IoStatusBlock;
  1363. UNICODE_STRING UnicodeString;
  1364. OBJECT_ATTRIBUTES Obja;
  1365. HANDLE Handle;
  1366. LARGE_INTEGER LargeZero;
  1367. PVOID UnalignedMem,AlignedBuffer;
  1368. LargeZero.QuadPart = Offset;
  1369. //
  1370. // Form the name of the file.
  1371. //
  1372. wcscpy((PWSTR)TemporaryBuffer,FilePath);
  1373. if(AdditionalFilePath) {
  1374. SpConcatenatePaths((PWSTR)TemporaryBuffer,AdditionalFilePath);
  1375. }
  1376. FullPath = SpDupStringW((PWSTR)TemporaryBuffer);
  1377. //
  1378. // Open the file.
  1379. //
  1380. INIT_OBJA(&Obja,&UnicodeString,FullPath);
  1381. Status = ZwCreateFile(
  1382. &Handle,
  1383. Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
  1384. &Obja,
  1385. &IoStatusBlock,
  1386. NULL,
  1387. FILE_ATTRIBUTE_NORMAL,
  1388. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1389. OpenDisposition,
  1390. FILE_SYNCHRONOUS_IO_NONALERT | (Write ? FILE_WRITE_THROUGH : 0),
  1391. NULL,
  1392. 0
  1393. );
  1394. if(NT_SUCCESS(Status)) {
  1395. //
  1396. // Allocate a buffer if we are reading.
  1397. // Otherwise the caller passed us the buffer.
  1398. //
  1399. buffer = Write ? *Buffer : SpMemAlloc(BytesToRead);
  1400. //
  1401. // Read or write the disk -- properly aligned. Note that we force at least
  1402. // 512-byte alignment, since there's a hard-coded alignment requirement
  1403. // in the FT driver that must be satisfied.
  1404. //
  1405. if(BytesPerSector < 512) {
  1406. BytesPerSector = 512;
  1407. }
  1408. UnalignedMem = SpMemAlloc(BytesToRead + BytesPerSector);
  1409. AlignedBuffer = ALIGN(UnalignedMem,BytesPerSector);
  1410. if(Write) {
  1411. RtlMoveMemory(AlignedBuffer,buffer,BytesToRead);
  1412. }
  1413. Status = Write
  1414. ?
  1415. ZwWriteFile(
  1416. Handle,
  1417. NULL,
  1418. NULL,
  1419. NULL,
  1420. &IoStatusBlock,
  1421. AlignedBuffer,
  1422. BytesToRead,
  1423. &LargeZero,
  1424. NULL
  1425. )
  1426. :
  1427. ZwReadFile(
  1428. Handle,
  1429. NULL,
  1430. NULL,
  1431. NULL,
  1432. &IoStatusBlock,
  1433. AlignedBuffer,
  1434. BytesToRead,
  1435. &LargeZero,
  1436. NULL
  1437. );
  1438. if(NT_SUCCESS(Status)) {
  1439. if(!Write) {
  1440. RtlMoveMemory(buffer,AlignedBuffer,BytesToRead);
  1441. }
  1442. } else {
  1443. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1444. "SETUP: Unable to %ws %u bytes from %ws (%lx)\n",
  1445. Write ? L"write" : L"read",
  1446. BytesToRead,
  1447. FullPath,
  1448. Status
  1449. ));
  1450. }
  1451. SpMemFree(UnalignedMem);
  1452. //
  1453. // Close the file.
  1454. //
  1455. ZwClose(Handle);
  1456. } else {
  1457. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: pSpBootCodeIo: Unable to open %ws (%lx)\n",FullPath,Status));
  1458. }
  1459. SpMemFree(FullPath);
  1460. if(!Write) {
  1461. if(NT_SUCCESS(Status)) {
  1462. *Buffer = buffer;
  1463. } else {
  1464. if(buffer) {
  1465. SpMemFree(buffer);
  1466. }
  1467. }
  1468. }
  1469. return(Status);
  1470. }
  1471. BOOLEAN
  1472. pSpScanBootcode(
  1473. IN PVOID Buffer,
  1474. IN PCHAR String
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. Look in a boot sector to find an identifying string. The scan starts
  1479. at offset 128 and continues through byte 509 of the buffer.
  1480. The search is case-sensitive.
  1481. Arguments:
  1482. Buffer - buffer to scan
  1483. String - string to scan for
  1484. Return Value:
  1485. --*/
  1486. {
  1487. ULONG len = strlen(String);
  1488. ULONG LastFirstByte = 510 - len;
  1489. ULONG i;
  1490. PCHAR p = Buffer;
  1491. //
  1492. // Use the obvious brute force method.
  1493. //
  1494. for(i=128; i<LastFirstByte; i++) {
  1495. if(!strncmp(p+i,String,len)) {
  1496. return(TRUE);
  1497. }
  1498. }
  1499. return(FALSE);
  1500. }
  1501. VOID
  1502. SpDetermineOsTypeFromBootSector(
  1503. IN PWSTR CColonPath,
  1504. IN PUCHAR BootSector,
  1505. OUT PUCHAR *OsDescription,
  1506. OUT PBOOLEAN IsNtBootcode,
  1507. OUT PBOOLEAN IsOtherOsInstalled,
  1508. IN WCHAR DriveLetter
  1509. )
  1510. {
  1511. PWSTR description;
  1512. PWSTR *FilesToLookFor;
  1513. ULONG FileCount;
  1514. BOOLEAN PossiblyChicago = FALSE;
  1515. PWSTR MsDosFiles[2] = { L"MSDOS.SYS" , L"IO.SYS" };
  1516. //
  1517. // Some versions of PC-DOS have ibmio.com, others have ibmbio.com.
  1518. //
  1519. //PWSTR PcDosFiles[2] = { L"IBMDOS.COM", L"IBMIO.COM" };
  1520. PWSTR PcDosFiles[1] = { L"IBMDOS.COM" };
  1521. PWSTR Os2Files[2] = { L"OS2LDR" , L"OS2KRNL" };
  1522. //
  1523. // Check for nt boot code.
  1524. //
  1525. if(pSpScanBootcode(BootSector,"NTLDR")) {
  1526. *IsNtBootcode = TRUE;
  1527. *IsOtherOsInstalled = FALSE;
  1528. description = L"";
  1529. } else {
  1530. //
  1531. // It's not NT bootcode.
  1532. //
  1533. *IsNtBootcode = FALSE;
  1534. *IsOtherOsInstalled = TRUE;
  1535. //
  1536. // Check for MS-DOS.
  1537. //
  1538. if (pSpScanBootcode(BootSector,((!IsNEC_98) ? "MSDOS SYS" : "IO SYS"))) { //NEC98
  1539. FilesToLookFor = MsDosFiles;
  1540. FileCount = ELEMENT_COUNT(MsDosFiles);
  1541. description = L"MS-DOS";
  1542. PossiblyChicago = TRUE; // Chicago uses same signature files
  1543. } else {
  1544. //
  1545. // Check for PC-DOS.
  1546. //
  1547. if(pSpScanBootcode(BootSector,"IBMDOS COM")) {
  1548. FilesToLookFor = PcDosFiles;
  1549. FileCount = ELEMENT_COUNT(PcDosFiles);
  1550. description = L"PC-DOS";
  1551. } else {
  1552. //
  1553. // Check for OS/2.
  1554. //
  1555. if(pSpScanBootcode(BootSector,"OS2")) {
  1556. FilesToLookFor = Os2Files;
  1557. FileCount = ELEMENT_COUNT(Os2Files);
  1558. description = L"OS/2";
  1559. } else {
  1560. //
  1561. // Not NT, DOS, or OS/2.
  1562. // It's just plain old "previous operating system."
  1563. // Fetch the string from the resources.
  1564. //
  1565. WCHAR DriveLetterString[2];
  1566. DriveLetterString[0] = DriveLetter;
  1567. DriveLetterString[1] = L'\0';
  1568. SpStringToUpper(DriveLetterString);
  1569. FilesToLookFor = NULL;
  1570. FileCount = 0;
  1571. description = (PWSTR)TemporaryBuffer;
  1572. SpFormatMessage(description,sizeof(TemporaryBuffer),SP_TEXT_PREVIOUS_OS, DriveLetterString);
  1573. }
  1574. }
  1575. }
  1576. //
  1577. // If we think we have found an os, check to see whether
  1578. // its signature files are present.
  1579. // We could have, say, a disk where the user formats is using DOS
  1580. // and then installs NT immediately thereafter.
  1581. //
  1582. if(FilesToLookFor) {
  1583. //
  1584. // Copy CColonPath into a larger buffer, because
  1585. // SpNFilesExist wants to append a backslash onto it.
  1586. //
  1587. wcscpy((PWSTR)TemporaryBuffer,CColonPath);
  1588. if(!SpNFilesExist((PWSTR)TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) {
  1589. //
  1590. // Ths os is not really there.
  1591. //
  1592. *IsOtherOsInstalled = FALSE;
  1593. description = L"";
  1594. } else if(PossiblyChicago) {
  1595. wcscpy((PWSTR)TemporaryBuffer, CColonPath);
  1596. SpConcatenatePaths((PWSTR)TemporaryBuffer, L"IO.SYS");
  1597. if(SpHasMZHeader((PWSTR)TemporaryBuffer)) {
  1598. description = L"Microsoft Windows";
  1599. }
  1600. }
  1601. }
  1602. }
  1603. //
  1604. // convert the description to oem text.
  1605. //
  1606. *OsDescription = SpToOem(description);
  1607. }
  1608. VOID
  1609. SpLayBootCode(
  1610. IN OUT PDISK_REGION CColonRegion
  1611. )
  1612. {
  1613. PUCHAR NewBootCode;
  1614. ULONG BootCodeSize;
  1615. PUCHAR ExistingBootCode;
  1616. NTSTATUS Status;
  1617. PUCHAR ExistingBootCodeOs;
  1618. PWSTR CColonPath;
  1619. HANDLE PartitionHandle;
  1620. PWSTR BootsectDosName = L"\\bootsect.dos";
  1621. PWSTR OldBootsectDosName = L"\\bootsect.bak";
  1622. PWSTR BootSectDosFullName, OldBootSectDosFullName, p;
  1623. BOOLEAN IsNtBootcode,OtherOsInstalled, FileExist;
  1624. UNICODE_STRING UnicodeString;
  1625. OBJECT_ATTRIBUTES Obja;
  1626. IO_STATUS_BLOCK IoStatusBlock;
  1627. BOOLEAN BootSectorCorrupt = FALSE;
  1628. ULONG MirrorSector;
  1629. ULONG BytesPerSector;
  1630. ULONGLONG ActualSectorCount, hidden_sectors, super_area_size;
  1631. UCHAR SysId;
  1632. ULONGLONG HiddenSectorCount,VolumeSectorCount; //NEC98
  1633. PUCHAR DiskArraySectorData,TmpBuffer; //NEC98
  1634. ExistingBootCode = NULL;
  1635. BytesPerSector = HardDisks[CColonRegion->DiskNumber].Geometry.BytesPerSector;
  1636. CLEAR_CLIENT_SCREEN();
  1637. SpDisplayStatusText(SP_STAT_INITING_FLEXBOOT,DEFAULT_STATUS_ATTRIBUTE);
  1638. switch(CColonRegion->Filesystem) {
  1639. case FilesystemNewlyCreated:
  1640. //
  1641. // If the filesystem is newly-created, then there is
  1642. // nothing to do, because there can be no previous
  1643. // operating system.
  1644. //
  1645. return;
  1646. case FilesystemNtfs:
  1647. NewBootCode = (!IsNEC_98) ? NtfsBootCode : PC98NtfsBootCode; //NEC98
  1648. BootCodeSize = (!IsNEC_98) ? sizeof(NtfsBootCode) : sizeof(PC98NtfsBootCode); //NEC98
  1649. ASSERT(BootCodeSize == 8192);
  1650. break;
  1651. case FilesystemFat:
  1652. NewBootCode = (!IsNEC_98) ? FatBootCode : PC98FatBootCode; //NEC98
  1653. BootCodeSize = (!IsNEC_98) ? sizeof(FatBootCode) : sizeof(PC98FatBootCode); //NEC98
  1654. ASSERT(BootCodeSize == 512);
  1655. break;
  1656. case FilesystemFat32:
  1657. //
  1658. // Special hackage required for Fat32 because its NT boot code
  1659. // is discontiguous.
  1660. //
  1661. ASSERT(sizeof(Fat32BootCode) == 1536);
  1662. NewBootCode = (!IsNEC_98) ? Fat32BootCode : PC98Fat32BootCode; //NEC98
  1663. BootCodeSize = 512;
  1664. break;
  1665. default:
  1666. if (RepairItems[RepairBootSect]) {
  1667. BootSectorCorrupt = TRUE;
  1668. } else {
  1669. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: bogus filesystem %u for C:!\n",CColonRegion->Filesystem));
  1670. ASSERT(0);
  1671. return;
  1672. }
  1673. }
  1674. //
  1675. // Form the device path to C: and open the partition.
  1676. //
  1677. SpNtNameFromRegion(CColonRegion,(PWSTR)TemporaryBuffer,sizeof(TemporaryBuffer),PartitionOrdinalCurrent);
  1678. CColonPath = SpDupStringW((PWSTR)TemporaryBuffer);
  1679. INIT_OBJA(&Obja,&UnicodeString,CColonPath);
  1680. Status = ZwCreateFile(
  1681. &PartitionHandle,
  1682. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  1683. &Obja,
  1684. &IoStatusBlock,
  1685. NULL,
  1686. FILE_ATTRIBUTE_NORMAL,
  1687. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1688. FILE_OPEN,
  1689. FILE_SYNCHRONOUS_IO_NONALERT,
  1690. NULL,
  1691. 0
  1692. );
  1693. if (!NT_SUCCESS(Status)) {
  1694. KdPrintEx ((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to open the partition for C:!\n"));
  1695. ASSERT(0);
  1696. return;
  1697. }
  1698. //
  1699. // Allocate a buffer and read in the boot sector(s) currently on the disk.
  1700. //
  1701. if (BootSectorCorrupt) {
  1702. //
  1703. // We can't determine the file system type from the boot sector, so
  1704. // we assume it's NTFS if we find a mirror sector, and FAT otherwise.
  1705. //
  1706. if (MirrorSector = NtfsMirrorBootSector (PartitionHandle,
  1707. BytesPerSector, &ExistingBootCode)) {
  1708. //
  1709. // It's NTFS - use the mirror boot sector
  1710. //
  1711. NewBootCode = (!IsNEC_98) ? NtfsBootCode : PC98NtfsBootCode; //NEC98
  1712. BootCodeSize = (!IsNEC_98) ? sizeof(NtfsBootCode) : sizeof(PC98NtfsBootCode); //NEC98
  1713. ASSERT(BootCodeSize == 8192);
  1714. CColonRegion->Filesystem = FilesystemNtfs;
  1715. IsNtBootcode = TRUE;
  1716. } else {
  1717. //
  1718. // It's FAT - create a new boot sector
  1719. //
  1720. NewBootCode = (!IsNEC_98) ? FatBootCode : PC98FatBootCode; //NEC98
  1721. BootCodeSize = (!IsNEC_98) ? sizeof(FatBootCode) : sizeof(PC98FatBootCode); //NEC98
  1722. ASSERT(BootCodeSize == 512);
  1723. CColonRegion->Filesystem = FilesystemFat;
  1724. IsNtBootcode = FALSE;
  1725. SpPtGetSectorLayoutInformation (CColonRegion, &hidden_sectors,
  1726. &ActualSectorCount);
  1727. //
  1728. // No alignment requirement here
  1729. //
  1730. ExistingBootCode = SpMemAlloc(BytesPerSector);
  1731. //
  1732. // This will actually fail with STATUS_BUFFER_TOO_SMALL but it will fill in
  1733. // the bpb, which is what we want
  1734. //
  1735. FmtFillFormatBuffer (
  1736. ActualSectorCount,
  1737. BytesPerSector,
  1738. HardDisks[CColonRegion->DiskNumber].Geometry.SectorsPerTrack,
  1739. HardDisks[CColonRegion->DiskNumber].Geometry.TracksPerCylinder,
  1740. hidden_sectors,
  1741. ExistingBootCode,
  1742. BytesPerSector,
  1743. &super_area_size,
  1744. NULL,
  1745. 0,
  1746. &SysId
  1747. );
  1748. }
  1749. Status = STATUS_SUCCESS;
  1750. } else if (
  1751. RepairItems[RepairBootSect] &&
  1752. CColonRegion->Filesystem == FilesystemNtfs &&
  1753. (MirrorSector = NtfsMirrorBootSector (PartitionHandle, BytesPerSector,
  1754. &ExistingBootCode))
  1755. ) {
  1756. //
  1757. // We use the mirror sector to repair a NTFS file system
  1758. //
  1759. } else {
  1760. //
  1761. // Just use the existing boot code.
  1762. //
  1763. Status = pSpBootCodeIo(
  1764. CColonPath,
  1765. NULL,
  1766. BootCodeSize,
  1767. &ExistingBootCode,
  1768. FILE_OPEN,
  1769. FALSE,
  1770. 0,
  1771. BytesPerSector
  1772. );
  1773. if(CColonRegion->Filesystem == FilesystemNtfs) {
  1774. MirrorSector = NtfsMirrorBootSector(PartitionHandle,BytesPerSector,NULL);
  1775. }
  1776. }
  1777. if(NT_SUCCESS(Status)) {
  1778. //
  1779. // Determine the type of operating system the existing boot sector(s) are for
  1780. // and whether that os is actually installed. Note that we don't need to call
  1781. // this for NTFS.
  1782. //
  1783. if (BootSectorCorrupt) {
  1784. OtherOsInstalled = FALSE;
  1785. ExistingBootCodeOs = NULL;
  1786. } else if(CColonRegion->Filesystem != FilesystemNtfs) {
  1787. SpDetermineOsTypeFromBootSector(
  1788. CColonPath,
  1789. ExistingBootCode,
  1790. &ExistingBootCodeOs,
  1791. &IsNtBootcode,
  1792. &OtherOsInstalled,
  1793. CColonRegion->DriveLetter
  1794. );
  1795. } else {
  1796. IsNtBootcode = TRUE;
  1797. OtherOsInstalled = FALSE;
  1798. ExistingBootCodeOs = NULL;
  1799. }
  1800. //
  1801. // lay down the new boot code
  1802. //
  1803. if(OtherOsInstalled) {
  1804. if(RepairItems[RepairBootSect]) {
  1805. p = (PWSTR)TemporaryBuffer;
  1806. wcscpy(p,CColonPath);
  1807. SpConcatenatePaths(p,OldBootsectDosName);
  1808. OldBootSectDosFullName = SpDupStringW(p);
  1809. p = (PWSTR)TemporaryBuffer;
  1810. wcscpy(p,CColonPath);
  1811. SpConcatenatePaths(p,BootsectDosName);
  1812. BootSectDosFullName = SpDupStringW(p);
  1813. //
  1814. // If bootsect.dos already exists, we need to delete
  1815. // bootsect.pre, which may or may not exist and
  1816. // rename the bootsect.dos to bootsect.pre.
  1817. //
  1818. FileExist = SpFileExists(BootSectDosFullName, FALSE);
  1819. if (SpFileExists(OldBootSectDosFullName, FALSE) && FileExist) {
  1820. SpDeleteFile(CColonPath,OldBootsectDosName,NULL);
  1821. }
  1822. if (FileExist) {
  1823. SpRenameFile(BootSectDosFullName, OldBootSectDosFullName, FALSE);
  1824. }
  1825. SpMemFree(BootSectDosFullName);
  1826. SpMemFree(OldBootSectDosFullName);
  1827. } else {
  1828. //
  1829. // Delete bootsect.dos in preparation for rewriting it below.
  1830. // Doing this leverages code to set its attributes in SpDeleteFile.
  1831. // (We need to remove read-only attribute before overwriting).
  1832. //
  1833. SpDeleteFile(CColonPath,BootsectDosName,NULL);
  1834. }
  1835. //
  1836. // Write out the existing (old) boot sector into c:\bootsect.dos.
  1837. //
  1838. Status = pSpBootCodeIo(
  1839. CColonPath,
  1840. BootsectDosName,
  1841. BootCodeSize,
  1842. &ExistingBootCode,
  1843. FILE_OVERWRITE_IF,
  1844. TRUE,
  1845. 0,
  1846. BytesPerSector
  1847. );
  1848. //
  1849. // Set the description text to the description calculated
  1850. // by SpDetermineOsTypeFromBootSector().
  1851. //
  1852. _snprintf(
  1853. OldSystemLine,
  1854. sizeof(OldSystemLine),
  1855. "C:\\ = \"%s\"\r\n",
  1856. ExistingBootCodeOs
  1857. );
  1858. } // end if(OtherOsInstalled)
  1859. if(NT_SUCCESS(Status)) {
  1860. //
  1861. // Transfer the bpb from the existing boot sector into the boot code buffer
  1862. // and make sure the physical drive field is set to hard disk (0x80).
  1863. //
  1864. // The first three bytes of the NT boot code are going to be something like
  1865. // EB 3C 90, which is intel jump instruction to an offset in the boot sector,
  1866. // past the BPB, to continue execution. We want to preserve everything in the
  1867. // current boot sector up to the start of that code. Instead of harcoding
  1868. // a value, we'll use the offset of the jump instruction to determine how many
  1869. // bytes must be preserved.
  1870. //
  1871. RtlMoveMemory(NewBootCode+3,ExistingBootCode+3,NewBootCode[1]-1);
  1872. if(CColonRegion->Filesystem != FilesystemFat32) {
  1873. //
  1874. // On fat32 this overwrites the BigNumFatSecs field,
  1875. // a very bad thing to do indeed!
  1876. //
  1877. NewBootCode[36] = 0x80;
  1878. }
  1879. //
  1880. // get Hidden sector informatin.
  1881. //
  1882. if (IsNEC_98) { //NEC98
  1883. SpPtGetSectorLayoutInformation(
  1884. CColonRegion,
  1885. &HiddenSectorCount,
  1886. &VolumeSectorCount // not used
  1887. );
  1888. //
  1889. // write Hidden sector informatin.
  1890. //
  1891. if (!RepairWinnt) { // for install a partition where before DOS 3.x
  1892. *((ULONG *)&(NewBootCode[0x1c])) = (ULONG)HiddenSectorCount;
  1893. if(*((USHORT *)&(NewBootCode[0x13])) != 0) {
  1894. *((ULONG *)&(NewBootCode[0x20])) = 0L;
  1895. }
  1896. }
  1897. } //NEC98
  1898. //
  1899. // Write out boot code buffer, which now contains the valid bpb,
  1900. // to the boot sector(s).
  1901. //
  1902. Status = pSpBootCodeIo(
  1903. CColonPath,
  1904. NULL,
  1905. BootCodeSize,
  1906. &NewBootCode,
  1907. FILE_OPEN,
  1908. TRUE,
  1909. 0,
  1910. BytesPerSector
  1911. );
  1912. //
  1913. // Special case for Fat32, which has a second sector of boot code
  1914. // at sector 12, discontiguous from the code on sector 0.
  1915. //
  1916. if(NT_SUCCESS(Status) && (CColonRegion->Filesystem == FilesystemFat32)) {
  1917. NewBootCode = (!IsNEC_98) ? Fat32BootCode + 1024
  1918. : PC98Fat32BootCode + 1024; //NEC98
  1919. Status = pSpBootCodeIo(
  1920. CColonPath,
  1921. NULL,
  1922. BootCodeSize,
  1923. &NewBootCode,
  1924. FILE_OPEN,
  1925. TRUE,
  1926. 12*512,
  1927. BytesPerSector
  1928. );
  1929. }
  1930. //
  1931. // Update the mirror boot sector.
  1932. //
  1933. if((CColonRegion->Filesystem == FilesystemNtfs) && MirrorSector) {
  1934. WriteNtfsBootSector(PartitionHandle,BytesPerSector,NewBootCode,MirrorSector);
  1935. }
  1936. }
  1937. if(ExistingBootCodeOs) {
  1938. SpMemFree(ExistingBootCodeOs);
  1939. }
  1940. }
  1941. if(ExistingBootCode) {
  1942. SpMemFree(ExistingBootCode);
  1943. }
  1944. SpMemFree(CColonPath);
  1945. ZwClose (PartitionHandle);
  1946. //
  1947. // Handle the error case.
  1948. //
  1949. if(!NT_SUCCESS(Status)) {
  1950. WCHAR DriveLetterString[2];
  1951. DriveLetterString[0] = CColonRegion->DriveLetter;
  1952. DriveLetterString[1] = L'\0';
  1953. SpStringToUpper(DriveLetterString);
  1954. SpStartScreen(SP_SCRN_CANT_INIT_FLEXBOOT,
  1955. 3,
  1956. HEADER_HEIGHT+1,
  1957. FALSE,
  1958. FALSE,
  1959. DEFAULT_ATTRIBUTE,
  1960. DriveLetterString,
  1961. DriveLetterString
  1962. );
  1963. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  1964. SpInputDrain();
  1965. while(SpInputGetKeypress() != KEY_F3) ;
  1966. SpDone(0,FALSE,TRUE);
  1967. }
  1968. }
  1969. #if defined(REMOTE_BOOT)
  1970. BOOLEAN
  1971. Spx86FlushRemoteBootVars(
  1972. IN PDISK_REGION TargetRegion,
  1973. IN PWSTR **BootVars,
  1974. IN PWSTR Default
  1975. )
  1976. {
  1977. WCHAR BootIni[512];
  1978. NTSTATUS Status;
  1979. //
  1980. // Form the path to boot.ini.
  1981. //
  1982. SpNtNameFromRegion(TargetRegion,BootIni,sizeof(BootIni),PartitionOrdinalCurrent);
  1983. SpConcatenatePaths(BootIni,WBOOT_INI);
  1984. //
  1985. // If Boot.ini already exists, delete it.
  1986. //
  1987. if( SpFileExists( BootIni, FALSE ) ) {
  1988. SpDeleteFile( BootIni, NULL, NULL );
  1989. }
  1990. Status = Spx86WriteBootIni(
  1991. BootIni,
  1992. BootVars,
  1993. 1, // timeout
  1994. Default,
  1995. 1 // only write one line
  1996. );
  1997. if(!NT_SUCCESS( Status )) {
  1998. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Error writing boot.ini!\n"));
  1999. goto cleanup;
  2000. }
  2001. cleanup:
  2002. return( NT_SUCCESS(Status) );
  2003. }
  2004. #endif // defined(REMOTE_BOOT)
  2005. BOOLEAN
  2006. SpHasMZHeader(
  2007. IN PWSTR FileName
  2008. )
  2009. {
  2010. HANDLE FileHandle;
  2011. HANDLE SectionHandle;
  2012. PVOID ViewBase;
  2013. ULONG FileSize;
  2014. NTSTATUS Status;
  2015. PUCHAR Header;
  2016. BOOLEAN Ret = FALSE;
  2017. //
  2018. // Open and map the file.
  2019. //
  2020. FileHandle = 0;
  2021. Status = SpOpenAndMapFile(FileName,
  2022. &FileHandle,
  2023. &SectionHandle,
  2024. &ViewBase,
  2025. &FileSize,
  2026. FALSE
  2027. );
  2028. if(!NT_SUCCESS(Status)) {
  2029. return FALSE;
  2030. }
  2031. Header = (PUCHAR)ViewBase;
  2032. //
  2033. // Guard with try/except in case we get an inpage error
  2034. //
  2035. try {
  2036. if((FileSize >= 2) && (Header[0] == 'M') && (Header[1] == 'Z')) {
  2037. Ret = TRUE;
  2038. }
  2039. } except(IN_PAGE_ERROR) {
  2040. //
  2041. // Do nothing, we simply want to return FALSE.
  2042. //
  2043. }
  2044. SpUnmapFile(SectionHandle, ViewBase);
  2045. ZwClose(FileHandle);
  2046. return Ret;
  2047. }
  2048. //
  2049. // NEC98
  2050. //
  2051. PUCHAR
  2052. SpCreateBootiniImage(
  2053. OUT PULONG FileSize
  2054. )
  2055. {
  2056. PUCHAR BootIniBuf,IniImageBuf,IniImageBufSave,IniCreateBuf,IniCreateBufSave;
  2057. PUCHAR FindSectPtr;
  2058. PUCHAR sect; // point to target section. if it is NULL,not existing target section.
  2059. PUCHAR pArcNameA;
  2060. WCHAR TempBuffer[256];
  2061. WCHAR TempArcPath[256];
  2062. ULONG NtDirLen,TotalNtDirlen,CreateBufCnt;
  2063. ULONG Timeout;
  2064. ULONG Disk;
  2065. ULONG BootiniSize;
  2066. ULONG ArcNameLen;
  2067. PDISK_REGION pRegion;
  2068. HANDLE fh;
  2069. HANDLE SectionHandle;
  2070. PVOID ViewBase;
  2071. #define Default_Dir "\\MOCHI"
  2072. if(!HardDiskCount){
  2073. return(NULL);
  2074. }
  2075. //
  2076. // Create basic style of boot.ini image and progress pointer end of line.
  2077. //
  2078. NtDirLen = TotalNtDirlen = CreateBufCnt = 0;
  2079. IniCreateBufSave = IniCreateBuf = SpMemAlloc(1024);
  2080. RtlZeroMemory(IniCreateBuf,1024);
  2081. Timeout = DEFAULT_TIMEOUT;
  2082. sprintf(
  2083. IniCreateBuf,
  2084. "%s%s%s%s%ld%s%s%s%s%s%s%s%s",
  2085. FLEXBOOT_SECTION2, // [boot loader]
  2086. CRLF,
  2087. TIMEOUT,
  2088. EQUALS,
  2089. Timeout,
  2090. CRLF,
  2091. DEFAULT,
  2092. EQUALS,
  2093. "c:",
  2094. Default_Dir,
  2095. CRLF
  2096. BOOTINI_OS_SECTION, // [operating systems]
  2097. CRLF
  2098. );
  2099. sect = SppFindSectionInBootIni(IniCreateBuf,FLEXBOOT_SECTION2);
  2100. if(sect == NULL){
  2101. return(NULL);
  2102. }
  2103. for( IniCreateBuf = sect; *IniCreateBuf && (*IniCreateBuf != '\n'); IniCreateBuf++,CreateBufCnt++);
  2104. CreateBufCnt++;
  2105. sect = SppFindSectionInBootIni(IniCreateBuf,TIMEOUT);
  2106. if(sect == NULL){
  2107. return(NULL);
  2108. }
  2109. for( IniCreateBuf = sect; *IniCreateBuf && (*IniCreateBuf != '\n'); IniCreateBuf++,CreateBufCnt++);
  2110. CreateBufCnt++;
  2111. sect = SppFindSectionInBootIni(IniCreateBuf,DEFAULT);
  2112. if(sect == NULL){
  2113. return(NULL);
  2114. }
  2115. for( IniCreateBuf = sect; *IniCreateBuf && (*IniCreateBuf != '\n'); IniCreateBuf++,CreateBufCnt++);
  2116. CreateBufCnt++;
  2117. sect = SppFindSectionInBootIni(IniCreateBuf,BOOTINI_OS_SECTION);
  2118. if(sect == NULL){
  2119. return(NULL);
  2120. }
  2121. for( IniCreateBuf = sect; *IniCreateBuf && (*IniCreateBuf != '\n'); IniCreateBuf++,CreateBufCnt++);
  2122. IniCreateBuf++;
  2123. CreateBufCnt++;
  2124. //
  2125. // Read boot.ini files from all drives.(except sleep and non bootable drives.)
  2126. //
  2127. for(Disk=0; Disk < HardDiskCount; Disk++){
  2128. for(pRegion=PartitionedDisks[Disk].PrimaryDiskRegions; pRegion;pRegion=pRegion->Next){
  2129. if(!pRegion->PartitionedSpace) {
  2130. continue;
  2131. }
  2132. SpNtNameFromRegion(
  2133. pRegion,
  2134. TempBuffer,
  2135. sizeof(TempBuffer),
  2136. PartitionOrdinalCurrent
  2137. );
  2138. SpConcatenatePaths(TempBuffer,WBOOT_INI);
  2139. //
  2140. // Open and map the boot.ini file.
  2141. //
  2142. fh = 0;
  2143. if(!NT_SUCCESS(SpOpenAndMapFile(TempBuffer,&fh,&SectionHandle,&ViewBase,&BootiniSize,FALSE))) {
  2144. continue;
  2145. }
  2146. //
  2147. // Allocate a buffer for the file.
  2148. //
  2149. IniImageBuf = SpMemAlloc(BootiniSize+1);
  2150. IniImageBufSave = IniImageBuf;
  2151. ASSERT(IniImageBuf);
  2152. RtlZeroMemory(IniImageBuf, BootiniSize+1);
  2153. //
  2154. // Transfer boot.ini into the buffer. We do this because we also
  2155. // want to place a 0 byte at the end of the buffer to terminate
  2156. // the file.
  2157. //
  2158. // Guard the RtlMoveMemory because if we touch the memory backed by boot.ini
  2159. // and get an i/o error, the memory manager will raise an exception.
  2160. try {
  2161. RtlMoveMemory(IniImageBuf,ViewBase,BootiniSize);
  2162. }
  2163. except( IN_PAGE_ERROR ) {
  2164. //
  2165. // Do nothing, boot ini processing can proceed with whatever has been
  2166. // read
  2167. //
  2168. }
  2169. //
  2170. // check out existing target section in boot.ini
  2171. //
  2172. sect = SppFindSectionInBootIni(IniImageBuf,FLEXBOOT_SECTION2);
  2173. if(sect==NULL){
  2174. SpMemFree(IniImageBufSave);
  2175. SpUnmapFile(SectionHandle,ViewBase);
  2176. ZwClose(fh);
  2177. continue;
  2178. }
  2179. sect = SppFindSectionInBootIni(IniImageBuf,DEFAULT);
  2180. if(sect==NULL){
  2181. SpMemFree(IniImageBufSave);
  2182. SpUnmapFile(SectionHandle,ViewBase);
  2183. ZwClose(fh);
  2184. continue;
  2185. }
  2186. sect = SppFindSectionInBootIni(IniImageBuf,BOOTINI_OS_SECTION);
  2187. if(sect == NULL){
  2188. SpUnmapFile(SectionHandle,ViewBase);
  2189. ZwClose(fh);
  2190. continue;
  2191. }
  2192. //
  2193. // move pointer to end of line and skip the space.
  2194. //
  2195. for( IniImageBuf = sect; *IniImageBuf && (*IniImageBuf != '\n'); IniImageBuf++ );
  2196. for( ; *IniImageBuf && (( *IniImageBuf == ' ' ) || (*IniImageBuf == '\t')) ; IniImageBuf++ );
  2197. IniImageBuf++;
  2198. FindSectPtr = IniImageBuf;
  2199. //
  2200. // NOTE:
  2201. // override arc name when boot path written as "C:", not as arc name.
  2202. //
  2203. ArcNameLen = 0;
  2204. pArcNameA = (PUCHAR)NULL;
  2205. if( ( *(IniImageBuf+1) == L':' )&&( *(IniImageBuf+2) == L'\\' ) ) {
  2206. //
  2207. // This is NEC98 legacy style format, like "C:\WINNT=...",
  2208. // So translate to arc name for boot.ini in NT 5.0
  2209. //
  2210. SpArcNameFromRegion(pRegion,
  2211. TempArcPath,
  2212. sizeof(TempArcPath),
  2213. PartitionOrdinalOriginal,
  2214. PrimaryArcPath
  2215. );
  2216. pArcNameA = SpToOem(TempArcPath);
  2217. if( pArcNameA ) {
  2218. ArcNameLen = strlen(pArcNameA);
  2219. IniImageBuf += 2;
  2220. FindSectPtr = IniImageBuf;
  2221. }
  2222. }
  2223. for( NtDirLen = 0 ; *IniImageBuf && (*IniImageBuf != '\n');NtDirLen++,IniImageBuf++);
  2224. NtDirLen++;
  2225. if( ArcNameLen && pArcNameA ) { // Only case of override arc path.
  2226. RtlMoveMemory( IniCreateBuf+TotalNtDirlen, pArcNameA, ArcNameLen );
  2227. TotalNtDirlen += ArcNameLen;
  2228. SpMemFree(pArcNameA);
  2229. }
  2230. RtlMoveMemory(IniCreateBuf+TotalNtDirlen,FindSectPtr,NtDirLen);
  2231. TotalNtDirlen += NtDirLen;
  2232. SpMemFree(IniImageBufSave);
  2233. SpUnmapFile(SectionHandle,ViewBase);
  2234. ZwClose(fh);
  2235. }
  2236. }
  2237. if(TotalNtDirlen == 0){
  2238. SpMemFree(IniCreateBufSave);
  2239. return(NULL);
  2240. }
  2241. BootIniBuf = SpMemAlloc(CreateBufCnt + TotalNtDirlen + 1);
  2242. if(!(BootIniBuf)){
  2243. SpMemFree(IniCreateBufSave);
  2244. return(NULL);
  2245. }
  2246. if(FileSize) {
  2247. *FileSize = CreateBufCnt + TotalNtDirlen;
  2248. }
  2249. RtlZeroMemory(BootIniBuf,CreateBufCnt + TotalNtDirlen + 1);
  2250. RtlMoveMemory(BootIniBuf,IniCreateBufSave,CreateBufCnt + TotalNtDirlen);
  2251. BootIniBuf[CreateBufCnt + TotalNtDirlen] = 0;
  2252. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Create NT List\n%s\n",BootIniBuf));
  2253. SpMemFree(IniCreateBufSave);
  2254. return(BootIniBuf);
  2255. }
  2256. //
  2257. // NEC98
  2258. //
  2259. BOOLEAN
  2260. SppReInitializeBootVars_Nec98(
  2261. OUT PWSTR **BootVars,
  2262. OUT PWSTR *Default,
  2263. OUT PULONG Timeout
  2264. )
  2265. {
  2266. WCHAR BootIni[512];
  2267. HANDLE FileHandle;
  2268. HANDLE SectionHandle;
  2269. PVOID ViewBase;
  2270. NTSTATUS Status;
  2271. ULONG FileSize;
  2272. PUCHAR BootIniBuf;
  2273. PDISK_REGION CColonRegion;
  2274. BOOTVAR i;
  2275. PUCHAR p;
  2276. ULONG index;
  2277. PUCHAR TmpBootIniBuf;
  2278. PUCHAR pBuf;
  2279. PUCHAR pTmpBuf;
  2280. PUCHAR pArcNameA;
  2281. PUCHAR NtDir;
  2282. ULONG ArcNameLen;
  2283. ULONG NtDirLen;
  2284. WCHAR TempArcPath[256];
  2285. BOOLEAN IsChanged = FALSE;
  2286. SIZE_T Length;
  2287. HEADLESS_RSP_QUERY_INFO Response;
  2288. //
  2289. // Initialize the defaults
  2290. //
  2291. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  2292. if(BootVars[i]){
  2293. SpMemFree(BootVars[i]);
  2294. }
  2295. }
  2296. for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
  2297. BootVars[i] = (PWSTR *)SpMemAlloc( sizeof ( PWSTR * ) );
  2298. ASSERT( BootVars[i] );
  2299. *BootVars[i] = NULL;
  2300. }
  2301. *Default = NULL;
  2302. *Timeout = DEFAULT_TIMEOUT;
  2303. //
  2304. // Just clear BOOTVARS[] when fresh setup.
  2305. //
  2306. if(NTUpgrade != UpgradeFull)
  2307. return TRUE;
  2308. //
  2309. // See if there is a valid C: already. If not, then silently fail.
  2310. //
  2311. #if defined(REMOTE_BOOT)
  2312. if (RemoteBootSetup && !RemoteInstallSetup) {
  2313. ASSERT(RemoteBootTargetRegion != NULL);
  2314. CColonRegion = RemoteBootTargetRegion;
  2315. } else
  2316. #endif // defined(REMOTE_BOOT)
  2317. {
  2318. CColonRegion = TargetRegion_Nec98;
  2319. }
  2320. //
  2321. // Form name of file. Boot.ini better not be on a doublespace drive.
  2322. //
  2323. ASSERT(CColonRegion->Filesystem != FilesystemDoubleSpace);
  2324. SpNtNameFromRegion(CColonRegion,BootIni,sizeof(BootIni),PartitionOrdinalCurrent);
  2325. SpConcatenatePaths(BootIni,WBOOT_INI);
  2326. //
  2327. // Open and map the file.
  2328. //
  2329. FileHandle = 0;
  2330. Status = SpOpenAndMapFile(BootIni,&FileHandle,&SectionHandle,&ViewBase,&FileSize,FALSE);
  2331. if(!NT_SUCCESS(Status)) {
  2332. return TRUE;
  2333. }
  2334. //
  2335. // Allocate a buffer for the file.
  2336. //
  2337. BootIniBuf = SpMemAlloc(FileSize+1);
  2338. ASSERT(BootIniBuf);
  2339. RtlZeroMemory(BootIniBuf, FileSize+1);
  2340. //
  2341. // Transfer boot.ini into the buffer. We do this because we also
  2342. // want to place a 0 byte at the end of the buffer to terminate
  2343. // the file.
  2344. //
  2345. // Guard the RtlMoveMemory because if we touch the memory backed by boot.ini
  2346. // and get an i/o error, the memory manager will raise an exception.
  2347. try {
  2348. RtlMoveMemory(BootIniBuf,ViewBase,FileSize);
  2349. }
  2350. except( IN_PAGE_ERROR ) {
  2351. //
  2352. // Do nothing, boot ini processing can proceed with whatever has been
  2353. // read
  2354. //
  2355. }
  2356. //
  2357. // Not needed since buffer has already been zeroed, however just do this
  2358. // just the same
  2359. //
  2360. BootIniBuf[FileSize] = 0;
  2361. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Create NT List\n%s\n",BootIniBuf));
  2362. //***
  2363. TmpBootIniBuf = SpMemAlloc(FileSize+256);
  2364. RtlZeroMemory(TmpBootIniBuf,FileSize+256);
  2365. RtlMoveMemory(TmpBootIniBuf,BootIniBuf,FileSize);
  2366. pBuf = SppFindSectionInBootIni(BootIniBuf,BOOTINI_OS_SECTION);
  2367. pTmpBuf = SppFindSectionInBootIni(TmpBootIniBuf,BOOTINI_OS_SECTION);
  2368. if (pBuf && pTmpBuf) {
  2369. while( *pBuf && (pBuf < BootIniBuf+FileSize-(sizeof("C:\\")-1)) ) {
  2370. if((!_strnicmp(pBuf,"C:\\",sizeof("C:\\")-1))||
  2371. (!_strnicmp(pBuf,"c:\\",sizeof("c:\\")-1))) {
  2372. ArcNameLen = 0;
  2373. pArcNameA = NULL;
  2374. p = strchr(pBuf+3,'='); // *(pBuf+3) == '\\'
  2375. if((p != pBuf+3) && (*p == '=')) {
  2376. NtDirLen = p - (pBuf+3);
  2377. NtDir = SpMemAlloc(NtDirLen+1);
  2378. RtlZeroMemory(NtDir,NtDirLen+1);
  2379. RtlMoveMemory(NtDir,pBuf+3,NtDirLen);
  2380. if(SpIsNtInDirectory(TargetRegion_Nec98,SpToUnicode(NtDir))){
  2381. SpArcNameFromRegion(TargetRegion_Nec98,
  2382. TempArcPath,
  2383. sizeof(TempArcPath),
  2384. PartitionOrdinalOriginal,
  2385. PrimaryArcPath
  2386. );
  2387. if(pArcNameA=SpToOem(TempArcPath)) {
  2388. ArcNameLen = strlen(pArcNameA);
  2389. RtlMoveMemory(pTmpBuf,pArcNameA,ArcNameLen);
  2390. pBuf += 2;
  2391. pTmpBuf += ArcNameLen;
  2392. if( !IsChanged)
  2393. IsChanged = TRUE;
  2394. SpMemFree(NtDir);
  2395. continue;
  2396. }
  2397. }
  2398. SpMemFree(NtDir);
  2399. }
  2400. }
  2401. *pTmpBuf = *pBuf;
  2402. pBuf++;
  2403. pTmpBuf++;
  2404. }
  2405. }
  2406. if (IsChanged) {
  2407. if (pTmpBuf) {
  2408. *pTmpBuf = 0;
  2409. }
  2410. SpMemFree(BootIniBuf);
  2411. BootIniBuf = TmpBootIniBuf;
  2412. TmpBootIniBuf = (PUCHAR)NULL;
  2413. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2414. "SETUP: Create New NT List\n%s\n",BootIniBuf));
  2415. } else {
  2416. SpMemFree(TmpBootIniBuf);
  2417. TmpBootIniBuf = (PUCHAR)NULL;
  2418. }
  2419. //
  2420. // Cleanup
  2421. //
  2422. SpUnmapFile(SectionHandle,ViewBase);
  2423. ZwClose(FileHandle);
  2424. //
  2425. // Do the actual processing of the file.
  2426. //
  2427. SppProcessBootIni(BootIniBuf, BootVars, Default, Timeout);
  2428. //
  2429. // Scan the Buffer to see if there is a DefSwitches line,
  2430. // to move into new boot.ini in the [boot loader] section.
  2431. // If no DefSwitches, just point to a null string to be moved.
  2432. //
  2433. DefSwitches[0] = '\0';
  2434. for(p=BootIniBuf; *p && (p < BootIniBuf+FileSize-(sizeof("DefSwitches")-1)); p++) {
  2435. if(!_strnicmp(p,"DefSwitches",sizeof("DefSwitches")-1)) {
  2436. index = 0;
  2437. while ((*p != '\r') && (*p != '\n') && *p && (index < sizeof(DefSwitches)-4)) {
  2438. DefSwitches[index++] = *p++;
  2439. }
  2440. DefSwitches[index++] = '\r';
  2441. DefSwitches[index++] = '\n';
  2442. DefSwitches[index] = '\0';
  2443. break;
  2444. }
  2445. }
  2446. //
  2447. // Now add any headless parameters to the default switches.
  2448. //
  2449. Length = sizeof(HEADLESS_RSP_QUERY_INFO);
  2450. Status = HeadlessDispatch(HeadlessCmdQueryInformation,
  2451. NULL,
  2452. 0,
  2453. &Response,
  2454. &Length
  2455. );
  2456. if (NT_SUCCESS(Status) &&
  2457. (Response.PortType == HeadlessSerialPort) &&
  2458. Response.Serial.TerminalAttached) {
  2459. if (Response.Serial.UsedBiosSettings) {
  2460. p = "redirect=UseBiosSettings\r\n";
  2461. } else {
  2462. switch (Response.Serial.TerminalPort) {
  2463. case ComPort1:
  2464. p = "redirect=com1\r\n";
  2465. break;
  2466. case ComPort2:
  2467. p = "redirect=com2\r\n";
  2468. break;
  2469. case ComPort3:
  2470. p = "redirect=com3\r\n";
  2471. break;
  2472. case ComPort4:
  2473. p = "redirect=com4\r\n";
  2474. break;
  2475. default:
  2476. ASSERT(0);
  2477. p = NULL;
  2478. break;
  2479. }
  2480. }
  2481. if (p != NULL) {
  2482. strcat(DefSwitches, p);
  2483. }
  2484. }
  2485. SpMemFree(BootIniBuf);
  2486. return( TRUE );
  2487. }
  2488. //
  2489. // NEC98
  2490. //
  2491. NTSTATUS
  2492. SppRestoreBootCode(
  2493. VOID
  2494. )
  2495. {
  2496. //
  2497. // Restore previous OS boot code to boot sector from bootsect.dos.
  2498. //
  2499. WCHAR p1[256] = {0};
  2500. PUCHAR BootSectBuf;
  2501. PUCHAR BootCodeBuf;
  2502. HANDLE FileHandle;
  2503. HANDLE SectionHandle;
  2504. PVOID ViewBase;
  2505. ULONG FileSize;
  2506. NTSTATUS Status;
  2507. PDISK_REGION SystemRegion;
  2508. //
  2509. // add some code to determine bytes per sector.
  2510. //
  2511. ULONG BytesPerSector;
  2512. // BytesPerSector = HardDisks[SystemPartitionRegion->DiskNumber].Geometry.BytesPerSector;
  2513. BytesPerSector = 512; //???
  2514. wcscpy(p1,NtBootDevicePath);
  2515. SpConcatenatePaths(p1,L"bootsect.dos");
  2516. FileHandle = 0;
  2517. Status = SpOpenAndMapFile(p1,&FileHandle,&SectionHandle,&ViewBase,&FileSize,FALSE);
  2518. if(!NT_SUCCESS(Status)) {
  2519. return(Status);
  2520. }
  2521. BootCodeBuf = SpMemAlloc(FileSize+1);
  2522. try {
  2523. RtlMoveMemory(BootCodeBuf,ViewBase,FileSize);
  2524. }
  2525. except( IN_PAGE_ERROR ) {
  2526. //
  2527. // Do nothing, boot ini processing can proceed with whatever has been
  2528. // read
  2529. //
  2530. }
  2531. Status = pSpBootCodeIo(
  2532. NtBootDevicePath,
  2533. NULL,
  2534. 2048,
  2535. &BootSectBuf,
  2536. FILE_OPEN,
  2537. FALSE,
  2538. 0,
  2539. BytesPerSector
  2540. );
  2541. if(!NT_SUCCESS(Status)) {
  2542. SpMemFree(BootCodeBuf);
  2543. SpUnmapFile(SectionHandle,ViewBase);
  2544. ZwClose(FileHandle);
  2545. return(Status);
  2546. }
  2547. //
  2548. // Keep dirty flag in FAT BPB, to avoid confusion in disk management.
  2549. //
  2550. SystemRegion = SpRegionFromNtName(NtBootDevicePath, PartitionOrdinalCurrent);
  2551. if(SystemRegion && (SystemRegion->Filesystem != FilesystemNtfs)) {
  2552. BootCodeBuf[0x25] = BootSectBuf[0x25]; // Dirty flag in BPB.
  2553. }
  2554. RtlMoveMemory(BootSectBuf,BootCodeBuf,512);
  2555. pSpBootCodeIo(
  2556. NtBootDevicePath,
  2557. NULL,
  2558. 2048,
  2559. &BootSectBuf,
  2560. FILE_OPEN,
  2561. TRUE,
  2562. 0,
  2563. BytesPerSector
  2564. );
  2565. SpMemFree(BootCodeBuf);
  2566. SpMemFree(BootSectBuf);
  2567. SpUnmapFile(SectionHandle,ViewBase);
  2568. ZwClose(FileHandle);
  2569. return(Status);
  2570. }