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.

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