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.

3048 lines
84 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. arc.c
  5. Abstract:
  6. ARC/NV-RAM manipulation routines for 32-bit winnt setup.
  7. Author:
  8. Ted Miller (tedm) 19-December-1993
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "initguid.h"
  14. #include "diskguid.h"
  15. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  16. #if defined(_X86_)
  17. LOGICAL IsArcChecked = FALSE;
  18. LOGICAL IsArcMachine;
  19. #endif
  20. #if defined(EFI_NVRAM_ENABLED)
  21. #include <ntosp.h> // for ALIGN_UP
  22. LOGICAL IsEfiChecked = FALSE;
  23. LOGICAL IsEfiMachine;
  24. DWORD
  25. InitializeEfiStuff(
  26. IN HWND Parent
  27. );
  28. NTSTATUS
  29. (*AddBootEntry) (
  30. IN PBOOT_ENTRY BootEntry,
  31. OUT PULONG Id OPTIONAL
  32. );
  33. NTSTATUS
  34. (*DeleteBootEntry) (
  35. IN ULONG Id
  36. );
  37. NTSTATUS
  38. (*EnumerateBootEntries) (
  39. OUT PVOID Buffer,
  40. IN OUT PULONG BufferLength
  41. );
  42. NTSTATUS
  43. (*QueryBootEntryOrder) (
  44. OUT PULONG Ids,
  45. IN OUT PULONG Count
  46. );
  47. NTSTATUS
  48. (*SetBootEntryOrder) (
  49. IN PULONG Ids,
  50. IN ULONG Count
  51. );
  52. NTSTATUS
  53. (*QueryBootOptions) (
  54. OUT PBOOT_OPTIONS BootOptions,
  55. IN OUT PULONG BootOptionsLength
  56. );
  57. NTSTATUS
  58. (*SetBootOptions) (
  59. IN PBOOT_OPTIONS BootOptions,
  60. IN ULONG FieldsToChange
  61. );
  62. PBOOT_OPTIONS BootOptions = NULL;
  63. PBOOT_OPTIONS OriginalBootOptions = NULL;
  64. PULONG OriginalBootEntryOrder = NULL;
  65. ULONG OriginalBootEntryOrderCount;
  66. PBOOT_ENTRY_LIST BootEntries = NULL;
  67. //
  68. // MY_BOOT_ENTRY is the internal representation of an EFI NVRAM boot item.
  69. // The NtBootEntry item is the structure passed to/from the NT boot entry APIs.
  70. //
  71. typedef struct _MY_BOOT_ENTRY {
  72. struct _MY_BOOT_ENTRY *Next;
  73. PUCHAR AllocationEnd;
  74. ULONG Status;
  75. PWSTR FriendlyName;
  76. ULONG FriendlyNameLength;
  77. PWSTR OsLoadOptions;
  78. ULONG OsLoadOptionsLength;
  79. PFILE_PATH BootFilePath;
  80. PFILE_PATH OsFilePath;
  81. BOOT_ENTRY NtBootEntry;
  82. } MY_BOOT_ENTRY, *PMY_BOOT_ENTRY;
  83. #define MBE_STATUS_ORDERED 0x00000001
  84. #define MBE_STATUS_NEW 0x00000002
  85. #define MBE_STATUS_DELETED 0x00000004
  86. #define MBE_STATUS_COMMITTED 0x00000008
  87. #define IS_BOOT_ENTRY_ACTIVE(_be) \
  88. (((_be)->NtBootEntry.Attributes & BOOT_ENTRY_ATTRIBUTE_ACTIVE) != 0)
  89. #define IS_BOOT_ENTRY_WINDOWS(_be) \
  90. (((_be)->NtBootEntry.Attributes & BOOT_ENTRY_ATTRIBUTE_WINDOWS) != 0)
  91. #define IS_BOOT_ENTRY_REMOVABLE_MEDIA(_be) \
  92. (((_be)->NtBootEntry.Attributes & BOOT_ENTRY_ATTRIBUTE_REMOVABLE_MEDIA) != 0)
  93. #define IS_BOOT_ENTRY_ORDERED(_be) \
  94. (((_be)->Status & MBE_STATUS_ORDERED) != 0)
  95. #define IS_BOOT_ENTRY_NEW(_be) \
  96. (((_be)->Status & MBE_STATUS_NEW) != 0)
  97. #define IS_BOOT_ENTRY_DELETED(_be) \
  98. (((_be)->Status & MBE_STATUS_DELETED) != 0)
  99. #define IS_BOOT_ENTRY_COMMITTED(_be) \
  100. (((_be)->Status & MBE_STATUS_COMMITTED) != 0)
  101. PMY_BOOT_ENTRY MyBootEntries = NULL;
  102. NTSTATUS
  103. ConvertBootEntries(
  104. VOID
  105. );
  106. BOOL
  107. CreateBootEntry(
  108. PWSTR BootFileDevice,
  109. PWSTR BootFilePath,
  110. PWSTR OsLoadDevice,
  111. PWSTR OsLoadPath,
  112. PWSTR OsLoadOptions,
  113. PWSTR FriendlyName
  114. );
  115. #define ADD_OFFSET(_p,_o) (PVOID)((PUCHAR)(_p) + (_p)->_o)
  116. #endif // defined(EFI_NVRAM_ENABLED)
  117. UINT SystemPartitionCount;
  118. PWSTR* SystemPartitionNtNames;
  119. PWSTR SystemPartitionNtName;
  120. PWSTR SystemPartitionVolumeGuid;
  121. typedef enum {
  122. BootVarSystemPartition,
  123. BootVarOsLoader,
  124. BootVarOsLoadPartition,
  125. BootVarOsLoadFilename,
  126. BootVarLoadIdentifier,
  127. BootVarOsLoadOptions,
  128. BootVarMax
  129. } BootVars;
  130. LPCWSTR BootVarNames[BootVarMax] = { L"SYSTEMPARTITION",
  131. L"OSLOADER",
  132. L"OSLOADPARTITION",
  133. L"OSLOADFILENAME",
  134. L"LOADIDENTIFIER",
  135. L"OSLOADOPTIONS"
  136. };
  137. LPCWSTR szAUTOLOAD = L"AUTOLOAD";
  138. LPCWSTR szCOUNTDOWN = L"COUNTDOWN";
  139. LPWSTR BootVarValues[BootVarMax];
  140. LPCWSTR OriginalBootVarValues[BootVarMax];
  141. LPCWSTR OriginalCountdown;
  142. LPCWSTR OriginalAutoload;
  143. DWORD BootVarComponentCount[BootVarMax];
  144. LPWSTR *BootVarComponents[BootVarMax];
  145. DWORD LargestComponentCount;
  146. LPWSTR DosDeviceTargets[26];
  147. //
  148. // Flag indicating whether we messed with NV-RAM and thus need to
  149. // try to restore it in case the user cancels.
  150. //
  151. BOOL CleanUpNvRam;
  152. //
  153. // Leave as array because some code uses sizeof(ArcNameDirectory)
  154. //
  155. WCHAR ArcNameDirectory[] = L"\\ArcName";
  156. #define GLOBAL_ROOT L"\\\\?\\GLOBALROOT"
  157. #define MAX_COMPONENTS 20
  158. WCHAR ForcedSystemPartition;
  159. //
  160. // Helper macro to make object attribute initialization a little cleaner.
  161. //
  162. #define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
  163. \
  164. RtlInitUnicodeString((UnicodeString),(UnicodeText)); \
  165. \
  166. InitializeObjectAttributes( \
  167. (Obja), \
  168. (UnicodeString), \
  169. OBJ_CASE_INSENSITIVE, \
  170. NULL, \
  171. NULL \
  172. )
  173. UINT
  174. NormalizeArcPath(
  175. IN PCWSTR Path,
  176. OUT LPWSTR *NormalizedPath
  177. )
  178. /*++
  179. Routine Description:
  180. Transform an ARC path into one with no sets of empty parenthesis
  181. (ie, transforom all instances of () to (0).).
  182. Arguments:
  183. Path - ARC path to be normalized.
  184. NormalizedPath - if successful, receives a pointer to the
  185. normalized arc path. The caller must free with FREE().
  186. Return Value:
  187. Win32 error code indicating outcome.
  188. --*/
  189. {
  190. LPWSTR r;
  191. LPCWSTR p,q;
  192. LPWSTR normalizedPath;
  193. UINT numEmpties=0; //Number of instances of "()" seen so far
  194. UINT numEmptiesAllocated=100; //Number of instances of "()" accounted for
  195. if(normalizedPath = MALLOC((lstrlen(Path)+1+numEmptiesAllocated)*sizeof(WCHAR))) {
  196. ZeroMemory(normalizedPath,(lstrlen(Path)+1+numEmptiesAllocated)*sizeof(WCHAR));
  197. } else {
  198. return(ERROR_NOT_ENOUGH_MEMORY);
  199. }
  200. for(p=Path; q=wcsstr(p,L"()"); p=q+2) {
  201. numEmpties++;
  202. if (numEmpties > numEmptiesAllocated) {
  203. numEmptiesAllocated += 100;
  204. r = REALLOC(normalizedPath,(lstrlen(Path)+1+numEmptiesAllocated)*sizeof(WCHAR));
  205. if (r) {
  206. normalizedPath = r;
  207. }
  208. else {
  209. FREE(normalizedPath);
  210. return(ERROR_NOT_ENOUGH_MEMORY);
  211. }
  212. }
  213. r = normalizedPath + lstrlen(normalizedPath);
  214. lstrcpyn(r,p,(int)(q-p)+1);
  215. lstrcat(normalizedPath,L"(0)");
  216. }
  217. lstrcat(normalizedPath,p);
  218. if(r = REALLOC(normalizedPath,(lstrlen(normalizedPath)+1)*sizeof(WCHAR))) {
  219. *NormalizedPath = r;
  220. return(NO_ERROR);
  221. } else {
  222. FREE(normalizedPath);
  223. return(ERROR_NOT_ENOUGH_MEMORY);
  224. }
  225. }
  226. //
  227. // ISSUE -- Since only MAX_COMPONENTS components are supported in the input string, is this
  228. // a security hole, since having a boot.ini with more than 20 arc lines is not supported?
  229. //
  230. DWORD
  231. GetVarComponents(
  232. IN PCWSTR VarValue,
  233. OUT LPWSTR **Components,
  234. OUT PDWORD ComponentCount
  235. )
  236. /*++
  237. Routine Description:
  238. Split a semi-colon delineated list of arc paths up into
  239. a set of individual strings. For each component
  240. leading and trailing spaces are stripped out.
  241. Arguments:
  242. VarValue - supplies string with list of arc paths to be split apart. Only
  243. a maximum of MAX_COMPONENTS components are supported.
  244. Components - receives array of pointers to individual components
  245. on the variable specified in VarValue.
  246. ComponentCount - receives number of separate arc paths in the
  247. Components array.
  248. Return Value:
  249. Win32 error indicating outcome. If NO_ERROR then the caller
  250. must free the Components array and the strings pointed to by its elements.
  251. --*/
  252. {
  253. LPWSTR *components;
  254. LPWSTR *temp;
  255. DWORD componentCount;
  256. LPCWSTR p;
  257. LPCWSTR Var;
  258. LPWSTR comp;
  259. DWORD len;
  260. UINT ec;
  261. components = MALLOC(MAX_COMPONENTS * sizeof(LPWSTR));
  262. if(!components) {
  263. return(ERROR_NOT_ENOUGH_MEMORY);
  264. }
  265. ZeroMemory(components,MAX_COMPONENTS * sizeof(LPWSTR));
  266. ec = NO_ERROR;
  267. for(Var=VarValue,componentCount=0; *Var; ) {
  268. //
  269. // Skip leading spaces.
  270. //
  271. while((*Var == L' ') || (*Var == L'\t')) {
  272. Var++;
  273. }
  274. if(*Var == 0) {
  275. break;
  276. }
  277. p = Var;
  278. while(*p && (*p != L';')) {
  279. p++;
  280. }
  281. len = (DWORD)((PUCHAR)p - (PUCHAR)Var);
  282. comp = MALLOC(len + sizeof(WCHAR));
  283. if(!comp) {
  284. ec = ERROR_NOT_ENOUGH_MEMORY;
  285. break;
  286. }
  287. len /= sizeof(WCHAR);
  288. lstrcpynW(comp,Var,len+1);
  289. ec = NormalizeArcPath(comp,&components[componentCount]);
  290. FREE(comp);
  291. if(ec != NO_ERROR) {
  292. break;
  293. }
  294. componentCount++;
  295. if(componentCount == MAX_COMPONENTS) {
  296. break;
  297. }
  298. Var = p;
  299. if(*Var) {
  300. Var++; // skip ;
  301. }
  302. }
  303. if(ec == NO_ERROR) {
  304. if(componentCount) {
  305. temp = REALLOC(components,componentCount*sizeof(LPWSTR));
  306. if(!temp) {
  307. ec = ERROR_NOT_ENOUGH_MEMORY;
  308. }
  309. } else {
  310. temp = NULL;
  311. }
  312. }
  313. if(ec == NO_ERROR) {
  314. *Components = temp;
  315. *ComponentCount = componentCount;
  316. } else {
  317. for(len=0; components[len] && (len<MAX_COMPONENTS); len++) {
  318. FREE(components[len]);
  319. }
  320. FREE(components);
  321. }
  322. return(ec);
  323. }
  324. NTSTATUS
  325. QueryCanonicalName(
  326. IN PWSTR Name,
  327. IN ULONG MaxDepth,
  328. OUT PWSTR CanonicalName,
  329. IN ULONG SizeOfBufferInBytes
  330. )
  331. /*++
  332. Routine Description:
  333. Resolves the symbolic name to the specified depth. To resolve
  334. a symbolic name completely specify the MaxDepth as -1
  335. Arguments:
  336. Name - Symbolic name to be resolved
  337. MaxDepth - The depth till which the resolution needs to
  338. be carried out
  339. CanonicalName - The fully resolved name
  340. SizeOfBufferInBytes - The size of the CanonicalName buffer in
  341. bytes
  342. Return Value:
  343. Appropriate NT status code
  344. --*/
  345. {
  346. UNICODE_STRING name, canonName;
  347. OBJECT_ATTRIBUTES oa;
  348. NTSTATUS status;
  349. HANDLE handle;
  350. ULONG CurrentDepth;
  351. RtlInitUnicodeString(&name, Name);
  352. canonName.MaximumLength = (USHORT) (SizeOfBufferInBytes - sizeof(WCHAR));
  353. canonName.Length = 0;
  354. canonName.Buffer = CanonicalName;
  355. if (name.Length >= canonName.MaximumLength) {
  356. return STATUS_BUFFER_TOO_SMALL;
  357. }
  358. RtlCopyMemory(canonName.Buffer, name.Buffer, name.Length);
  359. canonName.Length = name.Length;
  360. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  361. for (CurrentDepth = 0; CurrentDepth < MaxDepth; CurrentDepth++) {
  362. InitializeObjectAttributes(&oa, &canonName, OBJ_CASE_INSENSITIVE, 0, 0);
  363. status = NtOpenSymbolicLinkObject(&handle,
  364. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  365. &oa);
  366. if (!NT_SUCCESS(status)) {
  367. break;
  368. }
  369. status = NtQuerySymbolicLinkObject(handle, &canonName, NULL);
  370. NtClose(handle);
  371. if (!NT_SUCCESS(status)) {
  372. return status;
  373. }
  374. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  375. }
  376. return STATUS_SUCCESS;
  377. }
  378. //
  379. // Structure to map from old NT partition names like
  380. // \device\harddisk0\partition1 to new NT partition names
  381. // like \device\harddiskvolume1
  382. //
  383. typedef struct _NAME_TRANSLATIONS {
  384. WCHAR OldNtName[MAX_PATH];
  385. WCHAR NewNtName[MAX_PATH];
  386. } NT_NAME_TRANSLATION, * PNT_NAME_TRANSLATION;
  387. //
  388. // Map of old style NT partition names to new style NT
  389. // partition names
  390. //
  391. NT_NAME_TRANSLATION OldNewNtNames[256] = {0};
  392. PWSTR
  393. OldNtNameToNewNtName(
  394. IN PCWSTR OldNtName
  395. )
  396. /*++
  397. Routine Description:
  398. Given a old format NT name tries to lookup at new format
  399. NT name in the global map
  400. Arguments:
  401. OldNtName - The partition name specified in the old
  402. format
  403. Return Value:
  404. The new NT name if there exists one, otherwise NULL.
  405. --*/
  406. {
  407. ULONG Index = 0;
  408. ULONG MaxEntries = sizeof(OldNewNtNames)/sizeof(NT_NAME_TRANSLATION);
  409. PWSTR NewNtName = NULL;
  410. for (Index = 0; (Index < MaxEntries); Index++) {
  411. if (OldNewNtNames[Index].OldNtName[0] &&
  412. !_wcsicmp(OldNewNtNames[Index].OldNtName, OldNtName)) {
  413. NewNtName = OldNewNtNames[Index].NewNtName;
  414. }
  415. }
  416. return NewNtName;
  417. }
  418. PWSTR
  419. NewNtNameToOldNtName(
  420. IN PCWSTR NewNtName
  421. )
  422. /*++
  423. Routine Description:
  424. Given a new format NT name tries to lookup at old format
  425. NT name in the global map
  426. Arguments:
  427. NewNtName - The partition name specified in the new
  428. format
  429. Return Value:
  430. The old NT name if there exists one, otherwise NULL.
  431. --*/
  432. {
  433. ULONG Index = 0;
  434. ULONG MaxEntries = sizeof(OldNewNtNames)/sizeof(NT_NAME_TRANSLATION);
  435. PWSTR OldNtName = NULL;
  436. for (Index=0; (Index < MaxEntries); Index++) {
  437. if (OldNewNtNames[Index].NewNtName[0] &&
  438. !_wcsicmp(OldNewNtNames[Index].NewNtName, NewNtName)) {
  439. OldNtName = OldNewNtNames[Index].OldNtName;
  440. }
  441. }
  442. return OldNtName;
  443. }
  444. DWORD
  445. InitOldToNewNtNameTranslations(
  446. VOID
  447. )
  448. /*++
  449. Routine Description:
  450. Initializes the global old NT partition names to
  451. new NT partition names mapping.
  452. Arguments:
  453. None.
  454. Return Value:
  455. The number of valid entries in the map
  456. --*/
  457. {
  458. DWORD MappingCount = 0;
  459. SYSTEM_DEVICE_INFORMATION SysDevInfo = {0};
  460. NTSTATUS Status;
  461. OBJECT_ATTRIBUTES ObjAttrs;
  462. UNICODE_STRING ObjName;
  463. Status = NtQuerySystemInformation(SystemDeviceInformation,
  464. &SysDevInfo,
  465. sizeof(SYSTEM_DEVICE_INFORMATION),
  466. NULL);
  467. if (NT_SUCCESS(Status)) {
  468. ULONG Index;
  469. WCHAR OldNtPath[MAX_PATH];
  470. DWORD ErrorCode = 0;
  471. ULONG SlotIndex = 0;
  472. ULONG MaxSlots = sizeof(OldNewNtNames)/sizeof(NT_NAME_TRANSLATION);
  473. for (Index=0;
  474. (!ErrorCode) && (Index < SysDevInfo.NumberOfDisks) &&
  475. (SlotIndex < MaxSlots);
  476. Index++) {
  477. HANDLE DirectoryHandle;
  478. swprintf(OldNtPath,
  479. L"\\device\\Harddisk%d",
  480. Index);
  481. //
  482. // Open the disk directory.
  483. //
  484. INIT_OBJA(&ObjAttrs, &ObjName, OldNtPath);
  485. Status = NtOpenDirectoryObject(&DirectoryHandle,
  486. DIRECTORY_QUERY,
  487. &ObjAttrs);
  488. if(NT_SUCCESS(Status)) {
  489. BOOLEAN RestartScan = TRUE;
  490. ULONG Context = 0;
  491. BOOLEAN MoreEntries = TRUE;
  492. WCHAR Buffer[MAX_PATH * 2] = {0};
  493. POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
  494. do {
  495. Status = NtQueryDirectoryObject(
  496. DirectoryHandle,
  497. Buffer,
  498. sizeof(Buffer),
  499. TRUE, // return single entry
  500. RestartScan,
  501. &Context,
  502. NULL // return length
  503. );
  504. if(NT_SUCCESS(Status)) {
  505. //
  506. // Make sure this name is a symbolic link.
  507. //
  508. if(DirInfo->Name.Length &&
  509. (DirInfo->TypeName.Length >= 24) &&
  510. CharUpperBuff((LPWSTR)DirInfo->TypeName.Buffer,12) &&
  511. !memcmp(DirInfo->TypeName.Buffer,L"SYMBOLICLINK",24)) {
  512. WCHAR EntryName[MAX_PATH];
  513. StringCchCopy(EntryName, ARRAYSIZE(EntryName), OldNtPath);
  514. ConcatenatePaths(EntryName,
  515. DirInfo->Name.Buffer,
  516. ARRAYSIZE(EntryName));
  517. Status = QueryCanonicalName(EntryName, -1, Buffer, sizeof(Buffer));
  518. if (NT_SUCCESS(Status)) {
  519. StringCchCopyW( OldNewNtNames[SlotIndex].OldNtName,
  520. ARRAYSIZE(OldNewNtNames[0].OldNtName),
  521. EntryName);
  522. StringCchCopyW( OldNewNtNames[SlotIndex].NewNtName,
  523. ARRAYSIZE(OldNewNtNames[0].NewNtName),
  524. Buffer);
  525. SlotIndex++;
  526. }
  527. }
  528. } else {
  529. MoreEntries = FALSE;
  530. if(Status == STATUS_NO_MORE_ENTRIES) {
  531. Status = STATUS_SUCCESS;
  532. }
  533. ErrorCode = RtlNtStatusToDosError(Status);
  534. }
  535. RestartScan = FALSE;
  536. } while(MoreEntries && (SlotIndex < MaxSlots));
  537. NtClose(DirectoryHandle);
  538. } else {
  539. ErrorCode = RtlNtStatusToDosError(Status);
  540. }
  541. }
  542. if (!ErrorCode && NT_SUCCESS(Status)) {
  543. MappingCount = SlotIndex;
  544. }
  545. }
  546. return MappingCount;
  547. }
  548. DWORD
  549. NtNameToArcPath (
  550. IN PCWSTR NtName,
  551. OUT LPWSTR *ArcPath
  552. )
  553. /*++
  554. Routine Description:
  555. Convert an NT volume name to an ARC path.
  556. Arguments:
  557. NtName - supplies name of drive to be converted.
  558. ArcPath - receives pointer to buffer containing arc path
  559. if the routine is successful. Caller must free with FREE().
  560. Return Value:
  561. Win32 error code indicating outcome.
  562. --*/
  563. {
  564. UNICODE_STRING UnicodeString;
  565. HANDLE DirectoryHandle;
  566. OBJECT_ATTRIBUTES Obja;
  567. NTSTATUS Status;
  568. BOOLEAN RestartScan;
  569. DWORD Context;
  570. BOOL MoreEntries;
  571. LPWSTR ArcName = NULL;
  572. WCHAR Buffer[2 * MAX_PATH];
  573. WCHAR ArcDiskName[MAX_PATH] = {0};
  574. WCHAR NtDiskName[MAX_PATH] = {0};
  575. WCHAR ArcPartitionName[MAX_PATH] = {0};
  576. PWSTR PartitionName = NULL;
  577. PWSTR PartitionNumStr = NULL;
  578. POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
  579. DWORD ErrorCode;
  580. ErrorCode = NO_ERROR;
  581. *ArcPath = NULL;
  582. //
  583. // Get hold of the NT disk name
  584. //
  585. PartitionName = NewNtNameToOldNtName(NtName);
  586. if (PartitionName) {
  587. PWSTR PartitionNameStart = PartitionName;
  588. PartitionName = wcsrchr(PartitionName, L'\\');
  589. if (PartitionName && wcsstr(PartitionName, L"Partition")) {
  590. wcsncpy(NtDiskName, PartitionNameStart, PartitionName - PartitionNameStart);
  591. wcscat(NtDiskName, L"\\Partition0");
  592. PartitionNumStr = PartitionName + wcslen(L"\\Partition");
  593. }
  594. }
  595. //
  596. // Open the \ArcName directory.
  597. //
  598. INIT_OBJA(&Obja,&UnicodeString,ArcNameDirectory);
  599. Status = NtOpenDirectoryObject(&DirectoryHandle,DIRECTORY_QUERY,&Obja);
  600. if(NT_SUCCESS(Status)) {
  601. RestartScan = TRUE;
  602. Context = 0;
  603. MoreEntries = TRUE;
  604. do {
  605. Status = NtQueryDirectoryObject(
  606. DirectoryHandle,
  607. Buffer,
  608. sizeof(Buffer),
  609. TRUE, // return single entry
  610. RestartScan,
  611. &Context,
  612. NULL // return length
  613. );
  614. if(NT_SUCCESS(Status)) {
  615. CharLower(DirInfo->Name.Buffer);
  616. //
  617. // Make sure this name is a symbolic link.
  618. //
  619. if(DirInfo->Name.Length
  620. && (DirInfo->TypeName.Length >= 24)
  621. && CharUpperBuff((LPWSTR)DirInfo->TypeName.Buffer,12)
  622. && !memcmp(DirInfo->TypeName.Buffer,L"SYMBOLICLINK",24))
  623. {
  624. WCHAR OldNtName[2 * MAX_PATH] = {0};
  625. DWORD size = DirInfo->Name.Length + sizeof(ArcNameDirectory) + sizeof(WCHAR);
  626. ArcName = MALLOC(size);
  627. if(!ArcName) {
  628. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  629. break;
  630. }
  631. //
  632. // These two operations are safe, since we have accounted for the size of an
  633. // ARC path, which could theoretically be larger than MAX_PATH
  634. //
  635. lstrcpy(ArcName,ArcNameDirectory);
  636. ConcatenatePaths(ArcName,DirInfo->Name.Buffer,size / sizeof(WCHAR));
  637. //
  638. // We have the entire arc name in ArcName. Now open the first
  639. // level symbolic link.
  640. //
  641. Status = QueryCanonicalName(ArcName, 1, Buffer, sizeof(Buffer));
  642. if (NT_SUCCESS(Status)) {
  643. wcscpy(OldNtName, Buffer);
  644. //
  645. // Now resolve the complete symbolic link
  646. //
  647. Status = QueryCanonicalName(ArcName, -1, Buffer, sizeof(Buffer));
  648. if (NT_SUCCESS(Status)) {
  649. if(!lstrcmpi(Buffer, NtName)) {
  650. *ArcPath = ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR));
  651. } else {
  652. if (!lstrcmpi(OldNtName, NtDiskName)) {
  653. wcscpy(ArcDiskName,
  654. ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR)));
  655. }
  656. }
  657. } else {
  658. if(!lstrcmpi(OldNtName, NtName)) {
  659. *ArcPath = ArcName + (sizeof(ArcNameDirectory)/sizeof(WCHAR));
  660. }
  661. }
  662. }
  663. if(!(*ArcPath)) {
  664. FREE(ArcName);
  665. ArcName = NULL;
  666. }
  667. }
  668. } else {
  669. MoreEntries = FALSE;
  670. if(Status == STATUS_NO_MORE_ENTRIES) {
  671. Status = STATUS_SUCCESS;
  672. }
  673. ErrorCode = RtlNtStatusToDosError(Status);
  674. }
  675. RestartScan = FALSE;
  676. } while(MoreEntries && !(*ArcPath));
  677. NtClose(DirectoryHandle);
  678. } else {
  679. ErrorCode = RtlNtStatusToDosError(Status);
  680. }
  681. //
  682. // If we found a match for the disk but not for the actual
  683. // partition specified then guess thepartition number
  684. // (based on the current nt partition number )
  685. //
  686. if ((!*ArcPath) && ArcDiskName[0] && PartitionName && PartitionNumStr) {
  687. PWSTR EndPtr = NULL;
  688. ULONG PartitionNumber = wcstoul(PartitionNumStr, &EndPtr, 10);
  689. if (PartitionNumber) {
  690. StringCchPrintfW(ArcPartitionName,
  691. ARRAYSIZE(ArcPartitionName),
  692. L"%wspartition(%d)",
  693. ArcDiskName,
  694. PartitionNumber);
  695. *ArcPath = DupString(ArcPartitionName);
  696. ErrorCode = NO_ERROR;
  697. DebugLog( Winnt32LogInformation,
  698. TEXT("\nCould not find arcname mapping for %1 partition.\r\n")
  699. TEXT("Guessing the arcname to be %2"),
  700. 0,
  701. NtName,
  702. ArcPartitionName);
  703. }
  704. }
  705. if (ErrorCode == NO_ERROR) {
  706. if(*ArcPath) {
  707. //
  708. // ArcPath points into the middle of a buffer.
  709. // The caller needs to be able to free it, so place it in its
  710. // own buffer here.
  711. //
  712. *ArcPath = DupString(*ArcPath);
  713. if (ArcName) {
  714. FREE(ArcName);
  715. }
  716. if(*ArcPath == NULL) {
  717. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  718. }
  719. } else {
  720. //
  721. // No matching drive.
  722. //
  723. ErrorCode = ERROR_INVALID_DRIVE;
  724. }
  725. }
  726. return ErrorCode;
  727. }
  728. DWORD
  729. DriveLetterToArcPath(
  730. IN WCHAR DriveLetter,
  731. OUT LPWSTR *ArcPath
  732. )
  733. /*++
  734. Routine Description:
  735. Convert a drive letter to an ARC path.
  736. This routine relies on the DosDeviceTargets array being set up
  737. beforehand.
  738. Arguments:
  739. DriveLetter - supplies letter of drive to be converted.
  740. ArcPath - receives pointer to buffer containing arc path
  741. if the routine is successful. Caller must free with FREE().
  742. Return Value:
  743. Win32 error code indicating outcome.
  744. --*/
  745. {
  746. LPWSTR NtPath;
  747. NtPath = DosDeviceTargets[(WCHAR)CharUpper((PWCHAR)DriveLetter)-L'A'];
  748. if(!NtPath) {
  749. return(ERROR_INVALID_DRIVE);
  750. }
  751. return NtNameToArcPath (NtPath, ArcPath);
  752. }
  753. DWORD
  754. ArcPathToDriveLetterAndNtName (
  755. IN PCWSTR ArcPath,
  756. OUT PWCHAR DriveLetter,
  757. OUT PWSTR NtName,
  758. IN DWORD BufferSizeInBytes
  759. )
  760. /*++
  761. Routine Description:
  762. Convert an arc path to a drive letter.
  763. This routine relies on the DosDeviceTargets array being set up
  764. beforehand.
  765. Arguments:
  766. ArcPath - specifies arc path to be converted.
  767. DriveLetter - if successful, receives letter of drive.
  768. Return Value:
  769. Win32 error code indicating outcome.
  770. --*/
  771. {
  772. NTSTATUS Status;
  773. WCHAR drive;
  774. LPWSTR arcPath;
  775. DWORD ec;
  776. //
  777. // Assume failure
  778. //
  779. *DriveLetter = 0;
  780. arcPath = MALLOC(((lstrlen(ArcPath)+1)*sizeof(WCHAR)) + sizeof(ArcNameDirectory));
  781. if(!arcPath) {
  782. return(ERROR_NOT_ENOUGH_MEMORY);
  783. }
  784. lstrcpy(arcPath,ArcNameDirectory);
  785. lstrcat(arcPath,L"\\");
  786. lstrcat(arcPath,ArcPath);
  787. Status = QueryCanonicalName(arcPath, -1, NtName, BufferSizeInBytes);
  788. if (NT_SUCCESS(Status)) {
  789. ec = ERROR_INVALID_DRIVE;
  790. for(drive=L'A'; drive<=L'Z'; drive++) {
  791. if(DosDeviceTargets[drive-L'A']
  792. && !lstrcmpi(NtName,DosDeviceTargets[drive-L'A']))
  793. {
  794. *DriveLetter = drive;
  795. ec = NO_ERROR;
  796. break;
  797. }
  798. }
  799. } else {
  800. ec = RtlNtStatusToDosError(Status);
  801. }
  802. FREE(arcPath);
  803. return(ec);
  804. }
  805. DWORD
  806. InitDriveNameTranslations(
  807. VOID
  808. )
  809. {
  810. WCHAR DriveName[15];
  811. WCHAR Drive;
  812. WCHAR Buffer[512];
  813. NTSTATUS status;
  814. swprintf(DriveName, L"\\DosDevices\\c:");
  815. //
  816. // Calculate NT names for all local hard disks C-Z.
  817. //
  818. for(Drive=L'A'; Drive<=L'Z'; Drive++) {
  819. DosDeviceTargets[Drive-L'A'] = NULL;
  820. if(MyGetDriveType(Drive) == DRIVE_FIXED) {
  821. DriveName[12] = Drive;
  822. status = QueryCanonicalName(DriveName, -1, Buffer, sizeof(Buffer));
  823. if (NT_SUCCESS(status)) {
  824. DosDeviceTargets[Drive-L'A'] = DupString(Buffer);
  825. if(!DosDeviceTargets[Drive-L'A']) {
  826. return(ERROR_NOT_ENOUGH_MEMORY);
  827. }
  828. }
  829. }
  830. }
  831. //
  832. // Initialize old Nt Parition names to new partition name
  833. // mapping
  834. //
  835. InitOldToNewNtNameTranslations();
  836. return(NO_ERROR);
  837. }
  838. DWORD
  839. DetermineSystemPartitions(
  840. VOID
  841. )
  842. {
  843. LPWSTR *SyspartComponents;
  844. DWORD NumSyspartComponents;
  845. DWORD d;
  846. DWORD rc;
  847. UINT u;
  848. WCHAR drive;
  849. WCHAR DeviceNtName[512];
  850. SyspartComponents = BootVarComponents[BootVarSystemPartition];
  851. NumSyspartComponents = BootVarComponentCount[BootVarSystemPartition];
  852. SystemPartitionNtNames = MALLOC ((NumSyspartComponents + 1) * sizeof (PWSTR));
  853. if (!SystemPartitionNtNames) {
  854. return ERROR_NOT_ENOUGH_MEMORY;
  855. }
  856. ZeroMemory(SystemPartitionNtNames, (NumSyspartComponents + 1) * sizeof (PWSTR));
  857. ZeroMemory(SystemPartitionDriveLetters,27*sizeof(WCHAR));
  858. //
  859. // Convert each system partition to a drive letter.
  860. //
  861. for(d=0; d<NumSyspartComponents; d++) {
  862. //
  863. // check for duplicates
  864. //
  865. if (SystemPartitionCount > 0) {
  866. for (u = 0; u < SystemPartitionCount; u++) {
  867. if (lstrcmpi (SyspartComponents[d], SystemPartitionNtNames[u]) == 0) {
  868. break;
  869. }
  870. }
  871. if (u < SystemPartitionCount) {
  872. continue;
  873. }
  874. }
  875. rc = ArcPathToDriveLetterAndNtName (
  876. SyspartComponents[d],
  877. &drive,
  878. DeviceNtName,
  879. (DWORD) sizeof (DeviceNtName)
  880. );
  881. if(rc == ERROR_NOT_ENOUGH_MEMORY) {
  882. return(ERROR_NOT_ENOUGH_MEMORY);
  883. }
  884. if (rc == ERROR_SUCCESS) {
  885. SystemPartitionDriveLetters[SystemPartitionCount] = drive;
  886. }
  887. SystemPartitionNtNames[SystemPartitionCount++] = DupString (DeviceNtName);
  888. }
  889. return(NO_ERROR);
  890. }
  891. DWORD
  892. DoInitializeArcStuff(
  893. VOID
  894. )
  895. {
  896. DWORD ec;
  897. DWORD var;
  898. UNICODE_STRING UnicodeString;
  899. NTSTATUS Status;
  900. WCHAR Buffer[4096];
  901. ec = InitDriveNameTranslations();
  902. if(ec != NO_ERROR) {
  903. goto c0;
  904. }
  905. //
  906. // Get relevent boot vars.
  907. //
  908. // Enable privilege -- since we check this privilege up front
  909. // in main() this should not fail.
  910. //
  911. if(!EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE)) {
  912. ec = ERROR_ACCESS_DENIED;
  913. goto c0;
  914. }
  915. for(var=0; var<BootVarMax; var++) {
  916. RtlInitUnicodeString(&UnicodeString,BootVarNames[var]);
  917. Status = NtQuerySystemEnvironmentValue(
  918. &UnicodeString,
  919. Buffer,
  920. sizeof(Buffer) / sizeof(WCHAR),
  921. NULL
  922. );
  923. if(NT_SUCCESS(Status)) {
  924. BootVarValues[var] = DupString(Buffer);
  925. OriginalBootVarValues[var] = DupString(Buffer);
  926. } else {
  927. //
  928. // We may get back failure if the variable is empty.
  929. //
  930. BootVarValues[var] = DupString(L"");
  931. OriginalBootVarValues[var] = DupString(L"");
  932. }
  933. if(!BootVarValues[var] || !OriginalBootVarValues[var]) {
  934. ec = ERROR_NOT_ENOUGH_MEMORY;
  935. goto c2;
  936. }
  937. ec = GetVarComponents(
  938. BootVarValues[var],
  939. &BootVarComponents[var],
  940. &BootVarComponentCount[var]
  941. );
  942. if(ec != NO_ERROR) {
  943. goto c2;
  944. }
  945. //
  946. // Track the variable with the most number of components.
  947. //
  948. if(BootVarComponentCount[var] > LargestComponentCount) {
  949. LargestComponentCount = BootVarComponentCount[var];
  950. }
  951. }
  952. //
  953. // Get original countdown and autoload values.
  954. // If not successful, oh well, we won't be able to restore them
  955. // if the user cancels.
  956. //
  957. RtlInitUnicodeString(&UnicodeString,szCOUNTDOWN);
  958. Status = NtQuerySystemEnvironmentValue(
  959. &UnicodeString,
  960. Buffer,
  961. sizeof(Buffer) / sizeof(WCHAR),
  962. NULL
  963. );
  964. if(NT_SUCCESS(Status)) {
  965. OriginalCountdown = DupString(Buffer);
  966. } else {
  967. OriginalCountdown = DupString(L"");
  968. }
  969. RtlInitUnicodeString(&UnicodeString,szAUTOLOAD);
  970. Status = NtQuerySystemEnvironmentValue(
  971. &UnicodeString,
  972. Buffer,
  973. sizeof(Buffer) / sizeof(WCHAR),
  974. NULL
  975. );
  976. if(NT_SUCCESS(Status)) {
  977. OriginalAutoload = DupString(Buffer);
  978. } else {
  979. OriginalAutoload = DupString(L"NO");
  980. }
  981. ec = DetermineSystemPartitions();
  982. if(ec != NO_ERROR) {
  983. goto c2;
  984. }
  985. return(NO_ERROR);
  986. c2:
  987. c0:
  988. return(ec);
  989. }
  990. BOOL
  991. ArcInitializeArcStuff(
  992. IN HWND Parent
  993. )
  994. {
  995. DWORD ec;
  996. BOOL b;
  997. HKEY key;
  998. DWORD type;
  999. DWORD size;
  1000. PBYTE buffer = NULL;
  1001. DWORD i;
  1002. #if defined(EFI_NVRAM_ENABLED)
  1003. //
  1004. // Try to initialize as an EFI machine. If we're on an EFI machine,
  1005. // this will succeed. Otherwise it will fail, in which case we try
  1006. // to initialize as an ARC machine.
  1007. //
  1008. ec = InitializeEfiStuff(Parent);
  1009. if (!IsEfi())
  1010. #endif
  1011. {
  1012. //
  1013. // Try to initialize as an ARC machine. This is expect to
  1014. // always succeed.
  1015. //
  1016. ec = DoInitializeArcStuff();
  1017. }
  1018. switch(ec) {
  1019. case NO_ERROR:
  1020. #if defined(EFI_NVRAM_ENABLED)
  1021. //
  1022. // On an EFI machine, the rest of this code (determining system
  1023. // partitions) is not necessary.
  1024. //
  1025. if (IsEfi()) {
  1026. b = TRUE;
  1027. } else
  1028. #endif
  1029. {
  1030. //
  1031. // Make sure there is at least one valid system partition.
  1032. //
  1033. if(!SystemPartitionCount) {
  1034. MessageBoxFromMessage(
  1035. Parent,
  1036. MSG_SYSTEM_PARTITION_INVALID,
  1037. FALSE,
  1038. AppTitleStringId,
  1039. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1040. );
  1041. b = FALSE;
  1042. } else {
  1043. i = 0;
  1044. //
  1045. // On ARC machines we set up a local boot directory that is
  1046. // placed in the root of the system partition.
  1047. //
  1048. //
  1049. // read the SystemPartition value from registry
  1050. //
  1051. // we must be careful in how we copy this value into buffers, since
  1052. // it comes from the registry!
  1053. //
  1054. ec = RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), &key);
  1055. if (ec == ERROR_SUCCESS) {
  1056. ec = RegQueryValueEx (key, TEXT("SystemPartition"), NULL, &type, NULL, &size);
  1057. if (ec == ERROR_SUCCESS && type == REG_SZ) {
  1058. buffer = MALLOC (size);
  1059. if (buffer) {
  1060. ec = RegQueryValueEx (key, TEXT("SystemPartition"), NULL, &type, buffer, &size);
  1061. if (ec != ERROR_SUCCESS) {
  1062. FREE (buffer);
  1063. buffer = NULL;
  1064. }
  1065. }
  1066. }
  1067. RegCloseKey (key);
  1068. }
  1069. #if defined(EFI_NVRAM_ENABLED)
  1070. //
  1071. // we just trust the value that comes from the regkey -- EFI
  1072. // systems only have one system partition, so it doesn't make
  1073. // sense to try to match this up against a list of potential
  1074. // system partitions.
  1075. //
  1076. SystemPartitionNtName = (PWSTR) buffer;
  1077. #else
  1078. //
  1079. // look for this system partition to make sure things are OK
  1080. //
  1081. if (buffer) {
  1082. while (i < SystemPartitionCount) {
  1083. if (lstrcmpi (SystemPartitionNtNames[i], (PCTSTR)buffer) == 0) {
  1084. SystemPartitionNtName = SystemPartitionNtNames[i];
  1085. break;
  1086. }
  1087. i++;
  1088. }
  1089. FREE (buffer);
  1090. }
  1091. #endif
  1092. if(!SystemPartitionNtName) {
  1093. MessageBoxFromMessage(
  1094. Parent,
  1095. MSG_SYSTEM_PARTITION_INVALID,
  1096. FALSE,
  1097. AppTitleStringId,
  1098. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1099. );
  1100. b = FALSE;
  1101. break;
  1102. }
  1103. #if !defined(EFI_NVRAM_ENABLED)
  1104. if (SystemPartitionDriveLetters[i]) {
  1105. SystemPartitionDriveLetter = ForcedSystemPartition
  1106. ? ForcedSystemPartition
  1107. : SystemPartitionDriveLetters[i];
  1108. LocalBootDirectory[0] = SystemPartitionDriveLetter;
  1109. LocalBootDirectory[1] = TEXT(':');
  1110. LocalBootDirectory[2] = TEXT('\\');
  1111. LocalBootDirectory[3] = 0;
  1112. } else
  1113. #endif
  1114. {
  1115. // SystemPartitionNtNtname is valid at this point thanks to
  1116. // the check above.
  1117. size = sizeof(GLOBAL_ROOT) +
  1118. lstrlen(SystemPartitionNtName)*sizeof(WCHAR) +
  1119. sizeof(WCHAR) + sizeof(WCHAR);
  1120. SystemPartitionVolumeGuid = MALLOC (size);
  1121. if(!SystemPartitionVolumeGuid) {
  1122. goto MemoryError;
  1123. }
  1124. lstrcpy (SystemPartitionVolumeGuid, GLOBAL_ROOT);
  1125. lstrcat (SystemPartitionVolumeGuid, SystemPartitionNtName);
  1126. lstrcat (SystemPartitionVolumeGuid, L"\\");
  1127. //
  1128. // SystemPartitionVolumeGuid may contain a value from
  1129. // the registry (SystemPartitionNtName), so we have to use a
  1130. // safe string operation here.
  1131. //
  1132. if (FAILED(StringCchCopy(LocalBootDirectory,
  1133. ARRAYSIZE(LocalBootDirectory),
  1134. SystemPartitionVolumeGuid)))
  1135. {
  1136. b = FALSE;
  1137. MYASSERT(FALSE);
  1138. break;
  1139. }
  1140. }
  1141. b = TRUE;
  1142. }
  1143. }
  1144. break;
  1145. case ERROR_NOT_ENOUGH_MEMORY:
  1146. MemoryError:
  1147. MessageBoxFromMessage(
  1148. Parent,
  1149. MSG_OUT_OF_MEMORY,
  1150. FALSE,
  1151. AppTitleStringId,
  1152. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1153. );
  1154. b = FALSE;
  1155. break;
  1156. default:
  1157. //
  1158. // Some other unknown error.
  1159. //
  1160. MessageBoxFromMessage(
  1161. Parent,
  1162. MSG_COULDNT_READ_NVRAM,
  1163. FALSE,
  1164. AppTitleStringId,
  1165. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1166. );
  1167. b = FALSE;
  1168. break;
  1169. }
  1170. #if defined(EFI_NVRAM_ENABLED)
  1171. //
  1172. // make sure the system partition is on a GPT disk.
  1173. //
  1174. if (b) {
  1175. HANDLE hDisk;
  1176. PARTITION_INFORMATION_EX partitionEx;
  1177. DWORD sizePartitionEx = 0;
  1178. UNICODE_STRING uString;
  1179. OBJECT_ATTRIBUTES ObjectAttributes;
  1180. IO_STATUS_BLOCK IoStatus;
  1181. NTSTATUS Status;
  1182. PWSTR p,q;
  1183. b = FALSE;
  1184. MYASSERT( SystemPartitionVolumeGuid != NULL );
  1185. //
  1186. // SystemPartitionVolumeGuid may have a '\' at the end of it.
  1187. // delete this character or we won't open the partition properly
  1188. //
  1189. p = DupString( SystemPartitionVolumeGuid + wcslen(GLOBAL_ROOT) );
  1190. if (p) {
  1191. if (wcslen(p) > 0) {
  1192. if (*(p+wcslen(p)-1) == L'\\') {
  1193. *(p+wcslen(p)-1) = L'\0';
  1194. }
  1195. }
  1196. INIT_OBJA( &ObjectAttributes, &uString, p );
  1197. Status = NtCreateFile(&hDisk,
  1198. (ACCESS_MASK)FILE_GENERIC_READ,
  1199. &ObjectAttributes,
  1200. &IoStatus,
  1201. NULL,
  1202. FILE_ATTRIBUTE_NORMAL,
  1203. FILE_SHARE_READ|FILE_SHARE_WRITE,
  1204. FILE_OPEN,
  1205. FILE_SYNCHRONOUS_IO_NONALERT,
  1206. NULL,
  1207. 0
  1208. );
  1209. if (NT_SUCCESS(Status)) {
  1210. Status = NtDeviceIoControlFile(
  1211. hDisk,
  1212. NULL,
  1213. NULL,
  1214. NULL,
  1215. &IoStatus,
  1216. IOCTL_DISK_GET_PARTITION_INFO_EX,
  1217. NULL,
  1218. 0,
  1219. &partitionEx,
  1220. sizeof(PARTITION_INFORMATION_EX) );
  1221. if (NT_SUCCESS(Status)) {
  1222. if (partitionEx.PartitionStyle == PARTITION_STYLE_GPT) {
  1223. b = TRUE;
  1224. }
  1225. } else if (Status == STATUS_INVALID_DEVICE_REQUEST) {
  1226. //
  1227. // we must be running on an older build where the IOCTL
  1228. // code is different
  1229. //
  1230. Status = NtDeviceIoControlFile(
  1231. hDisk,
  1232. NULL,
  1233. NULL,
  1234. NULL,
  1235. &IoStatus,
  1236. CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_READ_ACCESS),
  1237. NULL,
  1238. 0,
  1239. &partitionEx,
  1240. sizeof(PARTITION_INFORMATION_EX) );
  1241. if (NT_SUCCESS(Status)) {
  1242. if (partitionEx.PartitionStyle == PARTITION_STYLE_GPT) {
  1243. b = TRUE;
  1244. }
  1245. }
  1246. }
  1247. NtClose(hDisk);
  1248. }
  1249. FREE( p );
  1250. }
  1251. if (!b) {
  1252. MessageBoxFromMessage(
  1253. Parent,
  1254. MSG_SYSTEM_PARTITIONTYPE_INVALID,
  1255. FALSE,
  1256. AppTitleStringId,
  1257. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1258. );
  1259. }
  1260. }
  1261. #endif
  1262. return(b);
  1263. }
  1264. #if defined(EFI_NVRAM_ENABLED)
  1265. DWORD
  1266. LocateEfiSystemPartition(
  1267. OUT PWSTR SystemPartitionName
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. Locates the EFI system partition on a GPT disk
  1272. by scanning all the available hard disks.
  1273. Arguments:
  1274. SystemPartitionName : Buffer to receive system partition
  1275. name, if one is present
  1276. Return Value:
  1277. Win32 error code indicating outcome.
  1278. --*/
  1279. {
  1280. DWORD ErrorCode = ERROR_BAD_ARGUMENTS;
  1281. if (SystemPartitionName) {
  1282. SYSTEM_DEVICE_INFORMATION SysDevInfo;
  1283. NTSTATUS Status;
  1284. *SystemPartitionName = UNICODE_NULL;
  1285. //
  1286. // Get hold of number of hard disks on the system
  1287. //
  1288. ZeroMemory(&SysDevInfo, sizeof(SYSTEM_DEVICE_INFORMATION));
  1289. Status = NtQuerySystemInformation(SystemDeviceInformation,
  1290. &SysDevInfo,
  1291. sizeof(SYSTEM_DEVICE_INFORMATION),
  1292. NULL);
  1293. if (NT_SUCCESS(Status)) {
  1294. ULONG HardDiskCount = SysDevInfo.NumberOfDisks;
  1295. ULONG CurrentDisk;
  1296. ULONG BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  1297. (sizeof(PARTITION_INFORMATION_EX) * 128);
  1298. PCHAR Buffer = MALLOC(BufferSize);
  1299. BOOL Found = FALSE;
  1300. if (Buffer) {
  1301. //
  1302. // Go through each disk and find out its partition
  1303. // layout
  1304. //
  1305. for (CurrentDisk = 0;
  1306. (!Found && (CurrentDisk < HardDiskCount));
  1307. CurrentDisk++) {
  1308. WCHAR DiskName[MAX_PATH];
  1309. HANDLE DiskHandle;
  1310. swprintf(DiskName,
  1311. L"\\\\.\\PHYSICALDRIVE%d",
  1312. CurrentDisk);
  1313. DiskHandle = CreateFile(DiskName,
  1314. GENERIC_READ | GENERIC_WRITE,
  1315. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1316. NULL,
  1317. OPEN_EXISTING,
  1318. FILE_ATTRIBUTE_NORMAL,
  1319. NULL);
  1320. if ((DiskHandle) &&
  1321. (DiskHandle != INVALID_HANDLE_VALUE)) {
  1322. DWORD ReturnSize = 0;
  1323. ZeroMemory(Buffer, BufferSize);
  1324. if (DeviceIoControl(DiskHandle,
  1325. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  1326. NULL,
  1327. 0,
  1328. Buffer,
  1329. BufferSize,
  1330. &ReturnSize,
  1331. NULL)) {
  1332. //
  1333. // Only search in GPT disks on IA64
  1334. //
  1335. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  1336. DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)Buffer;
  1337. if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) {
  1338. ULONG PartitionIndex;
  1339. for (PartitionIndex = 0;
  1340. (PartitionIndex < DriveLayout->PartitionCount);
  1341. PartitionIndex++) {
  1342. PPARTITION_INFORMATION_EX Partition;
  1343. GUID *PartitionType;
  1344. Partition = DriveLayout->PartitionEntry + PartitionIndex;
  1345. PartitionType = &(Partition->Gpt.PartitionType);
  1346. if (IsEqualGUID(PartitionType, &PARTITION_SYSTEM_GUID)) {
  1347. swprintf(SystemPartitionName,
  1348. L"\\Device\\Harddisk%d\\Partition%d",
  1349. CurrentDisk,
  1350. Partition->PartitionNumber
  1351. );
  1352. Found = TRUE;
  1353. break;
  1354. }
  1355. }
  1356. }
  1357. }
  1358. CloseHandle(DiskHandle);
  1359. }
  1360. }
  1361. FREE(Buffer);
  1362. } else {
  1363. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  1364. }
  1365. if (!Found) {
  1366. ErrorCode = ERROR_FILE_NOT_FOUND;
  1367. } else {
  1368. ErrorCode = ERROR_SUCCESS;
  1369. }
  1370. }
  1371. }
  1372. return ErrorCode;
  1373. }
  1374. DWORD
  1375. InitializeEfiStuff(
  1376. IN HWND Parent
  1377. )
  1378. {
  1379. DWORD ec;
  1380. NTSTATUS status;
  1381. HMODULE h;
  1382. WCHAR dllName[MAX_PATH];
  1383. ULONG length;
  1384. HKEY key;
  1385. DWORD type;
  1386. LONG i;
  1387. PMY_BOOT_ENTRY bootEntry;
  1388. PMY_BOOT_ENTRY previousBootEntry;
  1389. MYASSERT(!IsEfiChecked);
  1390. //
  1391. // IsEfi() uses IsEfiMachine to determine its return value. Assume that
  1392. // we're not on an EFI machine.
  1393. //
  1394. IsEfiChecked = TRUE;
  1395. IsEfiMachine = FALSE;
  1396. //
  1397. // Enable the privilege that is necessary to query/set NVRAM.
  1398. //
  1399. if(!EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE)) {
  1400. ec = GetLastError();
  1401. return ec;
  1402. }
  1403. //
  1404. // Load ntdll.dll from the system directory.
  1405. //
  1406. GetSystemDirectory(dllName, MAX_PATH);
  1407. ConcatenatePaths(dllName, TEXT("ntdll.dll"), MAX_PATH);
  1408. h = LoadLibrary(dllName);
  1409. if (h == NULL) {
  1410. ec = GetLastError();
  1411. return ec;
  1412. }
  1413. //
  1414. // Get the addresses of the NVRAM APIs that we need to use. If any of
  1415. // these APIs are not available, this must be a pre-EFI NVRAM build.
  1416. //
  1417. (FARPROC)AddBootEntry = GetProcAddress(h, "NtAddBootEntry");
  1418. (FARPROC)DeleteBootEntry = GetProcAddress(h, "NtDeleteBootEntry");
  1419. (FARPROC)EnumerateBootEntries = GetProcAddress(h, "NtEnumerateBootEntries");
  1420. (FARPROC)QueryBootEntryOrder = GetProcAddress(h, "NtQueryBootEntryOrder");
  1421. (FARPROC)SetBootEntryOrder = GetProcAddress(h, "NtSetBootEntryOrder");
  1422. (FARPROC)QueryBootOptions = GetProcAddress(h, "NtQueryBootOptions");
  1423. (FARPROC)SetBootOptions = GetProcAddress(h, "NtSetBootOptions");
  1424. if ((AddBootEntry == NULL) ||
  1425. (DeleteBootEntry == NULL) ||
  1426. (EnumerateBootEntries == NULL) ||
  1427. (QueryBootEntryOrder == NULL) ||
  1428. (SetBootEntryOrder == NULL) ||
  1429. (QueryBootOptions == NULL) ||
  1430. (SetBootOptions == NULL)) {
  1431. return ERROR_OLD_WIN_VERSION;
  1432. }
  1433. //
  1434. // Get the global system boot options. If the call fails with
  1435. // STATUS_NOT_IMPLEMENTED, this is not an EFI machine.
  1436. //
  1437. length = 0;
  1438. status = QueryBootOptions(NULL, &length);
  1439. if (status != STATUS_NOT_IMPLEMENTED) {
  1440. IsEfiMachine = TRUE;
  1441. }
  1442. if (status != STATUS_BUFFER_TOO_SMALL) {
  1443. if (status == STATUS_SUCCESS) {
  1444. status = STATUS_UNSUCCESSFUL;
  1445. }
  1446. return RtlNtStatusToDosError(status);
  1447. }
  1448. BootOptions = MALLOC(length);
  1449. OriginalBootOptions = MALLOC(length);
  1450. if ((BootOptions == NULL) || (OriginalBootOptions == NULL)) {
  1451. return RtlNtStatusToDosError(ERROR_NOT_ENOUGH_MEMORY);
  1452. }
  1453. status = QueryBootOptions(BootOptions, &length);
  1454. if (status != STATUS_SUCCESS) {
  1455. FREE(BootOptions);
  1456. FREE(OriginalBootOptions);
  1457. BootOptions = NULL;
  1458. OriginalBootOptions = NULL;
  1459. return RtlNtStatusToDosError(status);
  1460. }
  1461. memcpy(OriginalBootOptions, BootOptions, length);
  1462. //
  1463. // Get the system boot order list.
  1464. //
  1465. length = 0;
  1466. status = QueryBootEntryOrder(NULL, &length);
  1467. if (status != STATUS_BUFFER_TOO_SMALL) {
  1468. if (status == STATUS_SUCCESS) {
  1469. status = STATUS_UNSUCCESSFUL;
  1470. }
  1471. return RtlNtStatusToDosError(status);
  1472. }
  1473. OriginalBootEntryOrder = MALLOC(length * sizeof(ULONG));
  1474. if (OriginalBootEntryOrder == NULL) {
  1475. return ERROR_NOT_ENOUGH_MEMORY;
  1476. }
  1477. status = QueryBootEntryOrder(OriginalBootEntryOrder, &length);
  1478. if (status != STATUS_SUCCESS) {
  1479. FREE(OriginalBootEntryOrder);
  1480. OriginalBootEntryOrder = NULL;
  1481. return RtlNtStatusToDosError(status);
  1482. }
  1483. OriginalBootEntryOrderCount = length;
  1484. //
  1485. // Get all existing boot entries.
  1486. //
  1487. length = 0;
  1488. status = EnumerateBootEntries(NULL, &length);
  1489. if (status != STATUS_BUFFER_TOO_SMALL) {
  1490. if (status == STATUS_SUCCESS) {
  1491. status = STATUS_UNSUCCESSFUL;
  1492. }
  1493. return RtlNtStatusToDosError(status);
  1494. }
  1495. BootEntries = MALLOC(length);
  1496. if (BootEntries == NULL) {
  1497. return ERROR_NOT_ENOUGH_MEMORY;
  1498. }
  1499. status = EnumerateBootEntries(BootEntries, &length);
  1500. if (status != STATUS_SUCCESS) {
  1501. FREE(BootEntries);
  1502. BootEntries = NULL;
  1503. return RtlNtStatusToDosError(status);
  1504. }
  1505. //
  1506. // Initialize drive name translations, which are needed for converting
  1507. // the boot entries into their internal representations.
  1508. //
  1509. ec = InitDriveNameTranslations();
  1510. if(ec != NO_ERROR) {
  1511. return ec;
  1512. }
  1513. //
  1514. // Convert the boot entries into an internal representation.
  1515. //
  1516. status = ConvertBootEntries();
  1517. if (!NT_SUCCESS(status)) {
  1518. return RtlNtStatusToDosError(status);
  1519. }
  1520. //
  1521. // Free the enumeration buffer.
  1522. //
  1523. FREE(BootEntries);
  1524. BootEntries = NULL;
  1525. //
  1526. // Boot entries are returned in an unspecified order. They are currently
  1527. // in the MyBootEntries list in the order in which they were returned.
  1528. // Sort the boot entry list based on the boot order. Do this by walking
  1529. // the boot order array backwards, reinserting the entry corresponding to
  1530. // each element of the array at the head of the list.
  1531. //
  1532. for (i = (LONG)OriginalBootEntryOrderCount - 1; i >= 0; i--) {
  1533. for (previousBootEntry = NULL, bootEntry = MyBootEntries;
  1534. bootEntry != NULL;
  1535. previousBootEntry = bootEntry, bootEntry = bootEntry->Next) {
  1536. if (bootEntry->NtBootEntry.Id == OriginalBootEntryOrder[i] ) {
  1537. //
  1538. // We found the boot entry with this ID. If it's not already
  1539. // at the front of the list, move it there.
  1540. //
  1541. bootEntry->Status |= MBE_STATUS_ORDERED;
  1542. if (previousBootEntry != NULL) {
  1543. previousBootEntry->Next = bootEntry->Next;
  1544. bootEntry->Next = MyBootEntries;
  1545. MyBootEntries = bootEntry;
  1546. } else {
  1547. ASSERT(MyBootEntries == bootEntry);
  1548. }
  1549. break;
  1550. }
  1551. }
  1552. }
  1553. //
  1554. // Get the NT name of the system partition from the registry.
  1555. //
  1556. ec = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), &key);
  1557. if (ec == ERROR_SUCCESS) {
  1558. ec = RegQueryValueEx(key, TEXT("SystemPartition"), NULL, &type, NULL, &length);
  1559. if (ec == ERROR_SUCCESS) {
  1560. if (type == REG_SZ) {
  1561. SystemPartitionNtName = MALLOC(length);
  1562. if (SystemPartitionNtName != NULL) {
  1563. ec = RegQueryValueEx(
  1564. key,
  1565. TEXT("SystemPartition"),
  1566. NULL,
  1567. &type,
  1568. (PBYTE)SystemPartitionNtName,
  1569. &length);
  1570. if (ec != ERROR_SUCCESS) {
  1571. FREE(SystemPartitionNtName);
  1572. }
  1573. } else {
  1574. return ERROR_NOT_ENOUGH_MEMORY;
  1575. }
  1576. } else {
  1577. return ERROR_INVALID_PARAMETER;
  1578. }
  1579. }
  1580. RegCloseKey (key);
  1581. }
  1582. if (ec != NO_ERROR) {
  1583. if (IsWinPEMode()) {
  1584. WCHAR OldSysPartName[MAX_PATH] = {0};
  1585. WCHAR NewSysPartName[MAX_PATH] = {0};
  1586. ec = LocateEfiSystemPartition(OldSysPartName);
  1587. if ((ec == NO_ERROR) && OldSysPartName[0]) {
  1588. NTSTATUS Status = QueryCanonicalName(OldSysPartName,
  1589. -1,
  1590. NewSysPartName,
  1591. sizeof(NewSysPartName));
  1592. if (NT_SUCCESS(Status) && NewSysPartName[0]) {
  1593. SystemPartitionNtName = DupString(NewSysPartName);
  1594. } else {
  1595. ec = ERROR_FILE_NOT_FOUND;
  1596. }
  1597. }
  1598. if ((ec == NO_ERROR) && (NewSysPartName[0] == UNICODE_NULL)) {
  1599. ec = ERROR_FILE_NOT_FOUND;
  1600. }
  1601. }
  1602. if (ec != NO_ERROR) {
  1603. return ec;
  1604. }
  1605. }
  1606. //
  1607. // Get the volume name for the NT name.
  1608. //
  1609. length = sizeof(GLOBAL_ROOT) +
  1610. lstrlen(SystemPartitionNtName)*sizeof(WCHAR) +
  1611. sizeof(WCHAR) + sizeof(WCHAR);
  1612. SystemPartitionVolumeGuid = MALLOC (length);
  1613. if(!SystemPartitionVolumeGuid) {
  1614. return ERROR_NOT_ENOUGH_MEMORY;
  1615. }
  1616. //
  1617. // These string operations are safe, since the buffer is preallocated
  1618. //
  1619. lstrcpy (SystemPartitionVolumeGuid, GLOBAL_ROOT);
  1620. lstrcat (SystemPartitionVolumeGuid, SystemPartitionNtName);
  1621. lstrcat (SystemPartitionVolumeGuid, L"\\");
  1622. //
  1623. // But strlen of SystemPartitionVolumeGuid may exceed MAX_PATH, so we
  1624. // do a safe string copy here
  1625. //
  1626. if (FAILED(StringCchCopy(LocalBootDirectory,
  1627. ARRAYSIZE(LocalBootDirectory),
  1628. SystemPartitionVolumeGuid)))
  1629. {
  1630. return ERROR_BUFFER_OVERFLOW;
  1631. }
  1632. return NO_ERROR;
  1633. } // InitializeEfiStuff
  1634. #endif // defined(EFI_NVRAM_ENABLED)
  1635. /////////////////////////////////////////////////////////////////////
  1636. //
  1637. // Everything above this line is concerned with reading NV-RAM.
  1638. // Everything below this line is concerned with setting NV-RAM.
  1639. //
  1640. /////////////////////////////////////////////////////////////////////
  1641. BOOL
  1642. DoSetNvRamVar(
  1643. IN LPCWSTR VarName,
  1644. IN LPCWSTR VarValue
  1645. )
  1646. {
  1647. UNICODE_STRING U1,U2;
  1648. RtlInitUnicodeString(&U1,VarName);
  1649. RtlInitUnicodeString(&U2,VarValue);
  1650. return(NT_SUCCESS(NtSetSystemEnvironmentValue(&U1,&U2)));
  1651. }
  1652. BOOL
  1653. WriteNewBootSetVar(
  1654. IN DWORD var,
  1655. IN PTSTR NewPart
  1656. )
  1657. {
  1658. WCHAR Buffer[2048];
  1659. DWORD i;
  1660. //
  1661. // Write the new part first.
  1662. //
  1663. if (FAILED(StringCchCopy(Buffer, ARRAYSIZE(Buffer), NewPart))) {
  1664. return FALSE;
  1665. }
  1666. //
  1667. // Append all components that were not deleted.
  1668. //
  1669. for(i=0; i<BootVarComponentCount[var]; i++) {
  1670. if(BootVarComponents[var][i]) {
  1671. if (FAILED(StringCchCat(Buffer, ARRAYSIZE(Buffer), L";"))) {
  1672. return FALSE;
  1673. }
  1674. if (FAILED(StringCchCat(Buffer, ARRAYSIZE(Buffer), BootVarComponents[var][i]))) {
  1675. return FALSE;
  1676. }
  1677. }
  1678. }
  1679. //
  1680. // Remember new value for this var.
  1681. //
  1682. if(BootVarValues[var]) {
  1683. FREE(BootVarValues[var]);
  1684. }
  1685. BootVarValues[var] = DupString(Buffer);
  1686. if (!BootVarValues[var])
  1687. return FALSE;
  1688. //
  1689. // Write the var into nvram and return.
  1690. //
  1691. return(DoSetNvRamVar(BootVarNames[var],BootVarValues[var]));
  1692. }
  1693. BOOL
  1694. WriteBootSet(
  1695. VOID
  1696. )
  1697. {
  1698. DWORD set;
  1699. DWORD var;
  1700. LPWSTR SystemPartition;
  1701. WCHAR Buffer[2048];
  1702. LPWSTR LocalSourceArc;
  1703. LPWSTR OsLoader;
  1704. WCHAR LoadId[128];
  1705. BOOL b;
  1706. CleanUpNvRam = TRUE;
  1707. //
  1708. // Find and remove any remnants of previously attempted
  1709. // winnt32 runs. Such runs are identified by 'winnt32'
  1710. // in their osloadoptions.
  1711. //
  1712. #if defined(EFI_NVRAM_ENABLED)
  1713. if (IsEfi()) {
  1714. NTSTATUS status;
  1715. PMY_BOOT_ENTRY bootEntry;
  1716. PWSTR NtPath;
  1717. //
  1718. // EFI machine. Walk the boot entry list.
  1719. //
  1720. for (bootEntry = MyBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1721. if (IS_BOOT_ENTRY_WINDOWS(bootEntry)) {
  1722. if (!lstrcmpi(bootEntry->OsLoadOptions, L"WINNT32")) {
  1723. //
  1724. // Delete this boot entry. Note that we don't update the
  1725. // boot entry order list at this point. CreateBootEntry()
  1726. // will do that.
  1727. //
  1728. status = DeleteBootEntry(bootEntry->NtBootEntry.Id);
  1729. bootEntry->Status |= MBE_STATUS_DELETED;
  1730. }
  1731. }
  1732. }
  1733. //
  1734. // Now create a new boot entry for textmode setup.
  1735. //
  1736. MYASSERT(LocalSourceDrive);
  1737. NtPath = DosDeviceTargets[(WCHAR)CharUpper((PWCHAR)LocalSourceDrive)-L'A'];
  1738. LoadString(hInst,IDS_RISCBootString,LoadId,sizeof(LoadId)/sizeof(TCHAR));
  1739. b = CreateBootEntry(
  1740. SystemPartitionNtName,
  1741. L"\\" SETUPLDR_FILENAME,
  1742. NtPath,
  1743. LocalSourceWithPlatform + 2,
  1744. L"WINNT32",
  1745. LoadId
  1746. );
  1747. if (b) {
  1748. //
  1749. // Set up for automatic startup, 10 second countdown. We don't
  1750. // care if this fails.
  1751. //
  1752. // Set the boot entry we added to be booted automatically on
  1753. // the next boot, without waiting for a timeout at the boot menu.
  1754. //
  1755. // NB: CreateBootEntry() sets BootOptions->NextBootEntryId.
  1756. //
  1757. BootOptions->Timeout = 10;
  1758. status = SetBootOptions(
  1759. BootOptions,
  1760. BOOT_OPTIONS_FIELD_TIMEOUT | BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID
  1761. );
  1762. }
  1763. return b;
  1764. }
  1765. #endif // defined(EFI_NVRAM_ENABLED)
  1766. //
  1767. // We get here if we're NOT on an EFI machine.
  1768. //
  1769. // Find and remove any remnants of previously attempted
  1770. // winnt32 runs. Such runs are identified by 'winnt32'
  1771. // in their osloadoptions.
  1772. //
  1773. for(set=0; set<min(LargestComponentCount,BootVarComponentCount[BootVarOsLoadOptions]); set++) {
  1774. //
  1775. // See if the os load options indicate that this is a winnt32 set.
  1776. //
  1777. if(!lstrcmpi(BootVarComponents[BootVarOsLoadOptions][set],L"WINNT32")) {
  1778. //
  1779. // Delete this boot set.
  1780. //
  1781. for(var=0; var<BootVarMax; var++) {
  1782. if(set < BootVarComponentCount[var]) {
  1783. FREE(BootVarComponents[var][set]);
  1784. BootVarComponents[var][set] = NULL;
  1785. }
  1786. }
  1787. }
  1788. }
  1789. //
  1790. // Now we want to write out each variable with the appropriate
  1791. // part of the new boot set added to the front.
  1792. //
  1793. if (SystemPartitionDriveLetter) {
  1794. if(DriveLetterToArcPath(SystemPartitionDriveLetter,&SystemPartition) != NO_ERROR) {
  1795. return(FALSE);
  1796. }
  1797. } else {
  1798. if(NtNameToArcPath (SystemPartitionNtName, &SystemPartition) != NO_ERROR) {
  1799. return(FALSE);
  1800. }
  1801. }
  1802. MYASSERT (LocalSourceDrive);
  1803. if(DriveLetterToArcPath(LocalSourceDrive,&LocalSourceArc) != NO_ERROR) {
  1804. FREE(SystemPartition);
  1805. return(FALSE);
  1806. }
  1807. LoadString(hInst,IDS_RISCBootString,LoadId,sizeof(LoadId)/sizeof(TCHAR));
  1808. if (FAILED(StringCchCopy(Buffer, ARRAYSIZE(Buffer), SystemPartition))) {
  1809. FREE(SystemPartition);
  1810. FREE(LocalSourceArc);
  1811. return (FALSE);
  1812. }
  1813. if (FAILED(StringCchCat(Buffer, ARRAYSIZE(Buffer), L"\\" SETUPLDR_FILENAME))) {
  1814. FREE(SystemPartition);
  1815. FREE(LocalSourceArc);
  1816. return (FALSE);
  1817. }
  1818. OsLoader = DupString(Buffer);
  1819. if (!OsLoader) {
  1820. FREE(SystemPartition);
  1821. FREE(LocalSourceArc);
  1822. return (FALSE);
  1823. }
  1824. //
  1825. // System partition: use the selected system partition as the
  1826. // new system partition component.
  1827. //
  1828. if(WriteNewBootSetVar(BootVarSystemPartition,SystemPartition)
  1829. //
  1830. // Os Loader: use the system partition + setupldr as the
  1831. // new os loader component.
  1832. //
  1833. && WriteNewBootSetVar(BootVarOsLoader,OsLoader)
  1834. //
  1835. // Os Load Partition: use the local source drive as the
  1836. // new os load partition component.
  1837. //
  1838. && WriteNewBootSetVar(BootVarOsLoadPartition,LocalSourceArc)
  1839. //
  1840. // Os Load Filename: use the platform-specific local source directory
  1841. // as the new os load filename component (do not include the drive letter).
  1842. //
  1843. && WriteNewBootSetVar(BootVarOsLoadFilename,LocalSourceWithPlatform+2)
  1844. //
  1845. // Os Load Options: use WINNT32 as the new os load options component.
  1846. //
  1847. && WriteNewBootSetVar(BootVarOsLoadOptions,L"WINNT32")
  1848. //
  1849. // Load Identifier: use a string we get from the resources as the
  1850. // new load identifier component.
  1851. //
  1852. && WriteNewBootSetVar(BootVarLoadIdentifier,LoadId))
  1853. {
  1854. //
  1855. // Set up for automatic startup, 10 second countdown.
  1856. // Note the order so that if setting countdown fails we don't
  1857. // set of for autoload. Also note that we don't really care
  1858. // if this fails.
  1859. //
  1860. if(DoSetNvRamVar(szCOUNTDOWN,L"10")) {
  1861. DoSetNvRamVar(szAUTOLOAD,L"YES");
  1862. }
  1863. b = TRUE;
  1864. } else {
  1865. //
  1866. // Setting nv-ram failed. Code in cleanup.c will come along and
  1867. // restore to original state later.
  1868. //
  1869. b = FALSE;
  1870. }
  1871. FREE(SystemPartition);
  1872. FREE(LocalSourceArc);
  1873. FREE(OsLoader);
  1874. return(b);
  1875. }
  1876. BOOL
  1877. SetUpNvRam(
  1878. IN HWND ParentWindow
  1879. )
  1880. {
  1881. if(!WriteBootSet()) {
  1882. MessageBoxFromMessage(
  1883. ParentWindow,
  1884. MSG_COULDNT_WRITE_NVRAM,
  1885. FALSE,
  1886. AppTitleStringId,
  1887. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1888. );
  1889. return(FALSE);
  1890. }
  1891. return(TRUE);
  1892. }
  1893. BOOL
  1894. RestoreNvRam(
  1895. VOID
  1896. )
  1897. {
  1898. UINT var;
  1899. BOOL b;
  1900. b = TRUE;
  1901. if(CleanUpNvRam) {
  1902. #if defined(EFI_NVRAM_ENABLED)
  1903. if (IsEfi()) {
  1904. NTSTATUS status;
  1905. PMY_BOOT_ENTRY bootEntry;
  1906. //
  1907. // EFI machine. Walk the boot entry list. For any boot entry that
  1908. // was added, delete it.
  1909. //
  1910. for (bootEntry = MyBootEntries; bootEntry != NULL; bootEntry = bootEntry->Next) {
  1911. if (IS_BOOT_ENTRY_COMMITTED(bootEntry)) {
  1912. MYASSERT(IS_BOOT_ENTRY_NEW(bootEntry));
  1913. status = DeleteBootEntry(bootEntry->NtBootEntry.Id);
  1914. if (!NT_SUCCESS(status)) {
  1915. b = FALSE;
  1916. }
  1917. }
  1918. }
  1919. //
  1920. // Restore the original boot order list and the original timeout.
  1921. //
  1922. status = SetBootEntryOrder(OriginalBootEntryOrder, OriginalBootEntryOrderCount);
  1923. if (!NT_SUCCESS(status)) {
  1924. b = FALSE;
  1925. }
  1926. status = SetBootOptions(OriginalBootOptions, BOOT_OPTIONS_FIELD_TIMEOUT);
  1927. if (!NT_SUCCESS(status)) {
  1928. b = FALSE;
  1929. }
  1930. }
  1931. } else {
  1932. #endif // defined(EFI_NVRAM_ENABLED)
  1933. for(var=0; var<BootVarMax; var++) {
  1934. if(!DoSetNvRamVar(BootVarNames[var],OriginalBootVarValues[var])) {
  1935. b = FALSE;
  1936. }
  1937. }
  1938. if(OriginalAutoload) {
  1939. if(!DoSetNvRamVar(szAUTOLOAD,OriginalAutoload)) {
  1940. b = FALSE;
  1941. }
  1942. }
  1943. if(OriginalCountdown) {
  1944. if(!DoSetNvRamVar(szCOUNTDOWN,OriginalCountdown)) {
  1945. b = FALSE;
  1946. }
  1947. }
  1948. }
  1949. return(b);
  1950. }
  1951. VOID
  1952. MigrateBootVarData(
  1953. VOID
  1954. )
  1955. /*++
  1956. Routine Description:
  1957. This routine retreives any boot data we want to migrate into a global
  1958. variable so that it can be written into winnt.sif.
  1959. Currently we only retreive the countdown
  1960. Arguments:
  1961. None
  1962. Return Value:
  1963. None. updates the Timeout global variable
  1964. --*/
  1965. {
  1966. UNICODE_STRING UnicodeString;
  1967. NTSTATUS Status;
  1968. WCHAR Buffer[4096];
  1969. MYASSERT(IsArc());
  1970. //
  1971. // If this is an EFI machine, use the cached BootOptions to get the timeout.
  1972. // (See IsEfi().) Otherwise, use the old version of the system service to
  1973. // query the "COUNTDOWN" variable.
  1974. //
  1975. #if defined(EFI_NVRAM_ENABLED)
  1976. if (IsEfi()) {
  1977. MYASSERT(BootOptions != NULL);
  1978. swprintf( Timeout, L"%d", BootOptions->Timeout );
  1979. } else
  1980. #endif // defined(EFI_NVRAM_ENABLED)
  1981. {
  1982. RtlInitUnicodeString(&UnicodeString,szCOUNTDOWN);
  1983. Status = NtQuerySystemEnvironmentValue(
  1984. &UnicodeString,
  1985. Buffer,
  1986. sizeof(Buffer) / sizeof(WCHAR),
  1987. NULL
  1988. );
  1989. if(NT_SUCCESS(Status)) {
  1990. //
  1991. // Global Timeout buffer is only 32 TCHARs, so use safe string copy!
  1992. //
  1993. StringCchCopy(Timeout, ARRAYSIZE(Timeout), Buffer);
  1994. }
  1995. }
  1996. }
  1997. #if defined(_X86_)
  1998. BOOL
  1999. IsArc(
  2000. VOID
  2001. )
  2002. /*++
  2003. Routine Description:
  2004. Run time check to determine if this is an Arc system. We attempt to read an
  2005. Arc variable using the Hal. This will fail for Bios based systems.
  2006. Arguments:
  2007. None
  2008. Return Value:
  2009. True = This is an Arc system.
  2010. --*/
  2011. {
  2012. UNICODE_STRING UnicodeString;
  2013. NTSTATUS Status;
  2014. WCHAR Buffer[4096];
  2015. //
  2016. // If we've already done the check once, don't bother doing it again.
  2017. //
  2018. if (IsArcChecked) {
  2019. return IsArcMachine;
  2020. }
  2021. IsArcChecked = TRUE;
  2022. IsArcMachine = FALSE;
  2023. if(!EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE)) {
  2024. return FALSE; // need better error handling?
  2025. }
  2026. //
  2027. // Get the env var into the temp buffer.
  2028. //
  2029. RtlInitUnicodeString(&UnicodeString,BootVarNames[BootVarOsLoader]);
  2030. Status = NtQuerySystemEnvironmentValue(
  2031. &UnicodeString,
  2032. Buffer,
  2033. sizeof(Buffer)/sizeof(WCHAR),
  2034. NULL
  2035. );
  2036. if (NT_SUCCESS(Status)) {
  2037. IsArcMachine = TRUE;
  2038. }
  2039. return IsArcMachine;
  2040. }
  2041. #endif // defined(_X86_)
  2042. #if defined(EFI_NVRAM_ENABLED)
  2043. BOOL
  2044. IsEfi(
  2045. VOID
  2046. )
  2047. /*++
  2048. Routine Description:
  2049. Run time check to determine if this is an EFI system.
  2050. Arguments:
  2051. None
  2052. Return Value:
  2053. True = This is an EFI system.
  2054. --*/
  2055. {
  2056. //
  2057. // InitializeEfiStuff() must be called first to do the actual check.
  2058. //
  2059. MYASSERT(IsEfiChecked);
  2060. return IsEfiMachine;
  2061. } // IsEfi
  2062. NTSTATUS
  2063. ConvertBootEntries(
  2064. VOID
  2065. )
  2066. /*++
  2067. Routine Description:
  2068. Convert boot entries read from EFI NVRAM into our internal format.
  2069. Arguments:
  2070. None.
  2071. Return Value:
  2072. NTSTATUS - Not STATUS_SUCCESS if an unexpected error occurred.
  2073. --*/
  2074. {
  2075. PBOOT_ENTRY_LIST bootEntryList;
  2076. PBOOT_ENTRY bootEntry;
  2077. PBOOT_ENTRY bootEntryCopy;
  2078. PMY_BOOT_ENTRY myBootEntry;
  2079. PMY_BOOT_ENTRY previousEntry;
  2080. PWINDOWS_OS_OPTIONS osOptions;
  2081. ULONG length;
  2082. bootEntryList = BootEntries;
  2083. previousEntry = NULL;
  2084. while (TRUE) {
  2085. bootEntry = &bootEntryList->BootEntry;
  2086. //
  2087. // Calculate the length of our internal structure. This includes
  2088. // the base part of MY_BOOT_ENTRY plus the NT BOOT_ENTRY.
  2089. //
  2090. length = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry) + bootEntry->Length;
  2091. myBootEntry = MALLOC(length);
  2092. if (myBootEntry == NULL) {
  2093. return STATUS_INSUFFICIENT_RESOURCES;
  2094. }
  2095. RtlZeroMemory(myBootEntry, length);
  2096. //
  2097. // Link the new entry into the list.
  2098. //
  2099. if (previousEntry != NULL) {
  2100. previousEntry->Next = myBootEntry;
  2101. } else {
  2102. MyBootEntries = myBootEntry;
  2103. }
  2104. previousEntry = myBootEntry;
  2105. //
  2106. // Copy the NT BOOT_ENTRY into the allocated buffer.
  2107. //
  2108. bootEntryCopy = &myBootEntry->NtBootEntry;
  2109. //
  2110. // work around till bootentry has the correct length specified
  2111. //
  2112. __try {
  2113. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2114. }
  2115. __except(EXCEPTION_EXECUTE_HANDLER) {
  2116. if (bootEntry->Length > sizeof(ULONG)) {
  2117. bootEntry->Length -= sizeof(ULONG);
  2118. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2119. } else {
  2120. //
  2121. // Lets atleast AV rather than having invalid
  2122. // in memory data structures
  2123. //
  2124. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  2125. }
  2126. }
  2127. //
  2128. // Fill in the base part of the structure.
  2129. //
  2130. myBootEntry->Next = NULL;
  2131. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + length - 1;
  2132. myBootEntry->FriendlyName = ADD_OFFSET(bootEntryCopy, FriendlyNameOffset);
  2133. myBootEntry->FriendlyNameLength = (wcslen(myBootEntry->FriendlyName) + 1) * sizeof(WCHAR);
  2134. myBootEntry->BootFilePath = ADD_OFFSET(bootEntryCopy, BootFilePathOffset);
  2135. //
  2136. // If this is an NT boot entry, capture the NT-specific information in
  2137. // the OsOptions.
  2138. //
  2139. osOptions = (PWINDOWS_OS_OPTIONS)bootEntryCopy->OsOptions;
  2140. if (!IS_BOOT_ENTRY_WINDOWS(myBootEntry)) {
  2141. //
  2142. // The original implementation of NtEnumerateBootEntries() didn't
  2143. // set BOOT_ENTRY_ATTRIBUTE_WINDOWS, so we need to check for that
  2144. // here.
  2145. //
  2146. if ((bootEntryCopy->OsOptionsLength >= FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) &&
  2147. (strcmp(osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) == 0)) {
  2148. myBootEntry->NtBootEntry.Attributes |= BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  2149. }
  2150. }
  2151. if (IS_BOOT_ENTRY_WINDOWS(myBootEntry)) {
  2152. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  2153. myBootEntry->OsLoadOptionsLength = (wcslen(myBootEntry->OsLoadOptions) + 1) * sizeof(WCHAR);
  2154. myBootEntry->OsFilePath = ADD_OFFSET(osOptions, OsLoadPathOffset);
  2155. } else {
  2156. //
  2157. // It's not an NT entry. Check to see if it represents a removable
  2158. // media device. We want to know this so that we don't put our
  2159. // boot entry ahead of the floppy or the CD, if they're already
  2160. // at the front of the list. A boot entry represents a
  2161. }
  2162. //
  2163. // Move to the next entry in the enumeration list, if any.
  2164. //
  2165. if (bootEntryList->NextEntryOffset == 0) {
  2166. break;
  2167. }
  2168. bootEntryList = ADD_OFFSET(bootEntryList, NextEntryOffset);
  2169. }
  2170. return STATUS_SUCCESS;
  2171. } // ConvertBootEntries
  2172. BOOL
  2173. CreateBootEntry(
  2174. PWSTR BootFileDevice,
  2175. PWSTR BootFilePath,
  2176. PWSTR OsLoadDevice,
  2177. PWSTR OsLoadPath,
  2178. PWSTR OsLoadOptions,
  2179. PWSTR FriendlyName
  2180. )
  2181. /*++
  2182. Routine Description:
  2183. Create an internal-format boot entry.
  2184. Arguments:
  2185. BootFileDevice - The NT name of the device on which the OS loader resides.
  2186. BootFilePath - The volume-relative path to the OS loader. Must start with
  2187. a backslash.
  2188. OsLoadDevice - The NT name ofthe device on which the OS resides.
  2189. OsLoadPath - The volume-relative path to the OS root directory (\WINDOWS).
  2190. Must start with a backslash.
  2191. OsLoadOptions - Boot options for the OS. Can be an empty string.
  2192. FriendlyName - The user-visible name for the boot entry. (This is ARC's
  2193. LOADIDENTIFIER.)
  2194. Return Value:
  2195. BOOLEAN - FALSE if an unexpected error occurred.
  2196. --*/
  2197. {
  2198. NTSTATUS status;
  2199. ULONG requiredLength;
  2200. ULONG osOptionsOffset;
  2201. ULONG osLoadOptionsLength;
  2202. ULONG osLoadPathOffset;
  2203. ULONG osLoadPathLength;
  2204. ULONG osOptionsLength;
  2205. ULONG friendlyNameOffset;
  2206. ULONG friendlyNameLength;
  2207. ULONG bootPathOffset;
  2208. ULONG bootPathLength;
  2209. PMY_BOOT_ENTRY myBootEntry;
  2210. PMY_BOOT_ENTRY previousBootEntry;
  2211. PMY_BOOT_ENTRY nextBootEntry;
  2212. PBOOT_ENTRY ntBootEntry;
  2213. PWINDOWS_OS_OPTIONS osOptions;
  2214. PFILE_PATH osLoadPath;
  2215. PWSTR friendlyName;
  2216. PFILE_PATH bootPath;
  2217. PWSTR p;
  2218. PULONG order;
  2219. ULONG count;
  2220. ULONG savedAttributes;
  2221. //
  2222. // Calculate how long the internal boot entry needs to be. This includes
  2223. // our internal structure, plus the BOOT_ENTRY structure that the NT APIs
  2224. // use.
  2225. //
  2226. // Our structure:
  2227. //
  2228. requiredLength = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  2229. //
  2230. // Base part of NT structure:
  2231. //
  2232. requiredLength += FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  2233. //
  2234. // Save offset to BOOT_ENTRY.OsOptions. Add in base part of
  2235. // WINDOWS_OS_OPTIONS. Calculate length in bytes of OsLoadOptions
  2236. // and add that in.
  2237. //
  2238. osOptionsOffset = requiredLength;
  2239. requiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  2240. osLoadOptionsLength = (wcslen(OsLoadOptions) + 1) * sizeof(WCHAR);
  2241. requiredLength += osLoadOptionsLength;
  2242. //
  2243. // Round up to a ULONG boundary for the OS FILE_PATH in the
  2244. // WINDOWS_OS_OPTIONS. Save offset to OS FILE_PATH. Add in base part
  2245. // of FILE_PATH. Add in length in bytes of OS device NT name and OS
  2246. // directory. Calculate total length of OS FILE_PATH and of
  2247. // WINDOWS_OS_OPTIONS.
  2248. //
  2249. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2250. osLoadPathOffset = requiredLength;
  2251. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  2252. requiredLength += (wcslen(OsLoadDevice) + 1 + wcslen(OsLoadPath) + 1) * sizeof(WCHAR);
  2253. osLoadPathLength = requiredLength - osLoadPathOffset;
  2254. osOptionsLength = requiredLength - osOptionsOffset;
  2255. //
  2256. // Round up to a ULONG boundary for the friendly name in the BOOT_ENTRY.
  2257. // Save offset to friendly name. Calculate length in bytes of friendly name
  2258. // and add that in.
  2259. //
  2260. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2261. friendlyNameOffset = requiredLength;
  2262. friendlyNameLength = (wcslen(FriendlyName) + 1) * sizeof(WCHAR);
  2263. requiredLength += friendlyNameLength;
  2264. //
  2265. // Round up to a ULONG boundary for the boot FILE_PATH in the BOOT_ENTRY.
  2266. // Save offset to boot FILE_PATH. Add in base part of FILE_PATH. Add in
  2267. // length in bytes of boot device NT name and boot file. Calculate total
  2268. // length of boot FILE_PATH.
  2269. //
  2270. requiredLength = ALIGN_UP(requiredLength, ULONG);
  2271. bootPathOffset = requiredLength;
  2272. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  2273. requiredLength += (wcslen(BootFileDevice) + 1 + wcslen(BootFilePath) + 1) * sizeof(WCHAR);
  2274. bootPathLength = requiredLength - bootPathOffset;
  2275. //
  2276. // Allocate memory for the boot entry.
  2277. //
  2278. myBootEntry = MALLOC(requiredLength);
  2279. if (myBootEntry == NULL) {
  2280. return FALSE;
  2281. }
  2282. RtlZeroMemory(myBootEntry, requiredLength);
  2283. //
  2284. // Calculate addresses of various substructures using the saved offsets.
  2285. //
  2286. ntBootEntry = &myBootEntry->NtBootEntry;
  2287. osOptions = (PWINDOWS_OS_OPTIONS)ntBootEntry->OsOptions;
  2288. osLoadPath = (PFILE_PATH)((PUCHAR)myBootEntry + osLoadPathOffset);
  2289. friendlyName = (PWSTR)((PUCHAR)myBootEntry + friendlyNameOffset);
  2290. bootPath = (PFILE_PATH)((PUCHAR)myBootEntry + bootPathOffset);
  2291. //
  2292. // Fill in the internal-format structure.
  2293. //
  2294. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + requiredLength;
  2295. myBootEntry->Status = MBE_STATUS_NEW | MBE_STATUS_ORDERED;
  2296. myBootEntry->FriendlyName = friendlyName;
  2297. myBootEntry->FriendlyNameLength = friendlyNameLength;
  2298. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  2299. myBootEntry->OsLoadOptionsLength = osLoadOptionsLength;
  2300. myBootEntry->BootFilePath = bootPath;
  2301. myBootEntry->OsFilePath = osLoadPath;
  2302. //
  2303. // Fill in the base part of the NT boot entry.
  2304. //
  2305. ntBootEntry->Version = BOOT_ENTRY_VERSION;
  2306. ntBootEntry->Length = requiredLength - FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  2307. ntBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE | BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  2308. ntBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)friendlyName - (PUCHAR)ntBootEntry);
  2309. ntBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)bootPath - (PUCHAR)ntBootEntry);
  2310. ntBootEntry->OsOptionsLength = osOptionsLength;
  2311. //
  2312. // Fill in the base part of the WINDOWS_OS_OPTIONS, including the
  2313. // OsLoadOptions.
  2314. //
  2315. strcpy(osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  2316. osOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  2317. osOptions->Length = osOptionsLength;
  2318. osOptions->OsLoadPathOffset = (ULONG)((PUCHAR)osLoadPath - (PUCHAR)osOptions);
  2319. wcscpy(osOptions->OsLoadOptions, OsLoadOptions);
  2320. //
  2321. // Fill in the OS FILE_PATH.
  2322. //
  2323. osLoadPath->Version = FILE_PATH_VERSION;
  2324. osLoadPath->Length = osLoadPathLength;
  2325. osLoadPath->Type = FILE_PATH_TYPE_NT;
  2326. p = (PWSTR)osLoadPath->FilePath;
  2327. wcscpy(p, OsLoadDevice);
  2328. p += wcslen(p) + 1;
  2329. wcscpy(p, OsLoadPath);
  2330. //
  2331. // Copy the friendly name.
  2332. //
  2333. wcscpy(friendlyName, FriendlyName);
  2334. //
  2335. // Fill in the boot FILE_PATH.
  2336. //
  2337. bootPath->Version = FILE_PATH_VERSION;
  2338. bootPath->Length = bootPathLength;
  2339. bootPath->Type = FILE_PATH_TYPE_NT;
  2340. p = (PWSTR)bootPath->FilePath;
  2341. wcscpy(p, BootFileDevice);
  2342. p += wcslen(p) + 1;
  2343. wcscpy(p, BootFilePath);
  2344. //
  2345. // Add the new boot entry.
  2346. //
  2347. // NB: The original implementation of NtAddBootEntry didn't like it
  2348. // when attribute bits other than _ACTIVE and _DEFAULT were set, so
  2349. // we need to mask the other bits off here.
  2350. //
  2351. savedAttributes = ntBootEntry->Attributes;
  2352. ntBootEntry->Attributes &= (BOOT_ENTRY_ATTRIBUTE_DEFAULT | BOOT_ENTRY_ATTRIBUTE_ACTIVE);
  2353. status = AddBootEntry(ntBootEntry, &ntBootEntry->Id);
  2354. ntBootEntry->Attributes = savedAttributes;
  2355. if (!NT_SUCCESS(status)) {
  2356. FREE(myBootEntry);
  2357. return FALSE;
  2358. }
  2359. myBootEntry->Status |= MBE_STATUS_COMMITTED;
  2360. //
  2361. // Remember the ID of the new boot entry as the entry to be booted
  2362. // immediately on the next boot.
  2363. //
  2364. BootOptions->NextBootEntryId = ntBootEntry->Id;
  2365. //
  2366. // Link the new boot entry into the list, after any removable media
  2367. // entries that are at the front of the list.
  2368. //
  2369. previousBootEntry = NULL;
  2370. nextBootEntry = MyBootEntries;
  2371. while ((nextBootEntry != NULL) &&
  2372. IS_BOOT_ENTRY_REMOVABLE_MEDIA(nextBootEntry)) {
  2373. previousBootEntry = nextBootEntry;
  2374. nextBootEntry = nextBootEntry->Next;
  2375. }
  2376. myBootEntry->Next = nextBootEntry;
  2377. if (previousBootEntry == NULL) {
  2378. MyBootEntries = myBootEntry;
  2379. } else {
  2380. previousBootEntry->Next = myBootEntry;
  2381. }
  2382. //
  2383. // Build the new boot order list. Insert all boot entries with
  2384. // MBE_STATUS_ORDERED into the list. (Don't insert deleted entries.)
  2385. //
  2386. count = 0;
  2387. nextBootEntry = MyBootEntries;
  2388. while (nextBootEntry != NULL) {
  2389. if (IS_BOOT_ENTRY_ORDERED(nextBootEntry) && !IS_BOOT_ENTRY_DELETED(nextBootEntry)) {
  2390. count++;
  2391. }
  2392. nextBootEntry = nextBootEntry->Next;
  2393. }
  2394. order = MALLOC(count * sizeof(ULONG));
  2395. if (order == NULL) {
  2396. return FALSE;
  2397. }
  2398. count = 0;
  2399. nextBootEntry = MyBootEntries;
  2400. while (nextBootEntry != NULL) {
  2401. if (IS_BOOT_ENTRY_ORDERED(nextBootEntry) && !IS_BOOT_ENTRY_DELETED(nextBootEntry)) {
  2402. order[count++] = nextBootEntry->NtBootEntry.Id;
  2403. }
  2404. nextBootEntry = nextBootEntry->Next;
  2405. }
  2406. //
  2407. // Write the new boot entry order list.
  2408. //
  2409. status = SetBootEntryOrder(order, count);
  2410. FREE(order);
  2411. if (!NT_SUCCESS(status)) {
  2412. return FALSE;
  2413. }
  2414. return TRUE;
  2415. } // CreateBootEntry
  2416. #endif // defined(EFI_NVRAM_ENABLED)
  2417. #endif // UNICODE