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.

1203 lines
35 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. bootient.c
  5. Abstract:
  6. Contains the Boot.ini OS boot entry and boot options
  7. abstraction implementation.
  8. Author:
  9. Revision History:
  10. None.
  11. --*/
  12. #include <bootient.h>
  13. //
  14. // defines
  15. //
  16. #define BOIOS_SECTION_NAME_START TEXT('[')
  17. #define BOIOS_SECTION_NAME_END TEXT(']')
  18. #define BOIOS_SECTION_NAME_START_STR TEXT("[")
  19. #define BOIOS_SECTION_NAME_END_STR TEXT("]")
  20. #define BOIOS_BOOTLOADER_SECTION TEXT("boot loader")
  21. #define BOIOS_OS_SECTION TEXT("operating systems")
  22. #define BOIOS_TIMEOUT_KEY TEXT("timeout=")
  23. #define BOIOS_DEFAULT_KEY TEXT("default=")
  24. #define MAX_BOOT_INI_SIZE (4 * 1024)
  25. static
  26. PTSTR
  27. BOIOSFixupString(
  28. IN PTSTR String,
  29. IN PTSTR SpecialChars
  30. )
  31. {
  32. PTSTR ResultStr = String;
  33. //
  34. // Verify arguments
  35. //
  36. if (ResultStr && SpecialChars) {
  37. ULONG Index;
  38. BOOLEAN DoneWithStart = FALSE;
  39. TCHAR Buffer[MAX_PATH * 4] = {0};
  40. TCHAR NextIndex = 0;
  41. //
  42. // skip unwanted characters
  43. //
  44. for (Index = 0; String[Index]; Index++) {
  45. if (!_tcschr(SpecialChars, String[Index])) {
  46. Buffer[NextIndex++] = String[Index];
  47. }
  48. }
  49. //
  50. // Null terminate the string
  51. //
  52. Buffer[NextIndex] = 0;
  53. if (!NextIndex) {
  54. ResultStr = NULL;
  55. } else {
  56. //
  57. // Copy back the new string to the
  58. // input / output buffer
  59. //
  60. _tcscpy(ResultStr, Buffer);
  61. }
  62. }
  63. return ResultStr;
  64. }
  65. //
  66. // BOI_OS_SECTION Methods
  67. //
  68. PBOI_SECTION
  69. BOISectionCreate(
  70. IN PCTSTR SectionData
  71. )
  72. {
  73. PBOI_SECTION This = NULL;
  74. if (SectionData) {
  75. PTSTR Buffer = (PTSTR)SBE_MALLOC((_tcslen(SectionData) + 1) * sizeof(TCHAR));
  76. if (Buffer && _tcscpy(Buffer, SectionData)) {
  77. PTSTR SectionNameStart = _tcschr(Buffer, BOIOS_SECTION_NAME_START);
  78. PTSTR SectionNameEnd = _tcschr(Buffer, BOIOS_SECTION_NAME_END);
  79. BOOLEAN Result = FALSE;
  80. if (SectionNameStart && SectionNameEnd && (SectionNameEnd > SectionNameStart)) {
  81. This = (PBOI_SECTION)SBE_MALLOC(sizeof(BOI_SECTION));
  82. if (*Buffer && This) {
  83. DWORD DataLength = (_tcslen(Buffer) + 1) * sizeof(TCHAR);
  84. DataLength -= (((SectionNameEnd + 1) - Buffer) * sizeof(TCHAR));
  85. //
  86. // Init default object state
  87. //
  88. memset(This, 0, sizeof(BOI_SECTION));
  89. //
  90. // Get the name
  91. //
  92. _tcsncpy(This->Name, SectionNameStart + 1,
  93. SectionNameEnd - SectionNameStart - 1);
  94. //
  95. // Replicate the contents and keep it
  96. //
  97. This->Contents = (PTSTR)SBE_MALLOC(DataLength);
  98. if (This->Contents) {
  99. _tcscpy(This->Contents, SectionNameEnd + 1);
  100. Result = TRUE;
  101. } else {
  102. Result = FALSE;
  103. }
  104. }
  105. if (!Result) {
  106. BOISectionDelete(This);
  107. This = NULL;
  108. }
  109. }
  110. SBE_FREE(Buffer);
  111. }
  112. }
  113. return This;
  114. }
  115. VOID
  116. BOISectionDelete(
  117. IN PBOI_SECTION This
  118. )
  119. {
  120. if (This) {
  121. if (This->Contents) {
  122. SBE_FREE(This->Contents);
  123. }
  124. SBE_FREE(This);
  125. }
  126. }
  127. static
  128. BOOLEAN
  129. BOISectionWrite(
  130. IN PBOI_SECTION This,
  131. IN OUT PTSTR Buffer
  132. )
  133. {
  134. BOOLEAN Result = FALSE;
  135. if (This && Buffer) {
  136. _tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
  137. _tcscat(Buffer, BOISectionGetName(This));
  138. _tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
  139. _tcscat(Buffer, TEXT("\r\n"));
  140. if (This->Contents) {
  141. _tcscat(Buffer, This->Contents);
  142. }
  143. }
  144. return Result;
  145. }
  146. //
  147. // BOI_OS_BOOT_ENTRY Methods
  148. //
  149. static
  150. VOID
  151. BOIOSBEInit(
  152. IN PBOI_OS_BOOT_ENTRY This
  153. )
  154. {
  155. This->OsBootEntry.Delete = BOIOSBEDelete;
  156. This->OsBootEntry.Flush = BOIOSBEFlush;
  157. }
  158. PBOI_SECTION
  159. BOIOSBOFindSection(
  160. IN PBOI_OS_BOOT_OPTIONS This,
  161. IN PTSTR SectionName
  162. )
  163. {
  164. PBOI_SECTION Entry = NULL;
  165. for (Entry = This->Sections; Entry; Entry = Entry->Next) {
  166. if (!_tcsicmp(Entry->Name, SectionName)) {
  167. break; // found the required section
  168. }
  169. }
  170. return Entry;
  171. }
  172. static
  173. POS_BOOT_ENTRY
  174. BOIOSBECreate(
  175. IN ULONG Id,
  176. IN PCTSTR BootEntryLine,
  177. IN PBOI_OS_BOOT_OPTIONS Container
  178. )
  179. {
  180. POS_BOOT_ENTRY Entry = NULL;
  181. if (BootEntryLine && Container) {
  182. BOOLEAN Result = FALSE;
  183. TCHAR Buffer[MAX_PATH * 4];
  184. TCHAR Token[MAX_PATH];
  185. PBOI_OS_BOOT_ENTRY BootEntry = (PBOI_OS_BOOT_ENTRY)SBE_MALLOC(sizeof(BOI_OS_BOOT_ENTRY));
  186. POS_BOOT_ENTRY BaseBootEntry = (POS_BOOT_ENTRY)BootEntry;
  187. //
  188. // Replicate the input string
  189. //
  190. _tcsncpy(Buffer, BootEntryLine, sizeof(Buffer)/sizeof(TCHAR));
  191. //
  192. // Remove unwanted charcters in the string
  193. //
  194. if (BootEntry && BOIOSFixupString(Buffer, TEXT("\n\r"))) {
  195. PTSTR EqualSign = _tcschr(Buffer, TEXT('='));
  196. //
  197. // Initialize object state
  198. //
  199. memset(BootEntry, 0, sizeof(BOI_OS_BOOT_ENTRY));
  200. BOIOSBEInit(BootEntry);
  201. BaseBootEntry->Id = Id;
  202. BaseBootEntry->BootOptions = (POS_BOOT_OPTIONS)Container;
  203. if (EqualSign) {
  204. PTSTR Slash;
  205. *EqualSign = 0;
  206. Slash = _tcschr(Buffer, TEXT('\\'));
  207. if (Slash) {
  208. PTSTR NameStart = NULL, NameEnd = NULL;
  209. PTSTR NextToken = NULL;
  210. Result = TRUE;
  211. *Slash = 0;
  212. //
  213. // Parse & set the boot device name
  214. //
  215. _tcscpy(Token, Buffer);
  216. BOIOSFixupString(Token, TEXT("\n\r "));
  217. _tcslwr(Token);
  218. OSBESetBootVolumeName(BaseBootEntry, Token);
  219. //
  220. // if it starts with "C:" its either old OS,
  221. // or CmdCons or WinPE or Setup entry
  222. //
  223. if (_tcschr(Token, TEXT(':'))) {
  224. OSBE_SET_OLDOS(BaseBootEntry);
  225. }
  226. //
  227. // Parse & set the boot path
  228. //
  229. _tcscpy(Token, Slash + 1);
  230. BOIOSFixupString(Token, TEXT("\n\r "));
  231. OSBESetBootPath(BaseBootEntry, Token);
  232. //
  233. // Parse & set the friendly name
  234. //
  235. NameStart = _tcschr(EqualSign + 1, TEXT('\"'));
  236. //
  237. // Set friendly name
  238. //
  239. if (NameStart) {
  240. NameEnd = _tcschr(NameStart + 1, TEXT('\"'));
  241. }
  242. if (NameEnd) {
  243. _tcsncpy(Token, NameStart, NameEnd - NameStart);
  244. Token[NameEnd - NameStart] = 0;
  245. BOIOSFixupString(Token, TEXT("\r\n\""));
  246. OSBESetFriendlyName(BaseBootEntry, Token);
  247. } else {
  248. Result = FALSE;
  249. }
  250. //
  251. // Set osload options
  252. //
  253. NextToken = _tcschr(EqualSign + 1, TEXT('/'));
  254. if (NextToken) {
  255. _tcscpy(Token, NextToken);
  256. BOIOSFixupString(Token, TEXT("\r\n"));
  257. OSBESetOsLoadOptions(BaseBootEntry, Token);
  258. }
  259. }
  260. }
  261. if (!Result) {
  262. SBE_FREE(BaseBootEntry);
  263. BaseBootEntry = NULL;
  264. } else {
  265. Entry = BaseBootEntry;
  266. }
  267. }
  268. }
  269. return Entry;
  270. }
  271. static
  272. VOID
  273. BOIOSBEDelete(
  274. IN POS_BOOT_ENTRY Obj
  275. )
  276. {
  277. PBOI_OS_BOOT_ENTRY This = (PBOI_OS_BOOT_ENTRY)Obj;
  278. if (This) {
  279. SBE_FREE(This);
  280. }
  281. }
  282. static
  283. BOOLEAN
  284. BOIOSBEWrite(
  285. IN POS_BOOT_ENTRY This,
  286. IN OUT PTSTR Buffer
  287. )
  288. {
  289. BOOLEAN Result = FALSE;
  290. if (This && Buffer && !OSBE_IS_DELETED(This)) {
  291. _tcscat(Buffer, OSBEGetBootVolumeName(This));
  292. _tcscat(Buffer, TEXT("\\"));
  293. _tcscat(Buffer, OSBEGetBootPath(This));
  294. _tcscat(Buffer, TEXT("="));
  295. _tcscat(Buffer, TEXT("\""));
  296. _tcscat(Buffer, OSBEGetFriendlyName(This));
  297. _tcscat(Buffer, TEXT("\""));
  298. _tcscat(Buffer, TEXT(" "));
  299. _tcscat(Buffer, OSBEGetOsLoadOptions(This));
  300. _tcscat(Buffer, TEXT("\r\n"));
  301. Result = TRUE;
  302. }
  303. return Result;
  304. }
  305. static
  306. BOOLEAN
  307. BOIOSBEFlush(
  308. IN POS_BOOT_ENTRY Obj
  309. )
  310. {
  311. return TRUE; // currently can't flush individual entries
  312. }
  313. //
  314. // BOI_OS_BOOT_OPTIONS Methods
  315. //
  316. static
  317. VOID
  318. BOIOSBOInit(
  319. IN PBOI_OS_BOOT_OPTIONS This
  320. )
  321. {
  322. This->OsBootOptions.Delete = BOIOSBODelete;
  323. This->OsBootOptions.Flush = BOIOSBOFlush;
  324. This->OsBootOptions.AddNewBootEntry = BOIOSBOAddNewBootEntry;
  325. This->OsBootOptions.DeleteBootEntry = OSBODeleteBootEntry;
  326. }
  327. BOOLEAN
  328. BOIOSBOParseAndCreateBootEntries(
  329. IN PBOI_OS_BOOT_OPTIONS This,
  330. IN PBOI_SECTION Section
  331. )
  332. {
  333. BOOLEAN Result = FALSE;
  334. if (This && Section) {
  335. Result = TRUE;
  336. if (Section->Contents) {
  337. PTSTR NextLineStart = Section->Contents;
  338. PTSTR NextLineEnd;
  339. TCHAR OldChar;
  340. POS_BOOT_ENTRY FirstBootEntry = NULL;
  341. POS_BOOT_ENTRY BootEntry = NULL;
  342. POS_BOOT_ENTRY LastBootEntry = NULL;
  343. ULONG BootEntryCount;
  344. while (NextLineStart) {
  345. NextLineEnd = _tcschr(NextLineStart, TEXT('\r'));
  346. if (NextLineEnd) {
  347. if (*(NextLineEnd + 1) == TEXT('\n')) {
  348. NextLineEnd++;
  349. }
  350. NextLineEnd++;
  351. OldChar = *NextLineEnd;
  352. *NextLineEnd = 0;
  353. }
  354. //
  355. // Each boot entry line needs to be more than 2 characters in
  356. // length and contain an entry of "a=b" form
  357. //
  358. if ((!NextLineEnd || ((NextLineEnd - NextLineStart) > 2)) &&
  359. (_tcschr(NextLineStart, TEXT('=')))) {
  360. BootEntry = BOIOSBECreate(This->NextEntryId++, NextLineStart, This);
  361. if (BootEntry) {
  362. This->OsBootOptions.EntryCount++;
  363. if (!FirstBootEntry) {
  364. FirstBootEntry = LastBootEntry = BootEntry;
  365. } else {
  366. LastBootEntry->NextEntry = BootEntry;
  367. LastBootEntry = BootEntry;
  368. }
  369. } else {
  370. Result = FALSE;
  371. break; // don't continue on
  372. }
  373. }
  374. if (NextLineEnd) {
  375. *NextLineEnd = OldChar;
  376. }
  377. NextLineStart = NextLineEnd;
  378. }
  379. This->OsBootOptions.BootEntries = FirstBootEntry;
  380. //
  381. // Initialize the boot order array
  382. // NOTE : Doesn't make much sense with boot.ini currently
  383. //
  384. BootEntryCount = OSBOGetBootEntryCount((POS_BOOT_OPTIONS)This);
  385. if (BootEntryCount) {
  386. PULONG BootOrder = (PULONG)SBE_MALLOC(BootEntryCount * sizeof(ULONG));
  387. if (BootOrder) {
  388. ULONG Index = 0;
  389. memset(BootOrder, 0, sizeof(ULONG) * BootEntryCount);
  390. BootEntry = OSBOGetFirstBootEntry((POS_BOOT_OPTIONS)This);
  391. while (BootEntry && (Index < BootEntryCount)) {
  392. BootOrder[Index] = OSBEGetId(BootEntry);
  393. BootEntry = OSBOGetNextBootEntry((POS_BOOT_OPTIONS)This, BootEntry);
  394. }
  395. This->OsBootOptions.BootOrder = BootOrder;
  396. This->OsBootOptions.BootOrderCount = BootEntryCount;
  397. }
  398. }
  399. }
  400. }
  401. return Result;
  402. }
  403. BOOLEAN
  404. BOIOSBOParseTimeoutAndActiveEntry(
  405. IN PBOI_OS_BOOT_OPTIONS This,
  406. IN PBOI_SECTION Section
  407. )
  408. {
  409. BOOLEAN Result = FALSE;
  410. if (This && Section && !_tcsicmp(Section->Name, BOIOS_BOOTLOADER_SECTION)) {
  411. TCHAR Buffer[MAX_PATH * 2];
  412. TCHAR Timeout[MAX_PATH];
  413. TCHAR Default[MAX_PATH];
  414. PTSTR DefKey, TimeoutKey;
  415. PTSTR DefValue;
  416. DWORD TimeKeyLength = _tcslen(BOIOS_TIMEOUT_KEY);
  417. DWORD DefKeyLength = _tcslen(BOIOS_DEFAULT_KEY);
  418. DWORD CopyLength;
  419. Result = TRUE;
  420. _tcscpy(Buffer, Section->Contents);
  421. _tcslwr(Buffer);
  422. BOIOSFixupString(Buffer, TEXT("\r\n "));
  423. Timeout[0] = Default[0] = 0;
  424. DefKey = _tcsstr(Buffer, BOIOS_DEFAULT_KEY);
  425. TimeoutKey = _tcsstr(Buffer, BOIOS_TIMEOUT_KEY);
  426. if (DefKey && TimeoutKey) {
  427. if (DefKey > TimeoutKey) {
  428. CopyLength = DefKey - TimeoutKey - TimeKeyLength;
  429. _tcsncpy(Timeout, TimeoutKey + TimeKeyLength, CopyLength);
  430. Timeout[CopyLength] = 0;
  431. _tcscpy(Default, DefKey + DefKeyLength);
  432. } else {
  433. CopyLength = TimeoutKey - DefKey - DefKeyLength;
  434. _tcsncpy(Default, DefKey + DefKeyLength, CopyLength);
  435. Default[CopyLength] = 0;
  436. _tcscpy(Timeout, TimeoutKey + TimeKeyLength);
  437. }
  438. } else if (DefKey) {
  439. _tcscpy(Default, DefKey + DefKeyLength);
  440. } else if (TimeoutKey) {
  441. _tcscpy(Timeout, TimeoutKey + TimeKeyLength);
  442. }
  443. if (TimeoutKey) {
  444. ULONG TimeoutValue = _ttol(Timeout);
  445. OSBOSetTimeOut((POS_BOOT_OPTIONS)This, TimeoutValue);
  446. }
  447. if (DefKey) {
  448. PTSTR BootPath = _tcschr(Default, TEXT('\\'));
  449. if (BootPath) {
  450. POS_BOOT_ENTRY CurrEntry;
  451. *BootPath = 0;
  452. CurrEntry = OSBOGetFirstBootEntry((POS_BOOT_OPTIONS)This);
  453. while (CurrEntry) {
  454. if (_tcsstr(Default, OSBEGetBootVolumeName(CurrEntry)) &&
  455. !_tcsicmp(OSBEGetBootPath(CurrEntry), BootPath + 1)) {
  456. break;
  457. }
  458. CurrEntry = OSBOGetNextBootEntry((POS_BOOT_OPTIONS)This, CurrEntry);
  459. }
  460. if (CurrEntry) {
  461. OSBOSetActiveBootEntry((POS_BOOT_OPTIONS)This, CurrEntry);
  462. }
  463. } else {
  464. Result = FALSE;
  465. }
  466. }
  467. OSBO_RESET_DIRTY((POS_BOOT_OPTIONS)This);
  468. }
  469. return Result;
  470. }
  471. POS_BOOT_OPTIONS
  472. BOIOSBOCreate(
  473. IN PCTSTR BootIniPath,
  474. IN BOOLEAN OpenExisting
  475. )
  476. {
  477. POS_BOOT_OPTIONS This = NULL;
  478. if (BootIniPath) {
  479. BY_HANDLE_FILE_INFORMATION FileInfo = {0};
  480. PCHAR FileContent = NULL;
  481. HANDLE BootIniHandle;
  482. //
  483. // Open the file
  484. //
  485. BootIniHandle = CreateFile(BootIniPath,
  486. GENERIC_READ,
  487. FILE_SHARE_READ,
  488. NULL,
  489. OPEN_EXISTING,
  490. FILE_ATTRIBUTE_NORMAL,
  491. NULL);
  492. if ((BootIniHandle != INVALID_HANDLE_VALUE) &&
  493. GetFileInformationByHandle(BootIniHandle,
  494. &FileInfo)){
  495. //
  496. // Map the file
  497. //
  498. HANDLE MapHandle = CreateFileMapping(BootIniHandle,
  499. NULL,
  500. PAGE_READONLY,
  501. FileInfo.nFileSizeHigh,
  502. FileInfo.nFileSizeLow,
  503. NULL);
  504. if (MapHandle) {
  505. //
  506. // Get hold of view for the file content
  507. //
  508. PVOID FileView = MapViewOfFile(MapHandle,
  509. FILE_MAP_READ,
  510. 0,
  511. 0,
  512. 0);
  513. if (FileView) {
  514. DWORD BytesRead = 0;
  515. //
  516. // Allocate the buffer and read the file contents
  517. //
  518. FileContent = SBE_MALLOC(FileInfo.nFileSizeLow + 1);
  519. if (FileContent) {
  520. if (!ReadFile(BootIniHandle,
  521. FileContent,
  522. FileInfo.nFileSizeLow,
  523. &BytesRead,
  524. NULL)) {
  525. SBE_FREE(FileContent);
  526. FileContent = NULL;
  527. } else {
  528. FileContent[FileInfo.nFileSizeLow] = 0;
  529. }
  530. }
  531. UnmapViewOfFile(FileView);
  532. }
  533. CloseHandle(MapHandle);
  534. }
  535. CloseHandle(BootIniHandle);
  536. } else {
  537. //
  538. // Could be that user is creating boot options fresh
  539. //
  540. if (!OpenExisting) {
  541. PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)SBE_MALLOC(sizeof(BOI_OS_BOOT_OPTIONS));
  542. if (Obj) {
  543. //
  544. // Initialize object
  545. //
  546. memset(Obj, 0, sizeof(BOI_OS_BOOT_OPTIONS));
  547. BOIOSBOInit(Obj);
  548. _tcscpy(Obj->BootIniPath, BootIniPath);
  549. }
  550. This = (POS_BOOT_OPTIONS)Obj;
  551. }
  552. }
  553. //
  554. // If there is any file content then parse it
  555. //
  556. if (FileContent) {
  557. #ifdef UNICODE
  558. PWSTR Content = SBE_MALLOC((FileInfo.nFileSizeLow + 1) * sizeof(WCHAR));
  559. //
  560. // Convert the Ansi/OEM content to unicode content
  561. //
  562. if (Content) {
  563. if (MultiByteToWideChar(CP_OEMCP,
  564. 0,
  565. FileContent,
  566. FileInfo.nFileSizeLow,
  567. Content,
  568. FileInfo.nFileSizeLow + 1)) {
  569. Content[FileInfo.nFileSizeLow ] = 0;
  570. } else {
  571. SBE_FREE(Content);
  572. Content = NULL;
  573. }
  574. } else {
  575. SBE_FREE(FileContent);
  576. FileContent = NULL;
  577. }
  578. #else
  579. PCHAR Content = FileContent;
  580. #endif
  581. if (Content && FileContent) {
  582. TCHAR NextLine[MAX_PATH * 4];
  583. PTSTR NextSectionStart = _tcschr(Content, BOIOS_SECTION_NAME_START);
  584. PTSTR NextSectionEnd;
  585. PBOI_SECTION SectionList = NULL;
  586. PBOI_SECTION Section = NULL;
  587. PBOI_SECTION TailSection = NULL;
  588. BOOLEAN Result = TRUE;
  589. //
  590. // Prase the whole files and create section objects
  591. //
  592. while (NextSectionStart) {
  593. TCHAR OldChar;
  594. Section = NULL;
  595. NextSectionEnd = _tcschr(NextSectionStart + 1, BOIOS_SECTION_NAME_START);
  596. if (NextSectionEnd) {
  597. OldChar = *NextSectionEnd;
  598. *NextSectionEnd = 0; // null terminate
  599. }
  600. //
  601. // Create the section object
  602. //
  603. Section = BOISectionCreate(NextSectionStart);
  604. if (NextSectionEnd) {
  605. *NextSectionEnd = OldChar;
  606. }
  607. if (Section) {
  608. if (!SectionList) {
  609. SectionList = Section;
  610. } else {
  611. TailSection->Next = Section;
  612. }
  613. TailSection = Section;
  614. } else {
  615. Result = FALSE;
  616. break;
  617. }
  618. NextSectionStart = NextSectionEnd;
  619. }
  620. if (Result) {
  621. PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)SBE_MALLOC(sizeof(BOI_OS_BOOT_OPTIONS));
  622. if (Obj) {
  623. //
  624. // Initialize object
  625. //
  626. memset(Obj, 0, sizeof(BOI_OS_BOOT_OPTIONS));
  627. BOIOSBOInit(Obj);
  628. _tcscpy(Obj->BootIniPath, BootIniPath);
  629. Obj->Sections = SectionList;
  630. SectionList = NULL;
  631. //
  632. // Get hold of [operating systems] section and
  633. // parse its entries and create boot entries
  634. //
  635. Section = BOIOSBOFindSection(Obj, BOIOS_OS_SECTION);
  636. if (Section) {
  637. Result = BOIOSBOParseAndCreateBootEntries(Obj, Section);
  638. }
  639. //
  640. // Get hold of [boot loader] section and prase its
  641. // entries
  642. //
  643. if (Result) {
  644. Section = BOIOSBOFindSection(Obj, BOIOS_BOOTLOADER_SECTION);
  645. if (Section) {
  646. Result = BOIOSBOParseTimeoutAndActiveEntry(Obj, Section);
  647. }
  648. }
  649. if (!Result) {
  650. //
  651. // Delete the object to free up all the sections
  652. // and the entries
  653. //
  654. BOIOSBODelete((POS_BOOT_OPTIONS)Obj);
  655. Obj = NULL;
  656. }
  657. This = (POS_BOOT_OPTIONS)Obj;
  658. } else {
  659. Result = FALSE;
  660. }
  661. }
  662. //
  663. // free up the allocated sections, in case of failure
  664. //
  665. if (!Result && SectionList) {
  666. while (SectionList) {
  667. Section = SectionList;
  668. SectionList = SectionList->Next;
  669. BOISectionDelete(Section);
  670. }
  671. }
  672. //
  673. // Free the content
  674. //
  675. if ((PVOID)Content != (PVOID)FileContent) {
  676. SBE_FREE(Content);
  677. }
  678. }
  679. SBE_FREE(FileContent);
  680. }
  681. }
  682. return This;
  683. }
  684. static
  685. VOID
  686. BOIOSBODelete(
  687. IN POS_BOOT_OPTIONS Obj
  688. )
  689. {
  690. PBOI_OS_BOOT_OPTIONS This = (PBOI_OS_BOOT_OPTIONS)Obj;
  691. if (This) {
  692. PBOI_SECTION CurrSection, PrevSection;
  693. //
  694. // delete each boot entry
  695. //
  696. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj);
  697. POS_BOOT_ENTRY PrevEntry;
  698. while (Entry) {
  699. PrevEntry = Entry;
  700. Entry = OSBOGetNextBootEntry(Obj, Entry);
  701. OSBEDelete(PrevEntry);
  702. }
  703. //
  704. // delete all the sections
  705. //
  706. CurrSection = This->Sections;
  707. while (CurrSection) {
  708. PrevSection = CurrSection;
  709. CurrSection = CurrSection->Next;
  710. BOISectionDelete(PrevSection);
  711. }
  712. if (Obj->BootOrder) {
  713. SBE_FREE(Obj->BootOrder);
  714. }
  715. //
  716. // delete the main object
  717. //
  718. SBE_FREE(This);
  719. }
  720. }
  721. static
  722. POS_BOOT_ENTRY
  723. BOIOSBOAddNewBootEntry(
  724. IN POS_BOOT_OPTIONS This,
  725. IN PCTSTR FriendlyName,
  726. IN PCTSTR OsLoaderVolumeName,
  727. IN PCTSTR OsLoaderPath,
  728. IN PCTSTR BootVolumeName,
  729. IN PCTSTR BootPath,
  730. IN PCTSTR OsLoadOptions
  731. )
  732. {
  733. PBOI_OS_BOOT_ENTRY Entry = NULL;
  734. if (This && FriendlyName && BootVolumeName && BootPath) {
  735. Entry = SBE_MALLOC(sizeof(BOI_OS_BOOT_ENTRY));
  736. if (Entry) {
  737. ULONG OrderCount;
  738. PULONG NewOrder;
  739. POS_BOOT_ENTRY BaseEntry = (POS_BOOT_ENTRY)Entry;
  740. PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)This;
  741. //
  742. // init core fields
  743. //
  744. memset(Entry, 0, sizeof(BOI_OS_BOOT_ENTRY));
  745. BOIOSBEInit(Entry);
  746. Entry->OsBootEntry.BootOptions = This;
  747. //
  748. // fill in the attributes
  749. //
  750. OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, FriendlyName);
  751. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry, BootVolumeName);
  752. OSBESetBootPath((POS_BOOT_ENTRY)Entry, BootPath);
  753. if (OsLoadOptions) {
  754. OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry, OsLoadOptions);
  755. }
  756. BaseEntry->Id = Obj->NextEntryId++;
  757. //
  758. // Flush the entry now to get a proper Id;
  759. //
  760. Entry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
  761. Entry->OsBootEntry.NextEntry = This->BootEntries;
  762. This->BootEntries = (POS_BOOT_ENTRY)Entry;
  763. This->EntryCount++;
  764. //
  765. // Put the new entry at the end of the boot order
  766. //
  767. OrderCount = OSBOGetOrderedBootEntryCount(This);
  768. NewOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
  769. if (NewOrder) {
  770. memset(NewOrder, 0, sizeof(ULONG) * (OrderCount + 1));
  771. //
  772. // copy over the old ordered list
  773. //
  774. memcpy(NewOrder, This->BootOrder, sizeof(ULONG) * OrderCount);
  775. NewOrder[OrderCount] = OSBEGetId((POS_BOOT_ENTRY)Entry);
  776. SBE_FREE(This->BootOrder);
  777. This->BootOrder = NewOrder;
  778. This->BootOrderCount = OrderCount + 1;
  779. } else {
  780. OSBODeleteBootEntry(This, BaseEntry);
  781. Entry = NULL;
  782. }
  783. if (Entry) {
  784. //
  785. // mark it dirty and new for flushing
  786. //
  787. OSBE_SET_NEW(Entry);
  788. OSBE_SET_DIRTY(Entry);
  789. }
  790. }
  791. }
  792. return (POS_BOOT_ENTRY)Entry;
  793. }
  794. static
  795. BOOLEAN
  796. BOIOSBOWrite(
  797. IN PBOI_OS_BOOT_OPTIONS This,
  798. IN PCTSTR Buffer
  799. )
  800. {
  801. BOOLEAN Result = FALSE;
  802. if (This && Buffer) {
  803. TCHAR BackupFileName[MAX_PATH];
  804. PTSTR Extension;
  805. HANDLE FileHandle;
  806. //
  807. // Create a backup name
  808. //
  809. _tcscpy(BackupFileName, This->BootIniPath);
  810. Extension = _tcschr(BackupFileName, TEXT('.'));
  811. if (Extension) {
  812. _tcscpy(Extension, TEXT(".BAK"));
  813. } else {
  814. _tcscat(BackupFileName, TEXT(".BAK"));
  815. }
  816. //
  817. // Delete the backup file if it exists
  818. //
  819. SetFileAttributes(BackupFileName, FILE_ATTRIBUTE_NORMAL);
  820. DeleteFile(BackupFileName);
  821. //
  822. // Copy the existing boot.ini as backup file
  823. //
  824. SetFileAttributes(This->BootIniPath, FILE_ATTRIBUTE_NORMAL);
  825. CopyFile(This->BootIniPath, BackupFileName, FALSE);
  826. //
  827. // Create new boot.ini file
  828. //
  829. FileHandle = CreateFile(This->BootIniPath,
  830. GENERIC_READ | GENERIC_WRITE,
  831. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  832. NULL,
  833. CREATE_ALWAYS,
  834. FILE_ATTRIBUTE_NORMAL,
  835. NULL);
  836. if (FileHandle && (FileHandle != INVALID_HANDLE_VALUE)) {
  837. PCHAR AnsiBuffer;
  838. ULONG BufferLength = _tcslen(Buffer);
  839. DWORD BytesWritten = 0;
  840. Result = TRUE;
  841. #ifdef UNICODE
  842. //
  843. // Convert the unicode buffer to ansi buffer
  844. //
  845. AnsiBuffer = (PCHAR)SBE_MALLOC(BufferLength + 1);
  846. if (AnsiBuffer) {
  847. memset(AnsiBuffer, 0, BufferLength);
  848. if (WideCharToMultiByte(CP_OEMCP,
  849. 0,
  850. Buffer,
  851. BufferLength,
  852. AnsiBuffer,
  853. BufferLength,
  854. NULL,
  855. NULL)) {
  856. Result = TRUE;
  857. AnsiBuffer[BufferLength] = 0;
  858. } else {
  859. Result = FALSE;
  860. }
  861. }
  862. #else
  863. AnsiBuffer = Buffer;
  864. #endif
  865. //
  866. // Write the buffer to the file
  867. //
  868. if (AnsiBuffer &&
  869. !WriteFile(FileHandle,
  870. AnsiBuffer,
  871. BufferLength,
  872. &BytesWritten,
  873. NULL)) {
  874. Result = FALSE;
  875. }
  876. if ((PVOID)AnsiBuffer != (PVOID)Buffer) {
  877. SBE_FREE(AnsiBuffer);
  878. AnsiBuffer = NULL;
  879. }
  880. //
  881. // Done with the file handle
  882. //
  883. CloseHandle(FileHandle);
  884. SetFileAttributes(This->BootIniPath,
  885. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY |
  886. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  887. }
  888. }
  889. return Result;
  890. }
  891. static
  892. BOOLEAN
  893. BOIOSBOFlush(
  894. IN POS_BOOT_OPTIONS Obj
  895. )
  896. {
  897. BOOLEAN Result = FALSE;
  898. PBOI_OS_BOOT_OPTIONS This = (PBOI_OS_BOOT_OPTIONS)Obj;
  899. if (This) {
  900. PTSTR Buffer = (PTSTR)SBE_MALLOC(MAX_BOOT_INI_SIZE * sizeof(TCHAR));
  901. if (Buffer) {
  902. TCHAR ScratchBuffer[MAX_PATH * 2] = {0};
  903. POS_BOOT_ENTRY ActiveEntry = OSBOGetActiveBootEntry(Obj);
  904. POS_BOOT_ENTRY CurrentEntry;
  905. PBOI_SECTION CurrentSection;
  906. Result = TRUE;
  907. memset(Buffer, 0, MAX_BOOT_INI_SIZE * sizeof(TCHAR));
  908. //
  909. // first flush the boot options
  910. //
  911. _tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
  912. _tcscat(Buffer, BOIOS_BOOTLOADER_SECTION);
  913. _tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
  914. _tcscat(Buffer, TEXT("\r\n"));
  915. //
  916. // write time out
  917. //
  918. _tcscat(Buffer, BOIOS_TIMEOUT_KEY);
  919. _tcscat(Buffer, _ltot(Obj->Timeout, ScratchBuffer, 10));
  920. _tcscat(Buffer, TEXT("\r\n"));
  921. //
  922. // write active entry
  923. //
  924. if (ActiveEntry) {
  925. _tcscpy(ScratchBuffer, BOIOS_DEFAULT_KEY);
  926. _tcscat(ScratchBuffer, OSBEGetBootVolumeName(ActiveEntry));
  927. _tcscat(ScratchBuffer, TEXT("\\"));
  928. _tcscat(ScratchBuffer, OSBEGetBootPath(ActiveEntry));
  929. _tcscat(ScratchBuffer, TEXT("\r\n"));
  930. _tcscat(Buffer, ScratchBuffer);
  931. }
  932. //
  933. // Write the boot entries section
  934. //
  935. _tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
  936. _tcscat(Buffer, BOIOS_OS_SECTION);
  937. _tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
  938. _tcscat(Buffer, TEXT("\r\n"));
  939. //
  940. // write each boot entry now
  941. //
  942. //
  943. // First write the valid arc entries
  944. //
  945. CurrentEntry = OSBOGetFirstBootEntry(Obj);
  946. while (Result && CurrentEntry) {
  947. if (!OSBE_IS_DELETED(CurrentEntry) &&
  948. !OSBE_IS_OLDOS(CurrentEntry)) {
  949. Result = BOIOSBEWrite(CurrentEntry, Buffer);
  950. }
  951. CurrentEntry = OSBOGetNextBootEntry(Obj, CurrentEntry);
  952. }
  953. //
  954. // Now write the old OS entries
  955. // NOTE : We do this for backward compatabily reasons
  956. //
  957. CurrentEntry = OSBOGetFirstBootEntry(Obj);
  958. while (Result && CurrentEntry) {
  959. if (OSBE_IS_OLDOS(CurrentEntry)) {
  960. Result = BOIOSBEWrite(CurrentEntry, Buffer);
  961. }
  962. CurrentEntry = OSBOGetNextBootEntry(Obj, CurrentEntry);
  963. }
  964. //
  965. // Write any additions sections which were present on the
  966. //
  967. CurrentSection = BOIOSGetFirstSection(This);
  968. while (Result && CurrentSection) {
  969. //
  970. // Write all the other additional sections in boot.ini other
  971. // than [boot loader] and [operating systems]
  972. //
  973. if (_tcsicmp(BOISectionGetName(CurrentSection), BOIOS_BOOTLOADER_SECTION) &&
  974. _tcsicmp(BOISectionGetName(CurrentSection), BOIOS_OS_SECTION)) {
  975. Result = BOISectionWrite(CurrentSection, Buffer);
  976. }
  977. CurrentSection = BOIOSGetNextSection(This, CurrentSection);
  978. }
  979. Result = BOIOSBOWrite(This, Buffer);
  980. //
  981. // Free the allocated buffer
  982. //
  983. SBE_FREE(Buffer);
  984. }
  985. }
  986. return Result;
  987. }