Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1222 lines
37 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. This->OsBootOptions.AddNewDriverEntry = BOIOSBOAddNewDriverEntry;
  327. This->OsBootOptions.DeleteDriverEntry = OSBODeleteDriverEntry;
  328. }
  329. BOOLEAN
  330. BOIOSBOParseAndCreateBootEntries(
  331. IN PBOI_OS_BOOT_OPTIONS This,
  332. IN PBOI_SECTION Section
  333. )
  334. {
  335. BOOLEAN Result = FALSE;
  336. if (This && Section) {
  337. Result = TRUE;
  338. if (Section->Contents) {
  339. PTSTR NextLineStart = Section->Contents;
  340. PTSTR NextLineEnd;
  341. TCHAR OldChar;
  342. POS_BOOT_ENTRY FirstBootEntry = NULL;
  343. POS_BOOT_ENTRY BootEntry = NULL;
  344. POS_BOOT_ENTRY LastBootEntry = NULL;
  345. ULONG BootEntryCount;
  346. while (NextLineStart) {
  347. NextLineEnd = _tcschr(NextLineStart, TEXT('\r'));
  348. if (NextLineEnd) {
  349. if (*(NextLineEnd + 1) == TEXT('\n')) {
  350. NextLineEnd++;
  351. }
  352. NextLineEnd++;
  353. OldChar = *NextLineEnd;
  354. *NextLineEnd = 0;
  355. }
  356. //
  357. // Each boot entry line needs to be more than 2 characters in
  358. // length and contain an entry of "a=b" form
  359. //
  360. if ((!NextLineEnd || ((NextLineEnd - NextLineStart) > 2)) &&
  361. (_tcschr(NextLineStart, TEXT('=')))) {
  362. BootEntry = BOIOSBECreate(This->NextEntryId++, NextLineStart, This);
  363. if (BootEntry) {
  364. This->OsBootOptions.EntryCount++;
  365. if (!FirstBootEntry) {
  366. FirstBootEntry = LastBootEntry = BootEntry;
  367. } else {
  368. LastBootEntry->NextEntry = BootEntry;
  369. LastBootEntry = BootEntry;
  370. }
  371. } else {
  372. Result = FALSE;
  373. break; // don't continue on
  374. }
  375. }
  376. if (NextLineEnd) {
  377. *NextLineEnd = OldChar;
  378. }
  379. NextLineStart = NextLineEnd;
  380. }
  381. This->OsBootOptions.BootEntries = FirstBootEntry;
  382. //
  383. // Initialize the boot order array
  384. // NOTE : Doesn't make much sense with boot.ini currently
  385. //
  386. BootEntryCount = OSBOGetBootEntryCount((POS_BOOT_OPTIONS)This);
  387. if (BootEntryCount) {
  388. PULONG BootOrder = (PULONG)SBE_MALLOC(BootEntryCount * sizeof(ULONG));
  389. if (BootOrder) {
  390. ULONG Index = 0;
  391. memset(BootOrder, 0, sizeof(ULONG) * BootEntryCount);
  392. BootEntry = OSBOGetFirstBootEntry((POS_BOOT_OPTIONS)This);
  393. while (BootEntry && (Index < BootEntryCount)) {
  394. BootOrder[Index] = OSBEGetId(BootEntry);
  395. BootEntry = OSBOGetNextBootEntry((POS_BOOT_OPTIONS)This, BootEntry);
  396. }
  397. This->OsBootOptions.BootOrder = BootOrder;
  398. This->OsBootOptions.BootOrderCount = BootEntryCount;
  399. }
  400. }
  401. }
  402. }
  403. return Result;
  404. }
  405. BOOLEAN
  406. BOIOSBOParseTimeoutAndActiveEntry(
  407. IN PBOI_OS_BOOT_OPTIONS This,
  408. IN PBOI_SECTION Section
  409. )
  410. {
  411. BOOLEAN Result = FALSE;
  412. if (This && Section && !_tcsicmp(Section->Name, BOIOS_BOOTLOADER_SECTION)) {
  413. TCHAR Buffer[MAX_PATH * 2];
  414. TCHAR Timeout[MAX_PATH];
  415. TCHAR Default[MAX_PATH];
  416. PTSTR DefKey, TimeoutKey;
  417. PTSTR DefValue;
  418. DWORD TimeKeyLength = _tcslen(BOIOS_TIMEOUT_KEY);
  419. DWORD DefKeyLength = _tcslen(BOIOS_DEFAULT_KEY);
  420. DWORD CopyLength;
  421. Result = TRUE;
  422. _tcscpy(Buffer, Section->Contents);
  423. _tcslwr(Buffer);
  424. BOIOSFixupString(Buffer, TEXT("\r\n "));
  425. Timeout[0] = Default[0] = 0;
  426. DefKey = _tcsstr(Buffer, BOIOS_DEFAULT_KEY);
  427. TimeoutKey = _tcsstr(Buffer, BOIOS_TIMEOUT_KEY);
  428. if (DefKey && TimeoutKey) {
  429. if (DefKey > TimeoutKey) {
  430. CopyLength = DefKey - TimeoutKey - TimeKeyLength;
  431. _tcsncpy(Timeout, TimeoutKey + TimeKeyLength, CopyLength);
  432. Timeout[CopyLength] = 0;
  433. _tcscpy(Default, DefKey + DefKeyLength);
  434. } else {
  435. CopyLength = TimeoutKey - DefKey - DefKeyLength;
  436. _tcsncpy(Default, DefKey + DefKeyLength, CopyLength);
  437. Default[CopyLength] = 0;
  438. _tcscpy(Timeout, TimeoutKey + TimeKeyLength);
  439. }
  440. } else if (DefKey) {
  441. _tcscpy(Default, DefKey + DefKeyLength);
  442. } else if (TimeoutKey) {
  443. _tcscpy(Timeout, TimeoutKey + TimeKeyLength);
  444. }
  445. if (TimeoutKey) {
  446. ULONG TimeoutValue = _ttol(Timeout);
  447. OSBOSetTimeOut((POS_BOOT_OPTIONS)This, TimeoutValue);
  448. }
  449. if (DefKey) {
  450. PTSTR BootPath = _tcschr(Default, TEXT('\\'));
  451. if (BootPath) {
  452. POS_BOOT_ENTRY CurrEntry;
  453. *BootPath = 0;
  454. CurrEntry = OSBOGetFirstBootEntry((POS_BOOT_OPTIONS)This);
  455. while (CurrEntry) {
  456. if (_tcsstr(Default, OSBEGetBootVolumeName(CurrEntry)) &&
  457. !_tcsicmp(OSBEGetBootPath(CurrEntry), BootPath + 1)) {
  458. break;
  459. }
  460. CurrEntry = OSBOGetNextBootEntry((POS_BOOT_OPTIONS)This, CurrEntry);
  461. }
  462. if (CurrEntry) {
  463. OSBOSetActiveBootEntry((POS_BOOT_OPTIONS)This, CurrEntry);
  464. }
  465. } else {
  466. Result = FALSE;
  467. }
  468. }
  469. OSBO_RESET_DIRTY((POS_BOOT_OPTIONS)This);
  470. }
  471. return Result;
  472. }
  473. POS_BOOT_OPTIONS
  474. BOIOSBOCreate(
  475. IN PCTSTR BootIniPath,
  476. IN BOOLEAN OpenExisting
  477. )
  478. {
  479. POS_BOOT_OPTIONS This = NULL;
  480. if (BootIniPath) {
  481. BY_HANDLE_FILE_INFORMATION FileInfo = {0};
  482. PCHAR FileContent = NULL;
  483. HANDLE BootIniHandle;
  484. //
  485. // Open the file
  486. //
  487. BootIniHandle = CreateFile(BootIniPath,
  488. GENERIC_READ,
  489. FILE_SHARE_READ,
  490. NULL,
  491. OPEN_EXISTING,
  492. FILE_ATTRIBUTE_NORMAL,
  493. NULL);
  494. if ((BootIniHandle != INVALID_HANDLE_VALUE) &&
  495. GetFileInformationByHandle(BootIniHandle,
  496. &FileInfo)){
  497. //
  498. // Map the file
  499. //
  500. HANDLE MapHandle = CreateFileMapping(BootIniHandle,
  501. NULL,
  502. PAGE_READONLY,
  503. FileInfo.nFileSizeHigh,
  504. FileInfo.nFileSizeLow,
  505. NULL);
  506. if (MapHandle) {
  507. //
  508. // Get hold of view for the file content
  509. //
  510. PVOID FileView = MapViewOfFile(MapHandle,
  511. FILE_MAP_READ,
  512. 0,
  513. 0,
  514. 0);
  515. if (FileView) {
  516. DWORD BytesRead = 0;
  517. //
  518. // Allocate the buffer and read the file contents
  519. //
  520. FileContent = SBE_MALLOC(FileInfo.nFileSizeLow + 1);
  521. if (FileContent) {
  522. if (!ReadFile(BootIniHandle,
  523. FileContent,
  524. FileInfo.nFileSizeLow,
  525. &BytesRead,
  526. NULL)) {
  527. SBE_FREE(FileContent);
  528. FileContent = NULL;
  529. } else {
  530. FileContent[FileInfo.nFileSizeLow] = 0;
  531. }
  532. }
  533. UnmapViewOfFile(FileView);
  534. }
  535. CloseHandle(MapHandle);
  536. }
  537. CloseHandle(BootIniHandle);
  538. } else {
  539. //
  540. // Could be that user is creating boot options fresh
  541. //
  542. if (!OpenExisting) {
  543. PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)SBE_MALLOC(sizeof(BOI_OS_BOOT_OPTIONS));
  544. if (Obj) {
  545. //
  546. // Initialize object
  547. //
  548. memset(Obj, 0, sizeof(BOI_OS_BOOT_OPTIONS));
  549. BOIOSBOInit(Obj);
  550. _tcscpy(Obj->BootIniPath, BootIniPath);
  551. }
  552. This = (POS_BOOT_OPTIONS)Obj;
  553. }
  554. }
  555. //
  556. // If there is any file content then parse it
  557. //
  558. if (FileContent) {
  559. #ifdef UNICODE
  560. PWSTR Content = SBE_MALLOC((FileInfo.nFileSizeLow + 1) * sizeof(WCHAR));
  561. //
  562. // Convert the Ansi/OEM content to unicode content
  563. //
  564. if (Content) {
  565. if (MultiByteToWideChar(CP_OEMCP,
  566. 0,
  567. FileContent,
  568. FileInfo.nFileSizeLow,
  569. Content,
  570. FileInfo.nFileSizeLow + 1)) {
  571. Content[FileInfo.nFileSizeLow ] = 0;
  572. } else {
  573. SBE_FREE(Content);
  574. Content = NULL;
  575. }
  576. } else {
  577. SBE_FREE(FileContent);
  578. FileContent = NULL;
  579. }
  580. #else
  581. PCHAR Content = FileContent;
  582. #endif
  583. if (Content && FileContent) {
  584. TCHAR NextLine[MAX_PATH * 4];
  585. PTSTR NextSectionStart = _tcschr(Content, BOIOS_SECTION_NAME_START);
  586. PTSTR NextSectionEnd;
  587. PBOI_SECTION SectionList = NULL;
  588. PBOI_SECTION Section = NULL;
  589. PBOI_SECTION TailSection = NULL;
  590. BOOLEAN Result = TRUE;
  591. //
  592. // Prase the whole files and create section objects
  593. //
  594. while (NextSectionStart) {
  595. TCHAR OldChar;
  596. Section = NULL;
  597. NextSectionEnd = _tcschr(NextSectionStart + 1, BOIOS_SECTION_NAME_START);
  598. if (NextSectionEnd) {
  599. OldChar = *NextSectionEnd;
  600. *NextSectionEnd = 0; // null terminate
  601. }
  602. //
  603. // Create the section object
  604. //
  605. Section = BOISectionCreate(NextSectionStart);
  606. if (NextSectionEnd) {
  607. *NextSectionEnd = OldChar;
  608. }
  609. if (Section) {
  610. if (!SectionList) {
  611. SectionList = Section;
  612. } else {
  613. TailSection->Next = Section;
  614. }
  615. TailSection = Section;
  616. } else {
  617. Result = FALSE;
  618. break;
  619. }
  620. NextSectionStart = NextSectionEnd;
  621. }
  622. if (Result) {
  623. PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)SBE_MALLOC(sizeof(BOI_OS_BOOT_OPTIONS));
  624. if (Obj) {
  625. //
  626. // Initialize object
  627. //
  628. memset(Obj, 0, sizeof(BOI_OS_BOOT_OPTIONS));
  629. BOIOSBOInit(Obj);
  630. _tcscpy(Obj->BootIniPath, BootIniPath);
  631. Obj->Sections = SectionList;
  632. SectionList = NULL;
  633. //
  634. // Get hold of [operating systems] section and
  635. // parse its entries and create boot entries
  636. //
  637. Section = BOIOSBOFindSection(Obj, BOIOS_OS_SECTION);
  638. if (Section) {
  639. Result = BOIOSBOParseAndCreateBootEntries(Obj, Section);
  640. }
  641. //
  642. // Get hold of [boot loader] section and prase its
  643. // entries
  644. //
  645. if (Result) {
  646. Section = BOIOSBOFindSection(Obj, BOIOS_BOOTLOADER_SECTION);
  647. if (Section) {
  648. Result = BOIOSBOParseTimeoutAndActiveEntry(Obj, Section);
  649. }
  650. }
  651. if (!Result) {
  652. //
  653. // Delete the object to free up all the sections
  654. // and the entries
  655. //
  656. BOIOSBODelete((POS_BOOT_OPTIONS)Obj);
  657. Obj = NULL;
  658. }
  659. This = (POS_BOOT_OPTIONS)Obj;
  660. } else {
  661. Result = FALSE;
  662. }
  663. }
  664. //
  665. // free up the allocated sections, in case of failure
  666. //
  667. if (!Result && SectionList) {
  668. while (SectionList) {
  669. Section = SectionList;
  670. SectionList = SectionList->Next;
  671. BOISectionDelete(Section);
  672. }
  673. }
  674. //
  675. // Free the content
  676. //
  677. if ((PVOID)Content != (PVOID)FileContent) {
  678. SBE_FREE(Content);
  679. }
  680. }
  681. SBE_FREE(FileContent);
  682. }
  683. }
  684. return This;
  685. }
  686. static
  687. VOID
  688. BOIOSBODelete(
  689. IN POS_BOOT_OPTIONS Obj
  690. )
  691. {
  692. PBOI_OS_BOOT_OPTIONS This = (PBOI_OS_BOOT_OPTIONS)Obj;
  693. if (This) {
  694. PBOI_SECTION CurrSection, PrevSection;
  695. //
  696. // delete each boot entry
  697. //
  698. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj);
  699. POS_BOOT_ENTRY PrevEntry;
  700. while (Entry) {
  701. PrevEntry = Entry;
  702. Entry = OSBOGetNextBootEntry(Obj, Entry);
  703. OSBEDelete(PrevEntry);
  704. }
  705. //
  706. // delete all the sections
  707. //
  708. CurrSection = This->Sections;
  709. while (CurrSection) {
  710. PrevSection = CurrSection;
  711. CurrSection = CurrSection->Next;
  712. BOISectionDelete(PrevSection);
  713. }
  714. if (Obj->BootOrder) {
  715. SBE_FREE(Obj->BootOrder);
  716. }
  717. //
  718. // delete the main object
  719. //
  720. SBE_FREE(This);
  721. }
  722. }
  723. static
  724. POS_BOOT_ENTRY
  725. BOIOSBOAddNewBootEntry(
  726. IN POS_BOOT_OPTIONS This,
  727. IN PCTSTR FriendlyName,
  728. IN PCTSTR OsLoaderVolumeName,
  729. IN PCTSTR OsLoaderPath,
  730. IN PCTSTR BootVolumeName,
  731. IN PCTSTR BootPath,
  732. IN PCTSTR OsLoadOptions
  733. )
  734. {
  735. PBOI_OS_BOOT_ENTRY Entry = NULL;
  736. if (This && FriendlyName && BootVolumeName && BootPath) {
  737. Entry = SBE_MALLOC(sizeof(BOI_OS_BOOT_ENTRY));
  738. if (Entry) {
  739. ULONG OrderCount;
  740. PULONG NewOrder;
  741. POS_BOOT_ENTRY BaseEntry = (POS_BOOT_ENTRY)Entry;
  742. PBOI_OS_BOOT_OPTIONS Obj = (PBOI_OS_BOOT_OPTIONS)This;
  743. //
  744. // init core fields
  745. //
  746. memset(Entry, 0, sizeof(BOI_OS_BOOT_ENTRY));
  747. BOIOSBEInit(Entry);
  748. Entry->OsBootEntry.BootOptions = This;
  749. //
  750. // fill in the attributes
  751. //
  752. OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, FriendlyName);
  753. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry, BootVolumeName);
  754. OSBESetBootPath((POS_BOOT_ENTRY)Entry, BootPath);
  755. if (OsLoadOptions) {
  756. OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry, OsLoadOptions);
  757. }
  758. BaseEntry->Id = Obj->NextEntryId++;
  759. //
  760. // Flush the entry now to get a proper Id;
  761. //
  762. Entry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
  763. Entry->OsBootEntry.NextEntry = This->BootEntries;
  764. This->BootEntries = (POS_BOOT_ENTRY)Entry;
  765. This->EntryCount++;
  766. //
  767. // Put the new entry at the end of the boot order
  768. //
  769. OrderCount = OSBOGetOrderedBootEntryCount(This);
  770. NewOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
  771. if (NewOrder) {
  772. memset(NewOrder, 0, sizeof(ULONG) * (OrderCount + 1));
  773. //
  774. // copy over the old ordered list
  775. //
  776. memcpy(NewOrder, This->BootOrder, sizeof(ULONG) * OrderCount);
  777. NewOrder[OrderCount] = OSBEGetId((POS_BOOT_ENTRY)Entry);
  778. SBE_FREE(This->BootOrder);
  779. This->BootOrder = NewOrder;
  780. This->BootOrderCount = OrderCount + 1;
  781. } else {
  782. OSBODeleteBootEntry(This, BaseEntry);
  783. Entry = NULL;
  784. }
  785. if (Entry) {
  786. //
  787. // mark it dirty and new for flushing
  788. //
  789. OSBE_SET_NEW(Entry);
  790. OSBE_SET_DIRTY(Entry);
  791. }
  792. }
  793. }
  794. return (POS_BOOT_ENTRY)Entry;
  795. }
  796. static
  797. BOOLEAN
  798. BOIOSBOWrite(
  799. IN PBOI_OS_BOOT_OPTIONS This,
  800. IN PCTSTR Buffer
  801. )
  802. {
  803. BOOLEAN Result = FALSE;
  804. if (This && Buffer) {
  805. TCHAR BackupFileName[MAX_PATH];
  806. PTSTR Extension;
  807. HANDLE FileHandle;
  808. //
  809. // Create a backup name
  810. //
  811. _tcscpy(BackupFileName, This->BootIniPath);
  812. Extension = _tcschr(BackupFileName, TEXT('.'));
  813. if (Extension) {
  814. _tcscpy(Extension, TEXT(".BAK"));
  815. } else {
  816. _tcscat(BackupFileName, TEXT(".BAK"));
  817. }
  818. //
  819. // Delete the backup file if it exists
  820. //
  821. SetFileAttributes(BackupFileName, FILE_ATTRIBUTE_NORMAL);
  822. DeleteFile(BackupFileName);
  823. //
  824. // Copy the existing boot.ini as backup file
  825. //
  826. SetFileAttributes(This->BootIniPath, FILE_ATTRIBUTE_NORMAL);
  827. CopyFile(This->BootIniPath, BackupFileName, FALSE);
  828. //
  829. // Create new boot.ini file
  830. //
  831. FileHandle = CreateFile(This->BootIniPath,
  832. GENERIC_READ | GENERIC_WRITE,
  833. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  834. NULL,
  835. CREATE_ALWAYS,
  836. FILE_ATTRIBUTE_NORMAL,
  837. NULL);
  838. if (FileHandle && (FileHandle != INVALID_HANDLE_VALUE)) {
  839. PCHAR AnsiBuffer;
  840. ULONG BufferLength = _tcslen(Buffer);
  841. DWORD BytesWritten = 0;
  842. Result = TRUE;
  843. #ifdef UNICODE
  844. //
  845. // Convert the unicode buffer to ansi buffer
  846. //
  847. AnsiBuffer = (PCHAR)SBE_MALLOC(BufferLength + 1);
  848. if (AnsiBuffer) {
  849. memset(AnsiBuffer, 0, BufferLength);
  850. if (WideCharToMultiByte(CP_OEMCP,
  851. 0,
  852. Buffer,
  853. BufferLength,
  854. AnsiBuffer,
  855. BufferLength,
  856. NULL,
  857. NULL)) {
  858. Result = TRUE;
  859. AnsiBuffer[BufferLength] = 0;
  860. } else {
  861. Result = FALSE;
  862. }
  863. }
  864. #else
  865. AnsiBuffer = Buffer;
  866. #endif
  867. //
  868. // Write the buffer to the file
  869. //
  870. if (AnsiBuffer &&
  871. !WriteFile(FileHandle,
  872. AnsiBuffer,
  873. BufferLength,
  874. &BytesWritten,
  875. NULL)) {
  876. Result = FALSE;
  877. }
  878. if ((PVOID)AnsiBuffer != (PVOID)Buffer) {
  879. SBE_FREE(AnsiBuffer);
  880. AnsiBuffer = NULL;
  881. }
  882. //
  883. // Done with the file handle
  884. //
  885. CloseHandle(FileHandle);
  886. SetFileAttributes(This->BootIniPath,
  887. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY |
  888. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  889. }
  890. }
  891. return Result;
  892. }
  893. static
  894. BOOLEAN
  895. BOIOSBOFlush(
  896. IN POS_BOOT_OPTIONS Obj
  897. )
  898. {
  899. BOOLEAN Result = FALSE;
  900. PBOI_OS_BOOT_OPTIONS This = (PBOI_OS_BOOT_OPTIONS)Obj;
  901. if (This) {
  902. PTSTR Buffer = (PTSTR)SBE_MALLOC(MAX_BOOT_INI_SIZE * sizeof(TCHAR));
  903. if (Buffer) {
  904. TCHAR ScratchBuffer[MAX_PATH * 2] = {0};
  905. POS_BOOT_ENTRY ActiveEntry = OSBOGetActiveBootEntry(Obj);
  906. POS_BOOT_ENTRY CurrentEntry;
  907. PBOI_SECTION CurrentSection;
  908. Result = TRUE;
  909. memset(Buffer, 0, MAX_BOOT_INI_SIZE * sizeof(TCHAR));
  910. //
  911. // first flush the boot options
  912. //
  913. _tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
  914. _tcscat(Buffer, BOIOS_BOOTLOADER_SECTION);
  915. _tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
  916. _tcscat(Buffer, TEXT("\r\n"));
  917. //
  918. // write time out
  919. //
  920. _tcscat(Buffer, BOIOS_TIMEOUT_KEY);
  921. _tcscat(Buffer, _ltot(Obj->Timeout, ScratchBuffer, 10));
  922. _tcscat(Buffer, TEXT("\r\n"));
  923. //
  924. // write active entry
  925. //
  926. if (ActiveEntry) {
  927. _tcscpy(ScratchBuffer, BOIOS_DEFAULT_KEY);
  928. _tcscat(ScratchBuffer, OSBEGetBootVolumeName(ActiveEntry));
  929. _tcscat(ScratchBuffer, TEXT("\\"));
  930. _tcscat(ScratchBuffer, OSBEGetBootPath(ActiveEntry));
  931. _tcscat(ScratchBuffer, TEXT("\r\n"));
  932. _tcscat(Buffer, ScratchBuffer);
  933. }
  934. //
  935. // Write the boot entries section
  936. //
  937. _tcscat(Buffer, BOIOS_SECTION_NAME_START_STR);
  938. _tcscat(Buffer, BOIOS_OS_SECTION);
  939. _tcscat(Buffer, BOIOS_SECTION_NAME_END_STR);
  940. _tcscat(Buffer, TEXT("\r\n"));
  941. //
  942. // write each boot entry now
  943. //
  944. //
  945. // First write the valid arc entries
  946. //
  947. CurrentEntry = OSBOGetFirstBootEntry(Obj);
  948. while (Result && CurrentEntry) {
  949. if (!OSBE_IS_DELETED(CurrentEntry) &&
  950. !OSBE_IS_OLDOS(CurrentEntry)) {
  951. Result = BOIOSBEWrite(CurrentEntry, Buffer);
  952. }
  953. CurrentEntry = OSBOGetNextBootEntry(Obj, CurrentEntry);
  954. }
  955. //
  956. // Now write the old OS entries
  957. // NOTE : We do this for backward compatabily reasons
  958. //
  959. CurrentEntry = OSBOGetFirstBootEntry(Obj);
  960. while (Result && CurrentEntry) {
  961. if (OSBE_IS_OLDOS(CurrentEntry)) {
  962. Result = BOIOSBEWrite(CurrentEntry, Buffer);
  963. }
  964. CurrentEntry = OSBOGetNextBootEntry(Obj, CurrentEntry);
  965. }
  966. //
  967. // Write any additions sections which were present on the
  968. //
  969. CurrentSection = BOIOSGetFirstSection(This);
  970. while (Result && CurrentSection) {
  971. //
  972. // Write all the other additional sections in boot.ini other
  973. // than [boot loader] and [operating systems]
  974. //
  975. if (_tcsicmp(BOISectionGetName(CurrentSection), BOIOS_BOOTLOADER_SECTION) &&
  976. _tcsicmp(BOISectionGetName(CurrentSection), BOIOS_OS_SECTION)) {
  977. Result = BOISectionWrite(CurrentSection, Buffer);
  978. }
  979. CurrentSection = BOIOSGetNextSection(This, CurrentSection);
  980. }
  981. Result = BOIOSBOWrite(This, Buffer);
  982. //
  983. // Free the allocated buffer
  984. //
  985. SBE_FREE(Buffer);
  986. }
  987. }
  988. return Result;
  989. }
  990. //
  991. // Dummy Driver Routines
  992. //
  993. PDRIVER_ENTRY
  994. BOIOSBOAddNewDriverEntry(
  995. IN POS_BOOT_OPTIONS This,
  996. IN PCWSTR FriendlyName,
  997. IN PCWSTR NtDevicePath,
  998. IN PCWSTR SrcNtFullPath
  999. )
  1000. /*++
  1001. Dummy routine
  1002. --*/
  1003. {
  1004. return NULL;
  1005. }