Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

903 lines
21 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. uninst.c
  5. Abstract:
  6. Implements the code to launch the uninstall.
  7. Author:
  8. Jim Schmidt (jimschm) 28-Nov-2000
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. #include "undop.h"
  13. #include "resource.h"
  14. //
  15. // Types
  16. //
  17. typedef enum {
  18. BACKUP_DOESNT_EXIST,
  19. BACKUP_IN_PROGRESS,
  20. BACKUP_SKIPPED_BY_USER,
  21. BACKUP_COMPLETE
  22. } JOURNALSTATUS;
  23. //
  24. // Global Variables
  25. //
  26. DRIVELETTERS g_DriveLetters;
  27. TCHAR g_BootDrv = UNKNOWN_DRIVE;
  28. #define WMX_STOP (WM_APP+96)
  29. //
  30. // Code
  31. //
  32. VOID
  33. pAddSifEntry (
  34. IN HINF Inf,
  35. IN PINFSECTION Section,
  36. IN PCTSTR Key,
  37. IN PCTSTR Data
  38. )
  39. {
  40. PTSTR quotedData;
  41. quotedData = AllocText (CharCount (Data) + 2);
  42. wsprintf (quotedData, TEXT("\"%s\""), Data);
  43. AddInfLineToTable (Inf, Section, Key, quotedData, 0);
  44. FreeText (quotedData);
  45. }
  46. BOOL
  47. pEnablePrivilege(
  48. IN PTSTR PrivilegeName,
  49. IN BOOL Enable
  50. )
  51. {
  52. HANDLE Token;
  53. BOOL b;
  54. TOKEN_PRIVILEGES NewPrivileges;
  55. LUID Luid;
  56. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
  57. return(FALSE);
  58. }
  59. if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  60. CloseHandle(Token);
  61. return(FALSE);
  62. }
  63. NewPrivileges.PrivilegeCount = 1;
  64. NewPrivileges.Privileges[0].Luid = Luid;
  65. NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  66. b = AdjustTokenPrivileges(
  67. Token,
  68. FALSE,
  69. &NewPrivileges,
  70. 0,
  71. NULL,
  72. NULL
  73. );
  74. CloseHandle(Token);
  75. return(b);
  76. }
  77. VOID
  78. pWriteDrvLtrFiles (
  79. VOID
  80. )
  81. {
  82. BOOL rf = TRUE;
  83. DWORD index;
  84. HANDLE signatureFile;
  85. TCHAR signatureFilePath[MAX_PATH * 2];
  86. DWORD signatureFilePathLength;
  87. DWORD bytesWritten;
  88. InitializeDriveLetterStructure (&g_DriveLetters);
  89. //
  90. // Hard drive information is actually written to a special signature file
  91. // on the root directory of each fixed hard drive. The information is
  92. // nothing special -- just the drive number (0 = A, etc.)
  93. //
  94. lstrcpy (signatureFilePath,TEXT("*:\\$DRVLTR$.~_~"));
  95. signatureFilePathLength = lstrlen(signatureFilePath);
  96. for (index = 0; index < NUMDRIVELETTERS; index++) {
  97. if (g_DriveLetters.ExistsOnSystem[index] &&
  98. g_DriveLetters.Type[index] == DRIVE_FIXED) {
  99. *signatureFilePath = (TCHAR) index + TEXT('A');
  100. signatureFile = CreateFile(
  101. signatureFilePath,
  102. GENERIC_WRITE | GENERIC_READ,
  103. 0,
  104. NULL,
  105. CREATE_ALWAYS,
  106. FILE_ATTRIBUTE_HIDDEN,
  107. NULL
  108. );
  109. if (signatureFile != INVALID_HANDLE_VALUE) {
  110. WriteFile (signatureFile, &index, sizeof(DWORD), &bytesWritten, NULL);
  111. CloseHandle (signatureFile);
  112. }
  113. }
  114. }
  115. }
  116. VOID
  117. pAppendSystemRestore (
  118. IN HANDLE FileHandle,
  119. IN PCWSTR SystemGuid
  120. )
  121. {
  122. INT index;
  123. WCHAR outputStr[MAX_PATH];
  124. DWORD dontCare;
  125. DEBUGMSG ((DBG_VERBOSE, "Enumerating sr drives"));
  126. for (index = 0; index < NUMDRIVELETTERS; index++) {
  127. if (g_DriveLetters.ExistsOnSystem[index] &&
  128. g_DriveLetters.Type[index] == DRIVE_FIXED
  129. ) {
  130. wsprintfW (
  131. outputStr,
  132. L"%c:\\System Volume Information\\_restore%s\r\n",
  133. (WCHAR) index + L'A',
  134. SystemGuid
  135. );
  136. DEBUGMSGW ((DBG_VERBOSE, "Adding %s to deldirs.txt file", outputStr));
  137. SetFilePointer (FileHandle, 0, NULL, FILE_END);
  138. WriteFile (FileHandle, outputStr, ByteCountW (outputStr), &dontCare, NULL);
  139. }
  140. }
  141. }
  142. VOID
  143. pAppendSystemRestoreToDelDirs (
  144. IN PCTSTR DelDirsTxtPath
  145. )
  146. {
  147. HANDLE delDirsFile = INVALID_HANDLE_VALUE;
  148. HKEY key = NULL;
  149. PCWSTR data = NULL;
  150. __try {
  151. key = OpenRegKeyStr (TEXT("HKLM\\System\\CurrentControlSet\\Services\\sr\\Parameters"));
  152. if (!key) {
  153. DEBUGMSG ((DBG_ERROR, "Can't open SR Parameters key"));
  154. __leave;
  155. }
  156. data = GetRegValueStringW (key, L"MachineGuid");
  157. if (!data) {
  158. DEBUGMSG ((DBG_ERROR, "Can't get SR MachineGuid"));
  159. __leave;
  160. }
  161. delDirsFile = CreateFile (
  162. DelDirsTxtPath,
  163. GENERIC_WRITE,
  164. 0,
  165. NULL,
  166. OPEN_EXISTING,
  167. FILE_ATTRIBUTE_NORMAL,
  168. NULL
  169. );
  170. if (delDirsFile == INVALID_HANDLE_VALUE) {
  171. DEBUGMSG ((DBG_ERROR, "Can't open %s for writing", DelDirsTxtPath));
  172. __leave;
  173. }
  174. pAppendSystemRestore (delDirsFile, data);
  175. }
  176. __finally {
  177. if (delDirsFile != INVALID_HANDLE_VALUE) {
  178. CloseHandle (delDirsFile);
  179. }
  180. if (data) {
  181. FreeMem (data);
  182. }
  183. if (key) {
  184. CloseRegKey (key);
  185. }
  186. }
  187. }
  188. BOOL
  189. WINAPI
  190. pCabNotificationSeekForDrive(
  191. IN PCTSTR FileName
  192. )
  193. {
  194. if(!FileName){
  195. MYASSERT(FALSE);
  196. return FALSE;
  197. }
  198. MYASSERT(UNKNOWN_DRIVE == g_BootDrv);
  199. g_BootDrv = (TCHAR)FileName[0];
  200. return -1;
  201. }
  202. BOOL
  203. GetBootDrive(
  204. IN PCTSTR BackUpPath,
  205. IN PCTSTR Path
  206. )
  207. {
  208. OCABHANDLE cabHandle;
  209. if(UNKNOWN_DRIVE != g_BootDrv){
  210. return TRUE;
  211. }
  212. cabHandle = CabOpenCabinet (Path);
  213. if (cabHandle) {
  214. SetCurrentDirectory (BackUpPath);
  215. CabExtractAllFilesEx (
  216. cabHandle,
  217. NULL,
  218. (PCABNOTIFICATIONW)pCabNotificationSeekForDrive);
  219. CabCloseCabinet (cabHandle);
  220. MYASSERT(UNKNOWN_DRIVE != g_BootDrv);
  221. } else {
  222. return FALSE;
  223. }
  224. return TRUE;
  225. }
  226. DWORD
  227. WINAPI
  228. pLongOperationUi (
  229. PVOID DontCare
  230. )
  231. {
  232. HWND h;
  233. RECT parentRect;
  234. MSG msg;
  235. TCHAR textBuf[256];
  236. HKEY key;
  237. LONG rc;
  238. DWORD size;
  239. HFONT font;
  240. HDC hdc;
  241. LOGFONT lf;
  242. SIZE textSize;
  243. RECT rect;
  244. HWND parent;
  245. TCHAR title[128];
  246. //
  247. // Get dialog title
  248. //
  249. if (!LoadString (g_hInst, IDS_TITLE, title, ARRAYSIZE(title))) {
  250. return 0;
  251. }
  252. //
  253. // Get display text
  254. //
  255. key = OpenRegKeyStr (S_WIN9XUPG_KEY);
  256. if (!key) {
  257. return 0;
  258. }
  259. size = sizeof (textBuf);
  260. rc = RegQueryValueEx (key, S_UNINSTALL_DISP_STR, NULL, NULL, (PBYTE) textBuf, &size);
  261. CloseRegKey (key);
  262. if (rc != ERROR_SUCCESS) {
  263. return 0;
  264. }
  265. //
  266. // Create font object and compute width/height
  267. //
  268. hdc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);
  269. ZeroMemory (&lf, sizeof (lf));
  270. lf.lfHeight = -MulDiv (9, GetDeviceCaps (hdc, LOGPIXELSY), 72);
  271. StringCopy (lf.lfFaceName, TEXT("MS Shell Dlg"));
  272. font = CreateFontIndirect (&lf);
  273. SelectObject (hdc, font);
  274. GetTextExtentPoint32 (hdc, textBuf, TcharCount (textBuf), &textSize);
  275. DeleteDC (hdc);
  276. //
  277. // Compute window position
  278. //
  279. GetWindowRect (GetDesktopWindow(), &parentRect);
  280. rect.left = (parentRect.right - parentRect.left) / 2;
  281. rect.right = rect.left;
  282. rect.left -= textSize.cx * 2;
  283. rect.right += textSize.cx * 2;
  284. rect.top = (parentRect.bottom - parentRect.top) / 2;
  285. rect.bottom = rect.top;
  286. rect.top -= textSize.cy * 4;
  287. rect.bottom += textSize.cy * 4;
  288. parent = CreateWindow (
  289. TEXT("STATIC"),
  290. title,
  291. WS_OVERLAPPED|WS_BORDER|WS_CAPTION|SS_WHITERECT,
  292. rect.left,
  293. rect.top,
  294. rect.right - rect.left,
  295. rect.bottom - rect.top,
  296. NULL,
  297. NULL,
  298. g_hInst,
  299. NULL
  300. );
  301. //
  302. // Create static control
  303. //
  304. GetClientRect (parent, &rect);
  305. //
  306. // Create window & let it run until verify is done
  307. //
  308. h = CreateWindow (
  309. TEXT("STATIC"),
  310. textBuf,
  311. WS_CHILD|SS_CENTER|SS_CENTERIMAGE,
  312. rect.left,
  313. rect.top,
  314. rect.right - rect.left,
  315. rect.bottom - rect.top,
  316. parent,
  317. NULL,
  318. g_hInst,
  319. NULL
  320. );
  321. SendMessage (h, WM_SETFONT, (WPARAM) font, 0);
  322. ShowWindow (parent, SW_SHOW);
  323. ShowWindow (h, SW_SHOW);
  324. UpdateWindow (parent);
  325. while (GetMessage (&msg, NULL, 0, 0)) {
  326. if (msg.message == WMX_STOP) {
  327. DestroyWindow (parent);
  328. break;
  329. }
  330. TranslateMessage (&msg);
  331. DispatchMessage (&msg);
  332. }
  333. DeleteObject (font);
  334. return 0;
  335. }
  336. DWORD
  337. pStartLongOperationUi (
  338. VOID
  339. )
  340. {
  341. HANDLE h;
  342. DWORD threadId;
  343. h = CreateThread (
  344. NULL,
  345. 0,
  346. pLongOperationUi,
  347. NULL,
  348. 0,
  349. &threadId
  350. );
  351. if (!h) {
  352. return 0;
  353. }
  354. CloseHandle (h);
  355. return threadId;
  356. }
  357. VOID
  358. pKillLongOperationUi (
  359. IN DWORD ThreadId
  360. )
  361. {
  362. if (ThreadId) {
  363. PostThreadMessage (ThreadId, WMX_STOP, 0, 0);
  364. }
  365. }
  366. BOOL
  367. CheckCabForAllFilesAvailability(
  368. IN PCTSTR CabPath
  369. )
  370. {
  371. OCABHANDLE cabHandle;
  372. BOOL result = FALSE;
  373. DWORD threadId;
  374. threadId = pStartLongOperationUi();
  375. cabHandle = CabOpenCabinet (CabPath);
  376. if (cabHandle) {
  377. result = CabVerifyCabinet (cabHandle);
  378. CabCloseCabinet (cabHandle);
  379. }
  380. pKillLongOperationUi (threadId);
  381. return result;
  382. }
  383. BOOL
  384. DoUninstall (
  385. VOID
  386. )
  387. {
  388. HINF inf = INVALID_HANDLE_VALUE;
  389. PINFSECTION section;
  390. PCTSTR path = NULL;
  391. PCTSTR path2 = NULL;
  392. PCTSTR sifPath = NULL;
  393. TCHAR bootPath[4] = TEXT("?:\\");
  394. BOOL error = TRUE;
  395. OCABHANDLE cabHandle;
  396. PINFLINE infLine;
  397. DWORD attribs;
  398. PCTSTR backUpPath;
  399. PTSTR updatedData;
  400. BOOL cantSave;
  401. TCHAR textModeBootIniEntry[] = TEXT("?:\\$win_nt$.~bt\\bootsect.dat");
  402. TCHAR bootDirPath[MAX_PATH] = TEXT("");
  403. HANDLE fileHandle;
  404. DWORD bytesWritten;
  405. JOURNALSTATUS journalStatus;
  406. BOOL result;
  407. __try {
  408. backUpPath = GetUndoDirPath();
  409. SetCursor (LoadCursor (NULL, IDC_WAIT));
  410. //
  411. // Retrieve directory path of backup directory
  412. //
  413. if(!backUpPath) {
  414. LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to retrieve directory path"));
  415. __leave;
  416. }
  417. //
  418. // Recreate "backup.$$$" with correct content, if file was not in place.
  419. //
  420. path = JoinPaths (backUpPath, TEXT("backup.$$$"));
  421. if(0xffffffff == GetFileAttributes(path)){
  422. MYASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
  423. fileHandle = CreateFile(path,
  424. GENERIC_WRITE,
  425. FILE_SHARE_READ,
  426. NULL,
  427. CREATE_ALWAYS,
  428. FILE_ATTRIBUTE_NORMAL,
  429. NULL);
  430. if(INVALID_HANDLE_VALUE != fileHandle){
  431. journalStatus = BACKUP_COMPLETE;
  432. result = WriteFile(fileHandle,
  433. &journalStatus,
  434. sizeof(journalStatus),
  435. &bytesWritten,
  436. NULL);
  437. CloseHandle(fileHandle);
  438. if(!result){
  439. LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to write to backup.$$$"));
  440. __leave;
  441. }
  442. }
  443. else {
  444. LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to create file backup.$$$"));
  445. __leave;
  446. }
  447. }
  448. FreePathString (path);
  449. //
  450. // Write a drive signature file to each drive
  451. //
  452. pWriteDrvLtrFiles();
  453. //
  454. // Prepare boot path, clean out existing $win_nt$.~bt
  455. // directory
  456. //
  457. path = JoinPaths (backUpPath, TEXT("boot.cab"));
  458. if(GetBootDrive(backUpPath, path)){
  459. bootPath[0] = g_BootDrv;
  460. textModeBootIniEntry[0] = g_BootDrv;
  461. }
  462. else{
  463. LOG ((LOG_WARNING, "Uninstall Cleanup: Unable to open %s", path));
  464. __leave;
  465. }
  466. FreePathString (path);
  467. path = JoinPaths (bootPath, TEXT("$win_nt$.~bt"));
  468. RemoveCompleteDirectory (path);
  469. StringCopy(bootDirPath, path);
  470. FreePathString (path);
  471. path = NULL;
  472. //
  473. // Extract the boot files from the boot.cab
  474. //
  475. path = JoinPaths (backUpPath, TEXT("boot.cab"));
  476. cabHandle = CabOpenCabinet (path);
  477. if (cabHandle) {
  478. SetCurrentDirectory (backUpPath);
  479. CabExtractAllFiles (cabHandle, NULL);
  480. CabCloseCabinet (cabHandle);
  481. } else {
  482. LOG ((LOG_WARNING, "Uninstall Cleanup: Unable to open %s", path));
  483. __leave;
  484. }
  485. //
  486. // Verify the CAB expanded properly
  487. //
  488. FreePathString (path);
  489. path = NULL;
  490. path = JoinPaths (bootPath, TEXT("$win_nt$.~bt"));
  491. if (!DoesFileExist (path)) {
  492. LOG ((LOG_ERROR, "Files did not expand properly or boot.cab is damaged"));
  493. __leave;
  494. }
  495. FreePathString (path);
  496. path = NULL;
  497. path = JoinPaths (backUpPath, S_ROLLBACK_DELFILES_TXT);
  498. if (!DoesFileExist (path)) {
  499. LOG ((LOG_ERROR, "delfiles.txt not found"));
  500. __leave;
  501. }
  502. FreePathString (path);
  503. path = NULL;
  504. path = JoinPaths (backUpPath, S_ROLLBACK_DELDIRS_TXT);
  505. if (!DoesFileExist (path)) {
  506. LOG ((LOG_ERROR, "deldirs.txt not found"));
  507. __leave;
  508. }
  509. FreePathString (path);
  510. path = NULL;
  511. path = JoinPaths (backUpPath, S_ROLLBACK_MKDIRS_TXT);
  512. if (!DoesFileExist (path)) {
  513. LOG ((LOG_ERROR, "mkdirs.txt not found"));
  514. __leave;
  515. }
  516. FreePathString (path);
  517. path = NULL;
  518. path = JoinPaths (backUpPath, S_ROLLBACK_MOVED_TXT);
  519. if (!DoesFileExist (path)) {
  520. LOG ((LOG_ERROR, "moved.txt not found"));
  521. __leave;
  522. }
  523. FreePathString (path);
  524. path = NULL;
  525. //
  526. // Modify winnt.sif so that text mode knows what to do
  527. //
  528. sifPath = JoinPaths (bootPath, TEXT("$win_nt$.~bt\\winnt.sif"));
  529. inf = OpenInfFile (sifPath);
  530. if (inf == INVALID_HANDLE_VALUE) {
  531. LOG ((LOG_ERROR, "Can't open %s", sifPath));
  532. __leave;
  533. }
  534. section = FindInfSectionInTable (inf, TEXT("data"));
  535. if (section) {
  536. //
  537. // Write keys to winnt.sif...
  538. //
  539. if (!FindLineInInfSection (inf, section, TEXT("Rollback"))) {
  540. pAddSifEntry (inf, section, TEXT("Rollback"), TEXT("1"));
  541. }
  542. //
  543. // ...change %windir%\setup\uninstall\*.txt to %backuppath%\*.txt
  544. //
  545. // moved.txt
  546. infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_MOVE);
  547. if (infLine) {
  548. DeleteLineInInfSection (inf, infLine);
  549. }
  550. path = JoinPaths (backUpPath, S_ROLLBACK_MOVED_TXT);
  551. pAddSifEntry (inf, section, WINNT_D_ROLLBACK_MOVE, path);
  552. FreePathString (path);
  553. path = NULL;
  554. // delfiles.txt
  555. infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_DELETE);
  556. if (infLine) {
  557. DeleteLineInInfSection (inf, infLine);
  558. }
  559. path = JoinPaths (backUpPath, S_ROLLBACK_DELFILES_TXT);
  560. pAddSifEntry (inf, section, WINNT_D_ROLLBACK_DELETE, path);
  561. FreePathString (path);
  562. path = NULL;
  563. // deldirs.txt
  564. infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_DELETE_DIR);
  565. if (infLine) {
  566. DeleteLineInInfSection (inf, infLine);
  567. }
  568. path = JoinPaths (backUpPath, S_ROLLBACK_DELDIRS_TXT);
  569. pAddSifEntry (inf, section, WINNT_D_ROLLBACK_DELETE_DIR, path);
  570. //
  571. // append System Restore directories to deldirs.txt
  572. //
  573. DEBUGMSG ((DBG_VERBOSE, "Appending SR dirs to %s", path));
  574. pAppendSystemRestoreToDelDirs (path);
  575. FreePathString (path);
  576. path = NULL;
  577. // mkdirs.txt
  578. infLine = FindLineInInfSection (inf, section, S_ROLLBACK_MK_DIRS);
  579. if (infLine) {
  580. DeleteLineInInfSection (inf, infLine);
  581. }
  582. path = JoinPaths (backUpPath, S_ROLLBACK_MKDIRS_TXT);
  583. pAddSifEntry (inf, section, S_ROLLBACK_MK_DIRS, path);
  584. FreePathString (path);
  585. path = NULL;
  586. //
  587. // ...write changed winnt.sif file
  588. //
  589. if (!SaveInfFile (inf, sifPath)) {
  590. LOG ((LOG_ERROR, "Unable to update winnt.sif"));
  591. __leave;
  592. }
  593. //
  594. // clone txtsetup.sif
  595. //
  596. path = JoinPaths (bootPath, TEXT("$win_nt$.~bt\\txtsetup.sif"));
  597. path2 = JoinPaths (bootPath, TEXT("txtsetup.sif"));
  598. SetFileAttributes (path2, FILE_ATTRIBUTE_NORMAL);
  599. if (!CopyFile (path, path2, FALSE)) {
  600. LOG ((LOG_ERROR, "Can't copy %s to %s", path, path2));
  601. __leave;
  602. }
  603. FreePathString (path);
  604. path = NULL;
  605. FreePathString (path2);
  606. path2 = NULL;
  607. } else {
  608. LOG ((LOG_ERROR, "[data] not found in winnt.sif"));
  609. }
  610. CloseInfFile (inf);
  611. FreePathString (sifPath);
  612. sifPath = NULL;
  613. //
  614. // Edit the current boot.ini
  615. //
  616. sifPath = JoinPaths (bootPath, TEXT("boot.ini"));
  617. inf = OpenInfFile (sifPath);
  618. if (inf == INVALID_HANDLE_VALUE) {
  619. LOG ((LOG_ERROR, "Can't open %s", sifPath));
  620. __leave;
  621. }
  622. section = FindInfSectionInTable (inf, TEXT("Operating Systems"));
  623. if (!section) {
  624. LOG ((LOG_ERROR, "[Operating Systems] not found in boot.ini"));
  625. __leave;
  626. }
  627. //
  628. // Add /rollback to textmode entry
  629. //
  630. infLine = FindLineInInfSection (inf, section, textModeBootIniEntry);
  631. if (infLine) {
  632. if(!_tcsistr (infLine->Data, TEXT("/rollback"))){
  633. updatedData = AllocText (TcharCount (infLine->Data) + 10);
  634. StringCopy (updatedData, infLine->Data);
  635. StringCat (updatedData, TEXT(" /rollback"));
  636. AddInfLineToTable (inf, section, infLine->Key, updatedData, infLine->LineFlags);
  637. DeleteLineInInfSection (inf, infLine);
  638. FreeText (updatedData);
  639. }
  640. } else {
  641. updatedData = AllocText (256 + sizeof (TEXT("\" /rollback\"")) / sizeof (TCHAR));
  642. StringCopy (updatedData, TEXT("\""));
  643. if (!LoadString (g_hInst, IDS_TITLE, GetEndOfString (updatedData), 256)) {
  644. DEBUGMSG ((DBG_ERROR, "Can't load boot.ini text"));
  645. __leave;
  646. }
  647. StringCat (updatedData, TEXT("\" /rollback"));
  648. AddInfLineToTable (inf, section, textModeBootIniEntry, updatedData, 0);
  649. FreeText (updatedData);
  650. }
  651. //
  652. // Set timeout to zero and set default
  653. //
  654. section = FindInfSectionInTable (inf, TEXT("boot loader"));
  655. if (!section) {
  656. LOG ((LOG_ERROR, "[Boot Loader] not found in boot.ini"));
  657. __leave;
  658. }
  659. infLine = FindLineInInfSection (inf, section, TEXT("timeout"));
  660. if (infLine) {
  661. DeleteLineInInfSection (inf, infLine);
  662. }
  663. AddInfLineToTable (inf, section, TEXT("timeout"), TEXT("0"), 0);
  664. infLine = FindLineInInfSection (inf, section, TEXT("default"));
  665. if (infLine) {
  666. DeleteLineInInfSection (inf, infLine);
  667. }
  668. AddInfLineToTable (inf, section, TEXT("default"), textModeBootIniEntry, 0);
  669. //
  670. // Save changes
  671. //
  672. attribs = GetFileAttributes (sifPath);
  673. SetFileAttributes (sifPath, FILE_ATTRIBUTE_NORMAL);
  674. cantSave = (SaveInfFile (inf, sifPath) == FALSE);
  675. if (attribs != INVALID_ATTRIBUTES) {
  676. SetFileAttributes (sifPath, attribs);
  677. }
  678. if (cantSave) {
  679. LOG ((LOG_ERROR, "Unable to update boot.ini"));
  680. __leave;
  681. }
  682. //
  683. // Rollback environment is ready to go
  684. //
  685. error = FALSE;
  686. }
  687. __finally {
  688. FreePathString (path);
  689. FreePathString (path2);
  690. FreePathString (sifPath);
  691. if (backUpPath) {
  692. MemFree (g_hHeap, 0, backUpPath);
  693. }
  694. if (inf != INVALID_HANDLE_VALUE) {
  695. CloseInfFile (inf);
  696. }
  697. }
  698. //
  699. // Shutdown on success
  700. //
  701. if (!error) {
  702. pEnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
  703. ExitWindowsEx (EWX_REBOOT, 0);
  704. } else {
  705. RemoveCompleteDirectory (bootDirPath);
  706. return FALSE;
  707. }
  708. return TRUE;
  709. }