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.

1781 lines
53 KiB

  1. #include "autosafe.h"
  2. PWSTR SystemPartitionNtName;
  3. PBOOT_OPTIONS BootOptions;
  4. ULONG BootOptionsLength;
  5. PBOOT_OPTIONS OriginalBootOptions;
  6. ULONG OriginalBootOptionsLength;
  7. PULONG BootEntryOrder;
  8. ULONG BootEntryOrderCount;
  9. PULONG OriginalBootEntryOrder;
  10. ULONG OriginalBootEntryOrderCount;
  11. LIST_ENTRY BootEntries;
  12. LIST_ENTRY DeletedBootEntries;
  13. LIST_ENTRY ActiveUnorderedBootEntries;
  14. LIST_ENTRY InactiveUnorderedBootEntries;
  15. VOID
  16. ConcatenatePaths (
  17. IN OUT PTSTR Path1,
  18. IN LPCTSTR Path2,
  19. IN DWORD BufferSizeChars
  20. );
  21. VOID
  22. ConvertBootEntries (
  23. PBOOT_ENTRY_LIST BootEntries
  24. );
  25. PMY_BOOT_ENTRY
  26. CreateBootEntryFromBootEntry (
  27. IN PMY_BOOT_ENTRY OldBootEntry
  28. );
  29. VOID
  30. FreeBootEntry (
  31. IN PMY_BOOT_ENTRY BootEntry
  32. );
  33. VOID
  34. InitializeEfi (
  35. VOID
  36. );
  37. NTSTATUS
  38. (*AddBootEntry) (
  39. IN PBOOT_ENTRY BootEntry,
  40. OUT PULONG Id OPTIONAL
  41. );
  42. NTSTATUS
  43. (*DeleteBootEntry) (
  44. IN ULONG Id
  45. );
  46. NTSTATUS
  47. (*ModifyBootEntry) (
  48. IN PBOOT_ENTRY BootEntry
  49. );
  50. NTSTATUS
  51. (*EnumerateBootEntries) (
  52. OUT PVOID Buffer,
  53. IN OUT PULONG BufferLength
  54. );
  55. NTSTATUS
  56. (*QueryBootEntryOrder) (
  57. OUT PULONG Ids,
  58. IN OUT PULONG Count
  59. );
  60. NTSTATUS
  61. (*SetBootEntryOrder) (
  62. IN PULONG Ids,
  63. IN ULONG Count
  64. );
  65. NTSTATUS
  66. (*QueryBootOptions) (
  67. OUT PBOOT_OPTIONS BootOptions,
  68. IN OUT PULONG BootOptionsLength
  69. );
  70. NTSTATUS
  71. (*SetBootOptions) (
  72. IN PBOOT_OPTIONS BootOptions,
  73. IN ULONG FieldsToChange
  74. );
  75. NTSTATUS
  76. (*TranslateFilePath) (
  77. IN PFILE_PATH InputFilePath,
  78. IN ULONG OutputType,
  79. OUT PFILE_PATH OutputFilePath,
  80. IN OUT PULONG OutputFilePathLength
  81. );
  82. NTSTATUS LabelDefaultIA64(WCHAR *szKeyWord);
  83. NTSTATUS LabelDefaultX86(CHAR *szKeyWord);
  84. NTSTATUS MoveSafeIA64(WCHAR *szKeyWord);
  85. NTSTATUS MoveSafeX86(CHAR *szKeyWord);
  86. WCHAR x86DetermineSystemPartition();
  87. WCHAR *ParseArgs();
  88. CHAR *sPreLabel(CHAR* szBootOp, CHAR* szLabel);
  89. CHAR *sReChanged(CHAR* szBootData, CHAR* szBootTitle, CHAR* szNewBootTitle);
  90. WCHAR Usage[] =
  91. L"Autosafe - Set next boot OS\n"
  92. L"Usage: \tAutosafe [/?][boot entry keywords]\n" \
  93. L"Ex: \tAutosafe \"Build 2505\"\n" \
  94. L" /? this message\n" \
  95. L" defaults to keyword = 'safe'\n";
  96. CHAR *sReChanged(CHAR* szBootData, CHAR* szBootTitle, CHAR* szNewBootTitle){
  97. CHAR* pMatch = NULL;
  98. CHAR* szHdPart = NULL;
  99. CHAR* szTlPart = NULL;
  100. CHAR* szNewBootData = NULL;
  101. szHdPart = (CHAR*)(MemAlloc(1+strlen(szBootData)));
  102. szTlPart = (CHAR*)(MemAlloc(1+strlen(szBootData)));
  103. szNewBootData = (CHAR*)(MemAlloc(3 + strlen(szNewBootTitle)+strlen(szBootData)));
  104. ZeroMemory(szNewBootData, 1+strlen(szBootData));
  105. ZeroMemory(szHdPart, 1+strlen(szBootData));
  106. ZeroMemory(szTlPart, 1+strlen(szBootData));
  107. if ((pMatch = strstr(szBootData, _strlwr(szBootTitle)))){
  108. memcpy(szHdPart, szBootData, (pMatch - szBootData));
  109. sprintf(szTlPart, "%s", pMatch + strlen(szBootTitle));
  110. sprintf(szNewBootData, "%s%s%s", szHdPart, szNewBootTitle, szTlPart);
  111. }
  112. MemFree(szHdPart);
  113. MemFree(szTlPart);
  114. return szNewBootData;
  115. }
  116. CHAR *sPreLabel(CHAR* szBootOp, CHAR* szLabel){
  117. CHAR* szOutputOp = NULL;
  118. CHAR* pQuote = NULL;
  119. CHAR* szHdPart = NULL;
  120. CHAR* szTlPart = NULL;
  121. UINT lIgLn = strlen("microsoft windows xp professional");
  122. szOutputOp = (CHAR*)(MemAlloc(3 + strlen(szBootOp)+strlen(szLabel)));
  123. szHdPart = (CHAR*)(MemAlloc(1 + strlen(szBootOp)));
  124. szTlPart = (CHAR*)(MemAlloc(1 + strlen(szBootOp)));
  125. ZeroMemory(szOutputOp, 3 + strlen(szBootOp)+strlen(szLabel));
  126. ZeroMemory(szHdPart, strlen(szBootOp)+1);
  127. ZeroMemory(szTlPart, strlen(szBootOp)+1);
  128. if ((pQuote = strchr(szBootOp, '"'))){
  129. memcpy(szHdPart, szBootOp, (pQuote - szBootOp) + 1);
  130. sprintf(szTlPart, "%s", pQuote + 1);
  131. sprintf(szOutputOp, "%s%s%s", szHdPart, szLabel , szTlPart);
  132. }
  133. else {
  134. sprintf(szOutputOp, "%s%s", szLabel, szBootOp);
  135. }
  136. /* if (lIgLn < strlen(szOutputOp)){
  137. *(szOutputOp+lIgLn-3) = '.';
  138. *(szOutputOp+lIgLn-2) = '.';
  139. *(szOutputOp+lIgLn-1) = '.';
  140. *(szOutputOp+lIgLn) = '\0';
  141. }
  142. // do not handle this case yet
  143. */
  144. MemFree(szHdPart);
  145. MemFree(szTlPart);
  146. return szOutputOp;
  147. }
  148. WCHAR* ParseArgs()
  149. {
  150. WCHAR * szwKeyWord = NULL;
  151. szwKeyWord = wcschr(GetCommandLineW(), ' ') + 1;
  152. //look for /?
  153. if( wcsstr( L"/?", szwKeyWord) ){
  154. wprintf(Usage);
  155. return NULL;
  156. }
  157. //strip beginning & trailing " if there
  158. if( L'"' == *szwKeyWord && L'"' == *(CharPrev(szwKeyWord, szwKeyWord + lstrlen(szwKeyWord))) )
  159. {
  160. szwKeyWord = CharNext(szwKeyWord);
  161. *(CharPrev(szwKeyWord, szwKeyWord + lstrlen(szwKeyWord))) = L'\0';
  162. }
  163. return szwKeyWord;
  164. }
  165. int
  166. __cdecl
  167. main (int argc, CHAR *argv[])
  168. {
  169. WCHAR dllName[MAX_PATH];
  170. HMODULE h;
  171. DWORD err;
  172. SYSTEM_INFO siInfo;
  173. WCHAR *szwKeyWord;
  174. CHAR szKeyWord[255];
  175. VOID (*GetNativeSystemInfo) (OUT LPSYSTEM_INFO lpSystemInfo) = NULL;
  176. ZeroMemory(szKeyWord, sizeof(szKeyWord));
  177. szwKeyWord = L"safe";
  178. if(argc > 1) // parseargs
  179. if(NULL == (szwKeyWord = ParseArgs())) return 1;
  180. //We want to run this via Wow64 on ia64 so we'll
  181. //determine proc arch - via GetNativeSystemInfo
  182. GetSystemDirectory( dllName, MAX_PATH );
  183. ConcatenatePaths( dllName, L"kernel32.dll", MAX_PATH );
  184. h = LoadLibrary( dllName );
  185. if ( h == NULL ) {
  186. err = GetLastError();
  187. FatalError( err, L"Can't load KERNEL32.DLL: %d\n", err );
  188. }
  189. GetNativeSystemInfo = (VOID(__stdcall *)(LPSYSTEM_INFO)) GetProcAddress(h, "GetNativeSystemInfo");
  190. if(!GetNativeSystemInfo) {
  191. //Not running WinXP - meaning not ia64/wow64 env, default to GetSystemInfo
  192. GetSystemInfo(&siInfo);
  193. }
  194. else
  195. {
  196. GetNativeSystemInfo(&siInfo);
  197. }
  198. switch( siInfo.wProcessorArchitecture )
  199. {
  200. wprintf(L"%i\n", siInfo.wProcessorArchitecture );
  201. case PROCESSOR_ARCHITECTURE_IA64:
  202. InitializeEfi( );
  203. if(!MoveSafeIA64(szwKeyWord)){
  204. wprintf(L"Boot option \"%ws\" not found.\nLabel the default option \"%ws\"\n",
  205. szwKeyWord, szwKeyWord);
  206. if(!LabelDefaultIA64(szwKeyWord)){
  207. wprintf(L"Could not lebel the default option \"%ws\"\nNo changes made\n",
  208. szwKeyWord);
  209. }
  210. }
  211. break;
  212. case PROCESSOR_ARCHITECTURE_INTEL:
  213. if(!WideCharToMultiByte( CP_ACP,
  214. WC_NO_BEST_FIT_CHARS,
  215. szwKeyWord,
  216. -1,
  217. szKeyWord,
  218. sizeof(szKeyWord),
  219. NULL,
  220. NULL))
  221. {
  222. FatalError(0, L"Couldn't convert string");
  223. }
  224. if(!MoveSafeX86(szKeyWord)){
  225. wprintf(L"Boot option \"%ws\" not found.\nLabel the default option \"%ws\"\n",
  226. szwKeyWord,szwKeyWord);
  227. if(!LabelDefaultX86(szKeyWord)){
  228. wprintf(L"Could not lebel the default option \"%ws\"\nNo changes made\n",
  229. szwKeyWord);
  230. }
  231. }
  232. break;
  233. default:
  234. FatalError( 0, L"Can't determine processor type.\n" );
  235. }
  236. return 0;
  237. }
  238. NTSTATUS MoveSafeX86(CHAR *szKeyWord){
  239. HANDLE hfile;
  240. DWORD dwFileSize = 0, dwRead, dwSafeSize, dwCnt;
  241. CHAR *lcbuf = NULL, *buf = NULL, *SafeBootLine = NULL;
  242. CHAR *pt1,*pt2,*pdefault,*plast,*p0,*p1,*psafe;
  243. BOOL b;
  244. WCHAR szBootIni[] = L"?:\\BOOT.INI";
  245. *szBootIni = x86DetermineSystemPartition();
  246. //
  247. // Open and read boot.ini.
  248. //
  249. b = FALSE;
  250. SetFileAttributes(szBootIni, FILE_ATTRIBUTE_NORMAL);
  251. hfile = CreateFile(szBootIni,
  252. GENERIC_READ,
  253. FILE_SHARE_READ,
  254. NULL,
  255. OPEN_EXISTING,
  256. 0,
  257. NULL);
  258. if(hfile != INVALID_HANDLE_VALUE) {
  259. dwFileSize = GetFileSize(hfile, NULL);
  260. if(dwFileSize != INVALID_FILE_SIZE) {
  261. buf = (CHAR*)(MemAlloc((SIZE_T)(dwFileSize+1)));
  262. b = ReadFile(hfile, buf, dwFileSize, &dwRead, NULL);
  263. }
  264. SetFileAttributes( szBootIni,
  265. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
  266. FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN
  267. );
  268. CloseHandle(hfile);
  269. }
  270. if(!b) {
  271. if(buf) MemFree(buf);
  272. FatalError(0, L"failed to read boot.ini\n");
  273. }
  274. //Set pdefault to end of default=
  275. if(!(pdefault = strstr(buf, "default=")) ||
  276. !(pdefault += sizeof("default"))) {
  277. MemFree(buf);
  278. FatalError(0, L"failed to find 'default' entry\n");
  279. return FALSE;
  280. }
  281. //Get the next line
  282. plast = strchr(pdefault, '\n') + 1;
  283. //Get the SafeBootLine
  284. //Set p0 to the first [operating systems] entry, p1 to the last, search between the two
  285. if(!(p0 = strstr(buf,"[operating systems]")) ||
  286. !(p0 = strchr(p0,'\n') + 1) ) {
  287. MemFree(buf);
  288. FatalError(0, L"failed to find '[operating systems]' entry\n");
  289. return FALSE;
  290. }
  291. //Find next ini section - or end of file
  292. if(!(p1 = strchr(p0, '['))) p1 = buf+strlen(buf);
  293. //create lowercase buffer to search through
  294. lcbuf = (CHAR*)( MemAlloc(p1-p0) );
  295. memcpy(lcbuf, p0, p1-p0);
  296. _strlwr(lcbuf);
  297. //Find szKeyWord string
  298. if(!(psafe = strstr(lcbuf, _strlwr(szKeyWord)))) {
  299. printf("No '%s' build found.\n", szKeyWord);
  300. MemFree(buf);
  301. MemFree(lcbuf);
  302. return FALSE;
  303. }
  304. //relate to position in org buffer: p0 + offset into psafe buffer - 1
  305. psafe = p0 + (psafe - lcbuf) - 1;
  306. MemFree(lcbuf);
  307. //Now Set p0 to begining & p1 to end of 'safe' entry & copy into SafeBootLine buffer
  308. p1 = p0;
  309. while( (p1 = strchr(p1, '\n') + 1)
  310. && (p1 < psafe ))
  311. p0 = p1;
  312. p1 = strchr(p0, '=');
  313. dwSafeSize = (DWORD)(p1-p0+2);
  314. SafeBootLine = (CHAR*)(MemAlloc(dwSafeSize));
  315. ZeroMemory(SafeBootLine, dwSafeSize);
  316. memcpy(SafeBootLine, p0, dwSafeSize);
  317. *(SafeBootLine + dwSafeSize - 2) = '\r';
  318. *(SafeBootLine + dwSafeSize - 1) = '\n';
  319. *(SafeBootLine + dwSafeSize ) = '\0';
  320. printf("Setting as next boot: \n\t%s\n", SafeBootLine);
  321. //
  322. // Write:
  323. //
  324. // 1) the first part, start=buf, len=pdefault-buf
  325. // 2) the default= line
  326. // 3) the last part, start=plast, len=buf+sizeof(buf)-plast
  327. //
  328. SetFileAttributes(szBootIni, FILE_ATTRIBUTE_NORMAL);
  329. hfile = CreateFile(szBootIni,
  330. GENERIC_ALL,
  331. 0,
  332. NULL,
  333. OPEN_EXISTING,
  334. 0,
  335. NULL);
  336. if(!WriteFile(hfile, buf, (DWORD)(pdefault-buf), &dwCnt, NULL) ||
  337. !WriteFile(hfile, SafeBootLine, dwSafeSize, &dwCnt, NULL) ||
  338. !WriteFile(hfile, plast, (DWORD)(buf+dwFileSize-plast+1), &dwCnt, NULL) )
  339. {
  340. CloseHandle(hfile);
  341. MemFree(buf);
  342. FatalError(0, L"Failed to write new boot.ini\n");
  343. return FALSE;
  344. }
  345. //
  346. // Make boot.ini archive, read only, and system.
  347. //
  348. SetFileAttributes(
  349. szBootIni,
  350. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN
  351. );
  352. MemFree(buf);
  353. return(TRUE);
  354. }
  355. NTSTATUS MoveSafeIA64(WCHAR *szwKeyWord){
  356. PMY_BOOT_ENTRY bootEntry;
  357. PLIST_ENTRY listEntry = NULL;
  358. PLIST_ENTRY ListHead = NULL;
  359. WCHAR szFriendlyName[255];
  360. ListHead = &BootEntries;
  361. if ( ListHead->Flink == ListHead ){
  362. //Don't have to move anything
  363. return 1;
  364. }
  365. for ( listEntry = ListHead->Flink;
  366. listEntry != ListHead;
  367. listEntry = listEntry->Flink ) {
  368. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  369. wcscpy(szFriendlyName, bootEntry->FriendlyName);
  370. if( wcsstr( _wcslwr(szFriendlyName), szwKeyWord ))
  371. {
  372. wprintf(L"Setting as next boot: \n\t%s\n", bootEntry->FriendlyName);
  373. RemoveEntryList( listEntry );
  374. InsertHeadList( &BootEntries, listEntry);
  375. SaveChanges(NULL);
  376. return 1;
  377. }
  378. }
  379. return 0;
  380. }
  381. NTSTATUS LabelDefaultX86(CHAR *szKeyWord){
  382. HANDLE hfile;
  383. DWORD dwFileSize = 0, dwRead, dwSafeSize, dwCnt, dwDefaultSize;
  384. CHAR *lcbuf = NULL, *buf = NULL;
  385. CHAR *sCurrentBootChoice = NULL;
  386. CHAR *sBootTitle = NULL, *newsBootTitle = NULL;
  387. CHAR *sBootDefault = NULL, *sBootData = NULL;
  388. CHAR *pdefault,*plast,*p0,*p1, *p2, *psafe;
  389. CHAR *szInsKeyWord = NULL;
  390. BOOL bReadFile = FALSE;
  391. BOOL bWriteFile = FALSE;
  392. WCHAR szBootIni[] = L"?:\\BOOT.INI";
  393. *szBootIni = x86DetermineSystemPartition();
  394. szInsKeyWord = (CHAR*)(MemAlloc(2+strlen(szKeyWord)));
  395. sprintf(szInsKeyWord, "%s ", szKeyWord);
  396. //
  397. // Open and read boot.ini.
  398. //
  399. SetFileAttributes(szBootIni, FILE_ATTRIBUTE_NORMAL);
  400. hfile = CreateFile( szBootIni,GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  401. if(hfile != INVALID_HANDLE_VALUE) {
  402. dwFileSize = GetFileSize(hfile, NULL);
  403. if(dwFileSize != INVALID_FILE_SIZE) {
  404. buf = (CHAR*)( MemAlloc((SIZE_T)(dwFileSize+1)));
  405. bReadFile = ReadFile(hfile, buf, dwFileSize, &dwRead, NULL);
  406. _strlwr(buf);
  407. }
  408. SetFileAttributes( szBootIni,
  409. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM |
  410. FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN
  411. );
  412. CloseHandle(hfile);
  413. }
  414. if(!bReadFile) {
  415. if(buf) MemFree(buf);
  416. FatalError(0, L"failed to read boot.ini\n");
  417. return FALSE;
  418. }
  419. //Set pdefault to end of default=... line
  420. if(!(pdefault = strstr(buf, "default=")) ||
  421. !(pdefault += sizeof("default"))) {
  422. MemFree(buf);
  423. FatalError(0, L"failed to find 'default' entry\n");
  424. return FALSE;
  425. }
  426. dwDefaultSize = (DWORD)(pdefault - buf);
  427. //Get the next line
  428. plast = strchr(pdefault, '\n') - 1;
  429. sCurrentBootChoice = (CHAR*)( MemAlloc(plast - pdefault));
  430. ZeroMemory(sCurrentBootChoice, sizeof(sCurrentBootChoice));
  431. memcpy(sCurrentBootChoice, pdefault, plast - pdefault);
  432. // printf("Default:\n%s\n", sCurrentBootChoice);
  433. plast = strchr(pdefault, '\n') + 1;
  434. //Get the sBootTitle
  435. //Set p0 to the first [Operating Systems] entry, p1 to the last, search between the two
  436. if(!(p0 = strstr(buf,"[operating systems]")) ||
  437. !(p0 = strchr(p0,'\n') + 1) ) {
  438. MemFree(buf);
  439. FatalError(0, L"failed to find '[Operating systems]' entry\n");
  440. return FALSE;
  441. }
  442. //Find next ini section - or end of file
  443. if(!(p1 = strchr(p0, '['))) p1 = buf+strlen(buf);
  444. dwSafeSize = (DWORD)(p1 - p0)+1;
  445. sBootDefault = (CHAR*)(MemAlloc(dwSafeSize));
  446. ZeroMemory(sBootDefault, dwSafeSize);
  447. sprintf(sBootDefault, "%s\r\n",sCurrentBootChoice);
  448. // printf("Setting label to: \n\t%s\n", sBootDefault);
  449. //create lowercase buffer to search through
  450. lcbuf = (CHAR*)( MemAlloc(p1-p0) );
  451. memcpy(lcbuf, p0, p1-p0);
  452. _strlwr(lcbuf);
  453. //Find sCurrentBootChoice string
  454. if(!(psafe = strstr(lcbuf, _strlwr(sCurrentBootChoice)))) {
  455. wprintf(L"Default boot \"%ws\" not found.\n", sCurrentBootChoice);
  456. MemFree(buf);
  457. MemFree(lcbuf);
  458. return FALSE;
  459. }
  460. //relate to position in org buffer: p0 + offset into psafe buffer - 1
  461. psafe = p0 + (psafe - lcbuf) - 1;
  462. MemFree(lcbuf);
  463. // Set p0 to begining & p1 to end of entry &
  464. // copy into sBootTitle buffer
  465. p1 = p0 ;
  466. while( (p1 = strchr(p1, '\n') + 1)
  467. && (p1 < psafe ))
  468. p0 = p1;
  469. p1 = 1 + strchr(psafe, '=');
  470. p2 = -1 + strchr(p1, '\n');
  471. dwSafeSize = (DWORD)(p2 - p1) + 1 ;
  472. sBootTitle = (CHAR*)(MemAlloc(dwSafeSize));
  473. ZeroMemory(sBootTitle, dwSafeSize);
  474. memcpy(sBootTitle, p1, dwSafeSize);
  475. newsBootTitle = (CHAR*)(MemAlloc(dwSafeSize+ strlen(szKeyWord) + 3));
  476. ZeroMemory(newsBootTitle, dwSafeSize+ strlen(szKeyWord) + 3);
  477. sprintf(newsBootTitle,"%s", sPreLabel(sBootTitle, szInsKeyWord ));
  478. // printf("Title:\n%s\n", newsBootTitle);
  479. sBootData = (CHAR* ) (MemAlloc(dwFileSize + strlen(szKeyWord) + 3));
  480. ZeroMemory(sBootData, dwFileSize + strlen(szKeyWord) + 3);
  481. memcpy(sBootData, buf, dwFileSize);
  482. // printf("Boot file data(old): \n%s\n", sBootData);
  483. sprintf(sBootData, "%s", sReChanged(sBootData, sBootTitle, newsBootTitle));
  484. MemFree(sBootTitle);
  485. MemFree(newsBootTitle);
  486. // printf("Boot file data(new): \n%s\n", sBootData);
  487. SetFileAttributes(szBootIni, FILE_ATTRIBUTE_NORMAL);
  488. hfile = CreateFile(szBootIni, GENERIC_ALL,0,NULL, OPEN_EXISTING, 0, NULL);
  489. if(hfile != INVALID_HANDLE_VALUE) {
  490. if(!WriteFile(hfile, sBootData , strlen(sBootData), &dwCnt, NULL)){
  491. CloseHandle(hfile);
  492. MemFree(buf);
  493. FatalError(0, L"Failed to write new boot.ini\n");
  494. return FALSE;
  495. }
  496. bWriteFile = TRUE;
  497. //
  498. // Make boot.ini archive, read only, and system.
  499. //
  500. SetFileAttributes(
  501. szBootIni,
  502. FILE_ATTRIBUTE_READONLY |
  503. FILE_ATTRIBUTE_SYSTEM |
  504. FILE_ATTRIBUTE_ARCHIVE |
  505. FILE_ATTRIBUTE_HIDDEN
  506. );
  507. }
  508. MemFree(buf);
  509. MemFree(sBootData);
  510. MemFree(szInsKeyWord);
  511. return(bWriteFile);
  512. }
  513. NTSTATUS LabelDefaultIA64(WCHAR *szwKeyWord){
  514. PMY_BOOT_ENTRY bootEntry;
  515. PLIST_ENTRY listEntry = NULL;
  516. PLIST_ENTRY ListHead = NULL;
  517. WCHAR szFriendlyName[1024];
  518. WCHAR szwSmFrFriendlyName[1024];
  519. WCHAR szwSmToFriendlyName[1024];
  520. CHAR szSmFrFriendlyName[1024];
  521. CHAR szSmToFriendlyName[1024];
  522. CHAR szInsKeyWord[1024];
  523. INT dOuTMB2WC;
  524. ListHead = &BootEntries;
  525. bootEntry =
  526. CONTAINING_RECORD(
  527. ListHead->Flink,
  528. MY_BOOT_ENTRY,
  529. ListEntry );
  530. // modify friendly name for default entry.
  531. wsprintf(szwSmFrFriendlyName, L"%ws", bootEntry->FriendlyName);
  532. if(!WideCharToMultiByte( CP_ACP,
  533. WC_NO_BEST_FIT_CHARS,
  534. szwKeyWord,
  535. -1,
  536. szInsKeyWord,
  537. sizeof(szInsKeyWord),
  538. NULL,
  539. NULL)) {
  540. FatalError(0, L"Couldn't convert string");
  541. }
  542. sprintf(szInsKeyWord, "%s ", szInsKeyWord);
  543. if(!WideCharToMultiByte( CP_ACP,
  544. WC_NO_BEST_FIT_CHARS,
  545. szwSmFrFriendlyName,
  546. -1,
  547. szSmFrFriendlyName,
  548. sizeof(szSmFrFriendlyName),
  549. NULL,
  550. NULL)) {
  551. FatalError(0, L"Couldn't convert string");
  552. }
  553. wprintf(L"original(w): \"%ws\"\n", szwSmFrFriendlyName);
  554. sprintf(szSmToFriendlyName, "%s", sPreLabel(szSmFrFriendlyName, szInsKeyWord));
  555. //do a hack here. Do not extend the Friendly name beyong
  556. //its former size. unless you wish to debug why
  557. //CreateBootEntryFromBootEntry sig segv
  558. szSmToFriendlyName[strlen(szSmFrFriendlyName)] = '\0';
  559. szSmToFriendlyName[strlen(szSmFrFriendlyName)-1] = '.';
  560. szSmToFriendlyName[strlen(szSmFrFriendlyName)-2] = '.';
  561. szSmToFriendlyName[strlen(szSmFrFriendlyName)-3] = '.';
  562. if (!(dOuTMB2WC=MultiByteToWideChar(CP_ACP,
  563. MB_PRECOMPOSED,
  564. szSmToFriendlyName,
  565. strlen(szSmToFriendlyName) + 1,
  566. szwSmToFriendlyName,
  567. sizeof(szwSmToFriendlyName)/sizeof(szwSmToFriendlyName[0])))){
  568. FatalError(0, L"Couldn't convert string back");
  569. }
  570. wprintf(L"modified(w): \"%ws\"\n", szwSmToFriendlyName);
  571. wcscpy( bootEntry->FriendlyName, szwSmToFriendlyName);
  572. // bootEntry->FriendlyNameLength = 2*strlen(szSmToFriendlyName)+2;
  573. // this seems to be ignored anyway.
  574. MBE_SET_MODIFIED( bootEntry );
  575. wprintf(L"saving changes:\n\"%ws\"\n",
  576. bootEntry->FriendlyName);
  577. SaveChanges(bootEntry);
  578. for ( listEntry = ListHead->Flink;
  579. listEntry != ListHead;
  580. listEntry = listEntry->Flink ) {
  581. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  582. wcscpy(szFriendlyName, bootEntry->FriendlyName);
  583. if( wcsstr( _wcslwr(szFriendlyName), _wcslwr(szwSmToFriendlyName ))){
  584. wprintf(L"committed changes:\n\"%ws\"\n",
  585. bootEntry->FriendlyName);
  586. return 1;
  587. }
  588. }
  589. return 0;
  590. }
  591. PVOID
  592. MemAlloc(
  593. IN SIZE_T Size
  594. )
  595. {
  596. PSIZE_T p;
  597. //
  598. // Add space for storing the size of the block.
  599. //
  600. p = (PSIZE_T)(RtlAllocateHeap( RtlProcessHeap(), 0, Size + sizeof(SIZE_T) ));
  601. if ( p == NULL ) {
  602. FatalError( ERROR_NOT_ENOUGH_MEMORY, L"Insufficient memory\n" );
  603. }
  604. //
  605. // Store the size of the block, and return the address
  606. // of the user portion of the block.
  607. //
  608. *p++ = Size;
  609. return p;
  610. }
  611. VOID
  612. MemFree(
  613. IN PVOID Block
  614. )
  615. {
  616. if (Block == NULL)
  617. return;
  618. //
  619. // Free the block at its real address.
  620. //
  621. RtlFreeHeap( RtlProcessHeap(), 0, (PSIZE_T)Block - 1);
  622. }
  623. WCHAR
  624. x86DetermineSystemPartition(
  625. VOID
  626. )
  627. /*++
  628. Routine Description:
  629. Determine the system partition on x86 machines.
  630. The system partition is the primary partition on the boot disk.
  631. Usually this is the active partition on disk 0 and usually it's C:.
  632. However the user could have remapped drive letters and generally
  633. determining the system partition with 100% accuracy is not possible.
  634. If for some reason we cannot determine the system partition by the above
  635. method, we simply assume it's C:.
  636. Arguments:
  637. None
  638. Return Value:
  639. Drive letter of system partition.
  640. --*/
  641. {
  642. BOOL GotIt;
  643. PWSTR NtDevicePath = NULL;
  644. WCHAR Drive;
  645. WCHAR DriveName[3];
  646. WCHAR Buffer[512];
  647. WCHAR FileName[512];
  648. WCHAR *BootFiles[4];
  649. DWORD NtDevicePathLen = 0;
  650. PWSTR p;
  651. DWORD PhysicalDriveNumber;
  652. HANDLE hDisk;
  653. BOOL b;
  654. DWORD DataSize;
  655. PVOID DriveLayout;
  656. DWORD DriveLayoutSize;
  657. DWORD d;
  658. int i;
  659. DriveName[1] = L':';
  660. DriveName[2] = 0;
  661. GotIt = FALSE;
  662. BootFiles[0] = L"BOOT.INI";
  663. BootFiles[1] = L"NTLDR";
  664. BootFiles[2] = L"NTDETECT.COM";
  665. BootFiles[3] = NULL;
  666. // The system partition can only be a drive that is on
  667. // this disk. We make this determination by looking at NT drive names
  668. // for each drive letter and seeing if the nt equivalent of
  669. // multi(0)disk(0)rdisk(0) is a prefix.
  670. //
  671. for(Drive=L'C'; Drive<=L'Z'; Drive++) {
  672. WCHAR drvbuf[5];
  673. swprintf(drvbuf, L"%c:\\", Drive);
  674. if(GetDriveType(drvbuf) == DRIVE_FIXED) {
  675. DriveName[0] = Drive;
  676. if(QueryDosDeviceW(DriveName,Buffer,sizeof(Buffer)/sizeof(WCHAR))) {
  677. if(!_wcsnicmp(NtDevicePath,Buffer,NtDevicePathLen)) {
  678. //
  679. // Now look to see whether there's an nt boot sector and
  680. // boot files on this drive.
  681. //
  682. for(i=0; BootFiles[i]; i++) {
  683. DWORD d;
  684. swprintf(FileName, L"%s%s", drvbuf, BootFiles[i]);
  685. if(-1 == GetFileAttributes(FileName))
  686. break;
  687. }
  688. return Drive;
  689. }
  690. }
  691. }
  692. }
  693. return L'C';
  694. }
  695. VOID
  696. FatalError (
  697. DWORD Error,
  698. PWSTR Format,
  699. ...
  700. )
  701. {
  702. va_list marker;
  703. va_start( marker, Format );
  704. wprintf(L"Fatal error:\n \t");
  705. vwprintf( Format, marker );
  706. va_end( marker );
  707. if ( Error == NO_ERROR ) {
  708. Error = ERROR_GEN_FAILURE;
  709. }
  710. exit( Error );
  711. } // FatalError
  712. VOID
  713. ConvertBootEntries (
  714. PBOOT_ENTRY_LIST NtBootEntries
  715. )
  716. /*++
  717. Routine Description:
  718. Convert boot entries read from EFI NVRAM into our internal format.
  719. Arguments:
  720. None.
  721. Return Value:
  722. NTSTATUS - Not STATUS_SUCCESS if an unexpected error occurred.
  723. --*/
  724. {
  725. PBOOT_ENTRY_LIST bootEntryList;
  726. PBOOT_ENTRY bootEntry;
  727. PBOOT_ENTRY bootEntryCopy;
  728. PMY_BOOT_ENTRY myBootEntry;
  729. PWINDOWS_OS_OPTIONS osOptions;
  730. ULONG length;
  731. bootEntryList = NtBootEntries;
  732. while (TRUE) {
  733. bootEntry = &bootEntryList->BootEntry;
  734. //
  735. // Calculate the length of our internal structure. This includes
  736. // the base part of MY_BOOT_ENTRY plus the NT BOOT_ENTRY.
  737. //
  738. length = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry) + bootEntry->Length;
  739. myBootEntry = (PMY_BOOT_ENTRY) (MemAlloc(length));
  740. RtlZeroMemory(myBootEntry, length);
  741. //
  742. // Link the new entry into the list.
  743. //
  744. if ( (bootEntry->Attributes & BOOT_ENTRY_ATTRIBUTE_ACTIVE) != 0 ) {
  745. InsertTailList( &ActiveUnorderedBootEntries, &myBootEntry->ListEntry );
  746. myBootEntry->ListHead = &ActiveUnorderedBootEntries;
  747. } else {
  748. InsertTailList( &InactiveUnorderedBootEntries, &myBootEntry->ListEntry );
  749. myBootEntry->ListHead = &InactiveUnorderedBootEntries;
  750. }
  751. //
  752. // Copy the NT BOOT_ENTRY into the allocated buffer.
  753. //
  754. bootEntryCopy = &myBootEntry->NtBootEntry;
  755. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  756. //
  757. // Fill in the base part of the structure.
  758. //
  759. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + length - 1;
  760. myBootEntry->Id = bootEntry->Id;
  761. myBootEntry->Attributes = bootEntry->Attributes;
  762. myBootEntry->FriendlyName = (PWSTR)(ADD_OFFSET(bootEntryCopy, FriendlyNameOffset));
  763. myBootEntry->FriendlyNameLength =
  764. ((ULONG)wcslen(myBootEntry->FriendlyName) + 1) * sizeof(WCHAR);
  765. myBootEntry->BootFilePath = (PFILE_PATH)(ADD_OFFSET(bootEntryCopy, BootFilePathOffset));
  766. //
  767. // If this is an NT boot entry, capture the NT-specific information in
  768. // the OsOptions.
  769. //
  770. osOptions = (PWINDOWS_OS_OPTIONS)bootEntryCopy->OsOptions;
  771. if ((bootEntryCopy->OsOptionsLength >= FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) &&
  772. (strcmp((char *)osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) == 0)) {
  773. MBE_SET_IS_NT( myBootEntry );
  774. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  775. myBootEntry->OsLoadOptionsLength =
  776. ((ULONG)wcslen(myBootEntry->OsLoadOptions) + 1) * sizeof(WCHAR);
  777. myBootEntry->OsFilePath = (PFILE_PATH)(ADD_OFFSET(osOptions, OsLoadPathOffset));
  778. } else {
  779. //
  780. // Foreign boot entry. Just capture whatever OS options exist.
  781. //
  782. myBootEntry->ForeignOsOptions = bootEntryCopy->OsOptions;
  783. myBootEntry->ForeignOsOptionsLength = bootEntryCopy->OsOptionsLength;
  784. }
  785. //
  786. // Move to the next entry in the enumeration list, if any.
  787. //
  788. if (bootEntryList->NextEntryOffset == 0) {
  789. break;
  790. }
  791. bootEntryList = (PBOOT_ENTRY_LIST)(ADD_OFFSET(bootEntryList, NextEntryOffset));
  792. }
  793. return;
  794. } // ConvertBootEntries
  795. VOID
  796. ConcatenatePaths (
  797. IN OUT PTSTR Path1,
  798. IN LPCTSTR Path2,
  799. IN DWORD BufferSizeChars
  800. )
  801. /*++
  802. Routine Description:
  803. Concatenate two path strings together, supplying a path separator
  804. character (\) if necessary between the 2 parts.
  805. Arguments:
  806. Path1 - supplies prefix part of path. Path2 is concatenated to Path1.
  807. Path2 - supplies the suffix part of path. If Path1 does not end with a
  808. path separator and Path2 does not start with one, then a path sep
  809. is appended to Path1 before appending Path2.
  810. BufferSizeChars - supplies the size in chars (Unicode version) or
  811. bytes (Ansi version) of the buffer pointed to by Path1. The string
  812. will be truncated as necessary to not overflow that size.
  813. Return Value:
  814. None.
  815. --*/
  816. {
  817. BOOL NeedBackslash = TRUE;
  818. DWORD l;
  819. if(!Path1)
  820. return;
  821. l = lstrlen(Path1);
  822. if(BufferSizeChars >= sizeof(TCHAR)) {
  823. //
  824. // Leave room for terminating nul.
  825. //
  826. BufferSizeChars -= sizeof(TCHAR);
  827. }
  828. //
  829. // Determine whether we need to stick a backslash
  830. // between the components.
  831. //
  832. if(l && (Path1[l-1] == TEXT('\\'))) {
  833. NeedBackslash = FALSE;
  834. }
  835. if(Path2 && *Path2 == TEXT('\\')) {
  836. if(NeedBackslash) {
  837. NeedBackslash = FALSE;
  838. } else {
  839. //
  840. // Not only do we not need a backslash, but we
  841. // need to eliminate one before concatenating.
  842. //
  843. Path2++;
  844. }
  845. }
  846. //
  847. // Append backslash if necessary and if it fits.
  848. //
  849. if(NeedBackslash && (l < BufferSizeChars)) {
  850. lstrcat(Path1,TEXT("\\"));
  851. }
  852. //
  853. // Append second part of string to first part if it fits.
  854. //
  855. if(Path2 && ((l+lstrlen(Path2)) < BufferSizeChars)) {
  856. lstrcat(Path1,Path2);
  857. }
  858. }
  859. PMY_BOOT_ENTRY
  860. CreateBootEntryFromBootEntry (
  861. IN PMY_BOOT_ENTRY OldBootEntry
  862. )
  863. {
  864. ULONG requiredLength;
  865. ULONG osOptionsOffset;
  866. ULONG osLoadOptionsLength;
  867. ULONG osLoadPathOffset;
  868. ULONG osLoadPathLength;
  869. ULONG osOptionsLength;
  870. ULONG friendlyNameOffset;
  871. ULONG friendlyNameLength;
  872. ULONG bootPathOffset;
  873. ULONG bootPathLength;
  874. PMY_BOOT_ENTRY newBootEntry;
  875. PBOOT_ENTRY ntBootEntry;
  876. PWINDOWS_OS_OPTIONS osOptions;
  877. PFILE_PATH osLoadPath;
  878. PWSTR friendlyName;
  879. PFILE_PATH bootPath;
  880. //
  881. // Calculate how long the internal boot entry needs to be. This includes
  882. // our internal structure, plus the BOOT_ENTRY structure that the NT APIs
  883. // use.
  884. //
  885. // Our structure:
  886. //
  887. requiredLength = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  888. //
  889. // Base part of NT structure:
  890. //
  891. requiredLength += FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  892. //
  893. // Save offset to BOOT_ENTRY.OsOptions. Add in base part of
  894. // WINDOWS_OS_OPTIONS. Calculate length in bytes of OsLoadOptions
  895. // and add that in.
  896. //
  897. osOptionsOffset = requiredLength;
  898. if ( MBE_IS_NT( OldBootEntry ) ) {
  899. //
  900. // Add in base part of WINDOWS_OS_OPTIONS. Calculate length in
  901. // bytes of OsLoadOptions and add that in.
  902. //
  903. requiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  904. osLoadOptionsLength = OldBootEntry->OsLoadOptionsLength;
  905. requiredLength += osLoadOptionsLength;
  906. //
  907. // Round up to a ULONG boundary for the OS FILE_PATH in the
  908. // WINDOWS_OS_OPTIONS. Save offset to OS FILE_PATH. Calculate length
  909. // in bytes of FILE_PATH and add that in. Calculate total length of
  910. // WINDOWS_OS_OPTIONS.
  911. //
  912. requiredLength = ALIGN_UP(requiredLength, ULONG);
  913. osLoadPathOffset = requiredLength;
  914. requiredLength += OldBootEntry->OsFilePath->Length;
  915. osLoadPathLength = requiredLength - osLoadPathOffset;
  916. } else {
  917. //
  918. // Add in length of foreign OS options.
  919. //
  920. requiredLength += OldBootEntry->ForeignOsOptionsLength;
  921. osLoadOptionsLength = 0;
  922. osLoadPathOffset = 0;
  923. osLoadPathLength = 0;
  924. }
  925. osOptionsLength = requiredLength - osOptionsOffset;
  926. //
  927. // Round up to a ULONG boundary for the friendly name in the BOOT_ENTRY.
  928. // Save offset to friendly name. Calculate length in bytes of friendly name
  929. // and add that in.
  930. //
  931. requiredLength = ALIGN_UP(requiredLength, ULONG);
  932. friendlyNameOffset = requiredLength;
  933. friendlyNameLength = OldBootEntry->FriendlyNameLength;
  934. requiredLength += friendlyNameLength;
  935. //
  936. // Round up to a ULONG boundary for the boot FILE_PATH in the BOOT_ENTRY.
  937. // Save offset to boot FILE_PATH. Calculate length in bytes of FILE_PATH
  938. // and add that in.
  939. //
  940. requiredLength = ALIGN_UP(requiredLength, ULONG);
  941. bootPathOffset = requiredLength;
  942. requiredLength += OldBootEntry->BootFilePath->Length;
  943. bootPathLength = requiredLength - bootPathOffset;
  944. //
  945. // Allocate memory for the boot entry.
  946. //
  947. newBootEntry = (PMY_BOOT_ENTRY)(MemAlloc(requiredLength));
  948. ASSERT(newBootEntry != NULL);
  949. RtlZeroMemory(newBootEntry, requiredLength);
  950. //
  951. // Calculate addresses of various substructures using the saved offsets.
  952. //
  953. ntBootEntry = &newBootEntry->NtBootEntry;
  954. osOptions = (PWINDOWS_OS_OPTIONS)ntBootEntry->OsOptions;
  955. osLoadPath = (PFILE_PATH)((PUCHAR)newBootEntry + osLoadPathOffset);
  956. friendlyName = (PWSTR)((PUCHAR)newBootEntry + friendlyNameOffset);
  957. bootPath = (PFILE_PATH)((PUCHAR)newBootEntry + bootPathOffset);
  958. //
  959. // Fill in the internal-format structure.
  960. //
  961. newBootEntry->AllocationEnd = (PUCHAR)newBootEntry + requiredLength;
  962. newBootEntry->Status = OldBootEntry->Status & MBE_STATUS_IS_NT;
  963. newBootEntry->Attributes = OldBootEntry->Attributes;
  964. newBootEntry->Id = OldBootEntry->Id;
  965. newBootEntry->FriendlyName = friendlyName;
  966. newBootEntry->FriendlyNameLength = friendlyNameLength;
  967. newBootEntry->BootFilePath = bootPath;
  968. if ( MBE_IS_NT( OldBootEntry ) ) {
  969. newBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  970. newBootEntry->OsLoadOptionsLength = osLoadOptionsLength;
  971. newBootEntry->OsFilePath = osLoadPath;
  972. }
  973. //
  974. // Fill in the base part of the NT boot entry.
  975. //
  976. ntBootEntry->Version = BOOT_ENTRY_VERSION;
  977. ntBootEntry->Length = requiredLength - FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  978. ntBootEntry->Attributes = OldBootEntry->Attributes;
  979. ntBootEntry->Id = OldBootEntry->Id;
  980. ntBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)friendlyName - (PUCHAR)ntBootEntry);
  981. ntBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)bootPath - (PUCHAR)ntBootEntry);
  982. ntBootEntry->OsOptionsLength = osOptionsLength;
  983. if ( MBE_IS_NT( OldBootEntry ) ) {
  984. //
  985. // Fill in the base part of the WINDOWS_OS_OPTIONS, including the
  986. // OsLoadOptions.
  987. //
  988. strcpy((char *)osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  989. osOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  990. osOptions->Length = osOptionsLength;
  991. osOptions->OsLoadPathOffset = (ULONG)((PUCHAR)osLoadPath - (PUCHAR)osOptions);
  992. wcscpy(osOptions->OsLoadOptions, OldBootEntry->OsLoadOptions);
  993. //
  994. // Copy the OS FILE_PATH.
  995. //
  996. memcpy( osLoadPath, OldBootEntry->OsFilePath, osLoadPathLength );
  997. } else {
  998. //
  999. // Copy the foreign OS options.
  1000. //
  1001. memcpy( osOptions, OldBootEntry->ForeignOsOptions, osOptionsLength );
  1002. }
  1003. //
  1004. // Copy the friendly name.
  1005. //
  1006. wcscpy(friendlyName, OldBootEntry->FriendlyName);
  1007. //
  1008. // Copy the boot FILE_PATH.
  1009. //
  1010. memcpy( bootPath, OldBootEntry->BootFilePath, bootPathLength );
  1011. return newBootEntry;
  1012. } // CreateBootEntryFromBootEntry
  1013. VOID
  1014. FreeBootEntry (
  1015. IN PMY_BOOT_ENTRY BootEntry
  1016. )
  1017. {
  1018. FREE_IF_SEPARATE_ALLOCATION( BootEntry, FriendlyName );
  1019. FREE_IF_SEPARATE_ALLOCATION( BootEntry, OsLoadOptions );
  1020. FREE_IF_SEPARATE_ALLOCATION( BootEntry, BootFilePath );
  1021. FREE_IF_SEPARATE_ALLOCATION( BootEntry, OsFilePath );
  1022. MemFree( BootEntry );
  1023. return;
  1024. } // FreeBootEntry
  1025. VOID
  1026. InitializeEfi (
  1027. VOID
  1028. )
  1029. {
  1030. DWORD error;
  1031. NTSTATUS status;
  1032. BOOLEAN wasEnabled;
  1033. HMODULE h;
  1034. WCHAR dllName[MAX_PATH];
  1035. ULONG length;
  1036. HKEY key;
  1037. DWORD type;
  1038. PBOOT_ENTRY_LIST ntBootEntries;
  1039. ULONG i;
  1040. PLIST_ENTRY listEntry;
  1041. PMY_BOOT_ENTRY bootEntry;
  1042. //
  1043. // Enable the privilege that is necessary to query/set NVRAM.
  1044. //
  1045. status = RtlAdjustPrivilege(
  1046. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  1047. TRUE,
  1048. FALSE,
  1049. &wasEnabled
  1050. );
  1051. if ( !NT_SUCCESS(status) ) {
  1052. error = RtlNtStatusToDosError( status );
  1053. FatalError(error , L"Insufficient privilege.\n" );
  1054. }
  1055. //
  1056. // Get the NT name of the system partition from the registry.
  1057. //
  1058. error = RegOpenKey( HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), &key );
  1059. if ( error != ERROR_SUCCESS ) {
  1060. FatalError( error, L"Unable to read SystemPartition registry value: %d\n", error );
  1061. }
  1062. error = RegQueryValueEx( key, TEXT("SystemPartition"), NULL, &type, NULL, &length );
  1063. if ( error != ERROR_SUCCESS ) {
  1064. FatalError( error, L"Unable to read SystemPartition registry value: %d\n", error );
  1065. }
  1066. if ( type != REG_SZ ) {
  1067. FatalError(
  1068. ERROR_INVALID_PARAMETER,
  1069. L"Unable to read SystemPartition registry value: wrong type\n"
  1070. );
  1071. }
  1072. SystemPartitionNtName = (PWSTR)(MemAlloc( length ));
  1073. error = RegQueryValueEx(
  1074. key,
  1075. TEXT("SystemPartition"),
  1076. NULL,
  1077. &type,
  1078. (PBYTE)SystemPartitionNtName,
  1079. &length
  1080. );
  1081. if ( error != ERROR_SUCCESS ) {
  1082. FatalError( error, L"Unable to read SystemPartition registry value: %d\n", error );
  1083. }
  1084. RegCloseKey( key );
  1085. //
  1086. // Load ntdll.dll from the system directory.
  1087. //
  1088. GetSystemDirectory( dllName, MAX_PATH );
  1089. ConcatenatePaths( dllName, TEXT("ntdll.dll"), MAX_PATH );
  1090. h = LoadLibrary( dllName );
  1091. if ( h == NULL ) {
  1092. error = GetLastError();
  1093. FatalError( error, L"Can't load NTDLL.DLL: %d\n", error );
  1094. }
  1095. //
  1096. // Get the addresses of the NVRAM APIs that we need to use. If any of
  1097. // these APIs are not available, this must be a pre-EFI NVRAM build.
  1098. //
  1099. AddBootEntry = (NTSTATUS (__stdcall *)(PBOOT_ENTRY,PULONG))GetProcAddress( h, "NtAddBootEntry" );
  1100. DeleteBootEntry = (NTSTATUS (__stdcall *)(ULONG))GetProcAddress( h, "NtDeleteBootEntry" );
  1101. ModifyBootEntry = (NTSTATUS (__stdcall *)(PBOOT_ENTRY))GetProcAddress( h, "NtModifyBootEntry" );
  1102. EnumerateBootEntries = (NTSTATUS (__stdcall *)(PVOID,PULONG))GetProcAddress( h, "NtEnumerateBootEntries" );
  1103. QueryBootEntryOrder = (NTSTATUS (__stdcall *)(PULONG,PULONG))GetProcAddress( h, "NtQueryBootEntryOrder" );
  1104. SetBootEntryOrder = (NTSTATUS (__stdcall *)(PULONG,ULONG))GetProcAddress( h, "NtSetBootEntryOrder" );
  1105. QueryBootOptions = (NTSTATUS (__stdcall *)(PBOOT_OPTIONS,PULONG))GetProcAddress( h, "NtQueryBootOptions" );
  1106. SetBootOptions = (NTSTATUS (__stdcall *)(PBOOT_OPTIONS,ULONG))GetProcAddress( h, "NtSetBootOptions" );
  1107. TranslateFilePath = (NTSTATUS (__stdcall *)(PFILE_PATH,ULONG,PFILE_PATH,PULONG))GetProcAddress( h, "NtTranslateFilePath" );
  1108. if ( (AddBootEntry == NULL) ||
  1109. (DeleteBootEntry == NULL) ||
  1110. (ModifyBootEntry == NULL) ||
  1111. (EnumerateBootEntries == NULL) ||
  1112. (QueryBootEntryOrder == NULL) ||
  1113. (SetBootEntryOrder == NULL) ||
  1114. (QueryBootOptions == NULL) ||
  1115. (SetBootOptions == NULL) ||
  1116. (TranslateFilePath == NULL) ) {
  1117. FatalError( ERROR_OLD_WIN_VERSION, L"This build does not support EFI NVRAM\n" );
  1118. }
  1119. //
  1120. // Get the global system boot options. If the call fails with
  1121. // STATUS_NOT_IMPLEMENTED, this is not an EFI machine.
  1122. //
  1123. length = 0;
  1124. status = QueryBootOptions( NULL, &length );
  1125. if ( status == STATUS_NOT_IMPLEMENTED ) {
  1126. FatalError( ERROR_OLD_WIN_VERSION, L"This build does not support EFI NVRAM\n" );
  1127. }
  1128. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  1129. error = RtlNtStatusToDosError( status );
  1130. FatalError( error, L"Unexpected error from NtQueryBootOptions: 0x%x\n", status );
  1131. }
  1132. BootOptions = (PBOOT_OPTIONS)(MemAlloc( length ));
  1133. OriginalBootOptions = (PBOOT_OPTIONS)(MemAlloc( length ));
  1134. status = QueryBootOptions( BootOptions, &length );
  1135. if ( status != STATUS_SUCCESS ) {
  1136. error = RtlNtStatusToDosError( status );
  1137. FatalError( error, L"Unexpected error from NtQueryBootOptions: 0x%x\n", status );
  1138. }
  1139. memcpy( OriginalBootOptions, BootOptions, length );
  1140. BootOptionsLength = length;
  1141. OriginalBootOptionsLength = length;
  1142. //
  1143. // Get the system boot order list.
  1144. //
  1145. length = 0;
  1146. status = QueryBootEntryOrder( NULL, &length );
  1147. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  1148. if ( status == STATUS_SUCCESS ) {
  1149. length = 0;
  1150. } else {
  1151. error = RtlNtStatusToDosError( status );
  1152. FatalError( error, L"Unexpected error from NtQueryBootEntryOrder: 0x%x\n", status );
  1153. }
  1154. }
  1155. if ( length != 0 ) {
  1156. BootEntryOrder = (PULONG)(MemAlloc( length * sizeof(ULONG) ));
  1157. OriginalBootEntryOrder = (PULONG)(MemAlloc( length * sizeof(ULONG) ));
  1158. status = QueryBootEntryOrder( BootEntryOrder, &length );
  1159. if ( status != STATUS_SUCCESS ) {
  1160. error = RtlNtStatusToDosError( status );
  1161. FatalError( error, L"Unexpected error from NtQueryBootEntryOrder: 0x%x\n", status );
  1162. }
  1163. memcpy( OriginalBootEntryOrder, BootEntryOrder, length * sizeof(ULONG) );
  1164. }
  1165. BootEntryOrderCount = length;
  1166. OriginalBootEntryOrderCount = length;
  1167. //
  1168. // Get all existing boot entries.
  1169. //
  1170. length = 0;
  1171. status = EnumerateBootEntries( NULL, &length );
  1172. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  1173. if ( status == STATUS_SUCCESS ) {
  1174. length = 0;
  1175. } else {
  1176. error = RtlNtStatusToDosError( status );
  1177. FatalError( error, L"Unexpected error from NtEnumerateBootEntries: 0x%x\n", status );
  1178. }
  1179. }
  1180. InitializeListHead( &BootEntries );
  1181. InitializeListHead( &DeletedBootEntries );
  1182. InitializeListHead( &ActiveUnorderedBootEntries );
  1183. InitializeListHead( &InactiveUnorderedBootEntries );
  1184. if ( length != 0 ) {
  1185. ntBootEntries = (PBOOT_ENTRY_LIST)(MemAlloc( length ));
  1186. status = EnumerateBootEntries( ntBootEntries, &length );
  1187. if ( status != STATUS_SUCCESS ) {
  1188. error = RtlNtStatusToDosError( status );
  1189. FatalError( error, L"Unexpected error from NtEnumerateBootEntries: 0x%x\n", status );
  1190. }
  1191. //
  1192. // Convert the boot entries into an internal representation.
  1193. //
  1194. ConvertBootEntries( ntBootEntries );
  1195. //
  1196. // Free the enumeration buffer.
  1197. //
  1198. MemFree( ntBootEntries );
  1199. }
  1200. //
  1201. // Build the ordered boot entry list.
  1202. //
  1203. for ( i = 0; i < BootEntryOrderCount; i++ ) {
  1204. ULONG id = BootEntryOrder[i];
  1205. for ( listEntry = ActiveUnorderedBootEntries.Flink;
  1206. listEntry != &ActiveUnorderedBootEntries;
  1207. listEntry = listEntry->Flink ) {
  1208. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  1209. if ( bootEntry->Id == id ) {
  1210. listEntry = listEntry->Blink;
  1211. RemoveEntryList( &bootEntry->ListEntry );
  1212. InsertTailList( &BootEntries, &bootEntry->ListEntry );
  1213. bootEntry->ListHead = &BootEntries;
  1214. }
  1215. }
  1216. for ( listEntry = InactiveUnorderedBootEntries.Flink;
  1217. listEntry != &InactiveUnorderedBootEntries;
  1218. listEntry = listEntry->Flink ) {
  1219. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  1220. if ( bootEntry->Id == id ) {
  1221. listEntry = listEntry->Blink;
  1222. RemoveEntryList( &bootEntry->ListEntry );
  1223. InsertTailList( &BootEntries, &bootEntry->ListEntry );
  1224. bootEntry->ListHead = &BootEntries;
  1225. }
  1226. }
  1227. }
  1228. return;
  1229. } // InitializeEfi
  1230. PMY_BOOT_ENTRY
  1231. SaveChanges (
  1232. PMY_BOOT_ENTRY CurrentBootEntry
  1233. )
  1234. {
  1235. NTSTATUS status;
  1236. DWORD error;
  1237. PLIST_ENTRY listHeads[4];
  1238. PLIST_ENTRY listHead;
  1239. PLIST_ENTRY listEntry;
  1240. ULONG list;
  1241. PMY_BOOT_ENTRY bootEntry;
  1242. PMY_BOOT_ENTRY newBootEntry;
  1243. PMY_BOOT_ENTRY newCurrentBootEntry;
  1244. ULONG count;
  1245. //SetStatusLine( L"Saving changes..." );
  1246. //
  1247. // Walk the three lists, updating boot entries in NVRAM.
  1248. //
  1249. newCurrentBootEntry = CurrentBootEntry;
  1250. listHeads[0] = &DeletedBootEntries;
  1251. listHeads[1] = &InactiveUnorderedBootEntries;
  1252. listHeads[2] = &ActiveUnorderedBootEntries;
  1253. listHeads[3] = &BootEntries;
  1254. for ( list = 0; list < 4; list++ ) {
  1255. listHead = listHeads[list];
  1256. for ( listEntry = listHead->Flink; listEntry != listHead; listEntry = listEntry->Flink ) {
  1257. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  1258. //
  1259. // Check first for deleted entries, then for new entries, and
  1260. // finally for modified entries.
  1261. //
  1262. if ( MBE_IS_DELETED( bootEntry ) ) {
  1263. //
  1264. // If it's also marked as new, it's not in NVRAM, so there's
  1265. // nothing to delete.
  1266. //
  1267. if ( !MBE_IS_NEW( bootEntry ) ) {
  1268. status = DeleteBootEntry( bootEntry->Id );
  1269. if ( !NT_SUCCESS(status) ) {
  1270. if ( status != STATUS_VARIABLE_NOT_FOUND ) {
  1271. error = RtlNtStatusToDosError( status );
  1272. FatalError( error, L"Unable to delete boot entry: 0x%x\n", status );
  1273. }
  1274. }
  1275. }
  1276. //
  1277. // Delete this entry from the list and from memory.
  1278. //
  1279. listEntry = listEntry->Blink;
  1280. RemoveEntryList( &bootEntry->ListEntry );
  1281. FreeBootEntry( bootEntry );
  1282. ASSERT( bootEntry != CurrentBootEntry );
  1283. } else if ( MBE_IS_NEW( bootEntry ) ) {
  1284. //
  1285. // We don't support this yet.
  1286. //
  1287. FatalError(
  1288. ERROR_GEN_FAILURE,
  1289. L"How did we end up in SaveChanges with a NEW boot entry?!?\n"
  1290. );
  1291. } else if ( MBE_IS_MODIFIED( bootEntry ) ) {
  1292. //
  1293. // Create a new boot entry structure using the existing one.
  1294. // This is necessary to make an NT BOOT_ENTRY that can be
  1295. // passed to NtModifyBootEntry.
  1296. //
  1297. newBootEntry = CreateBootEntryFromBootEntry( bootEntry );
  1298. status = ModifyBootEntry( &newBootEntry->NtBootEntry );
  1299. if ( !NT_SUCCESS(status) ) {
  1300. error = RtlNtStatusToDosError( status );
  1301. FatalError( error, L"Unable to modify boot entry: 0x%x\n", status );
  1302. }
  1303. //
  1304. // Insert the new boot entry in place of the existing one.
  1305. // Free the old one.
  1306. //
  1307. InsertHeadList( &bootEntry->ListEntry, &newBootEntry->ListEntry );
  1308. RemoveEntryList( &bootEntry->ListEntry );
  1309. FreeBootEntry( bootEntry );
  1310. if ( bootEntry == CurrentBootEntry ) {
  1311. newCurrentBootEntry = newBootEntry;
  1312. }
  1313. }
  1314. }
  1315. }
  1316. //
  1317. // Build and write the new boot entry order list.
  1318. //
  1319. listHead = &BootEntries;
  1320. count = 0;
  1321. for ( listEntry = listHead->Flink; listEntry != listHead; listEntry = listEntry->Flink ) {
  1322. count++;
  1323. }
  1324. MemFree( BootEntryOrder );
  1325. BootEntryOrder = (PULONG)(MemAlloc( count * sizeof(ULONG) ));
  1326. count = 0;
  1327. for ( listEntry = listHead->Flink; listEntry != listHead; listEntry = listEntry->Flink ) {
  1328. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  1329. BootEntryOrder[count++] = bootEntry->Id;
  1330. }
  1331. status = SetBootEntryOrder( BootEntryOrder, count );
  1332. if ( !NT_SUCCESS(status) ) {
  1333. error = RtlNtStatusToDosError( status );
  1334. FatalError( error, L"Unable to set boot entry order: 0x%x\n", status );
  1335. }
  1336. MemFree( OriginalBootEntryOrder );
  1337. OriginalBootEntryOrder = (PULONG)(MemAlloc( count * sizeof(ULONG) ));
  1338. memcpy( OriginalBootEntryOrder, BootEntryOrder, count * sizeof(ULONG) );
  1339. //
  1340. // Write the new timeout.
  1341. //
  1342. status = SetBootOptions( BootOptions, BOOT_OPTIONS_FIELD_TIMEOUT );
  1343. if ( !NT_SUCCESS(status) ) {
  1344. error = RtlNtStatusToDosError( status );
  1345. FatalError( error, L"Unable to set boot options: 0x%x\n", status );
  1346. }
  1347. MemFree( OriginalBootOptions );
  1348. OriginalBootOptions = (PBOOT_OPTIONS)(MemAlloc( BootOptionsLength ));
  1349. memcpy( OriginalBootOptions, BootOptions, BootOptionsLength );
  1350. OriginalBootOptionsLength = BootOptionsLength;
  1351. return newCurrentBootEntry;
  1352. } // SaveChanges
  1353. PWSTR
  1354. GetNtNameForFilePath (
  1355. IN PFILE_PATH FilePath
  1356. )
  1357. {
  1358. NTSTATUS status;
  1359. ULONG length;
  1360. PFILE_PATH ntPath;
  1361. PWSTR osDeviceNtName;
  1362. PWSTR osDirectoryNtName;
  1363. PWSTR fullNtName;
  1364. length = 0;
  1365. status = TranslateFilePath(
  1366. FilePath,
  1367. FILE_PATH_TYPE_NT,
  1368. NULL,
  1369. &length
  1370. );
  1371. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  1372. return NULL;
  1373. }
  1374. ntPath = (PFILE_PATH)(MemAlloc( length ));
  1375. status = TranslateFilePath(
  1376. FilePath,
  1377. FILE_PATH_TYPE_NT,
  1378. ntPath,
  1379. &length
  1380. );
  1381. if ( !NT_SUCCESS(status) ) {
  1382. MemFree( ntPath );
  1383. return NULL;
  1384. }
  1385. osDeviceNtName = (PWSTR)ntPath->FilePath;
  1386. osDirectoryNtName = osDeviceNtName + wcslen(osDeviceNtName) + 1;
  1387. length = (ULONG)(wcslen(osDeviceNtName) + wcslen(osDirectoryNtName) + 1) * sizeof(WCHAR);
  1388. fullNtName = (PWSTR)(MemAlloc( length ));
  1389. wcscpy( fullNtName, osDeviceNtName );
  1390. wcscat( fullNtName, osDirectoryNtName );
  1391. MemFree( ntPath );
  1392. return fullNtName;
  1393. } // GetNtNameForFilePath