|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
uninst.c
Abstract:
Implements the code to launch the uninstall.
Author:
Jim Schmidt (jimschm) 28-Nov-2000
Revision History:
--*/
#include "pch.h"
#include "undop.h"
#include "resource.h"
//
// Types
//
typedef enum { BACKUP_DOESNT_EXIST, BACKUP_IN_PROGRESS, BACKUP_SKIPPED_BY_USER, BACKUP_COMPLETE } JOURNALSTATUS;
//
// Global Variables
//
DRIVELETTERS g_DriveLetters; TCHAR g_BootDrv = UNKNOWN_DRIVE;
#define WMX_STOP (WM_APP+96)
//
// Code
//
VOID pAddSifEntry ( IN HINF Inf, IN PINFSECTION Section, IN PCTSTR Key, IN PCTSTR Data ) { PTSTR quotedData;
quotedData = AllocText (CharCount (Data) + 2); wsprintf (quotedData, TEXT("\"%s\""), Data); AddInfLineToTable (Inf, Section, Key, quotedData, 0); FreeText (quotedData); }
BOOL pEnablePrivilege( IN PTSTR PrivilegeName, IN BOOL Enable ) { HANDLE Token; BOOL b; TOKEN_PRIVILEGES NewPrivileges; LUID Luid;
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) { return(FALSE); }
if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) { CloseHandle(Token); return(FALSE); }
NewPrivileges.PrivilegeCount = 1; NewPrivileges.Privileges[0].Luid = Luid; NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
b = AdjustTokenPrivileges( Token, FALSE, &NewPrivileges, 0, NULL, NULL );
CloseHandle(Token);
return(b); }
VOID pWriteDrvLtrFiles ( VOID ) { BOOL rf = TRUE; DWORD index; HANDLE signatureFile; TCHAR signatureFilePath[MAX_PATH * 2]; DWORD signatureFilePathLength; DWORD bytesWritten;
InitializeDriveLetterStructure (&g_DriveLetters);
//
// Hard drive information is actually written to a special signature file
// on the root directory of each fixed hard drive. The information is
// nothing special -- just the drive number (0 = A, etc.)
//
lstrcpy (signatureFilePath,TEXT("*:\\$DRVLTR$.~_~")); signatureFilePathLength = lstrlen(signatureFilePath);
for (index = 0; index < NUMDRIVELETTERS; index++) {
if (g_DriveLetters.ExistsOnSystem[index] && g_DriveLetters.Type[index] == DRIVE_FIXED) {
*signatureFilePath = (TCHAR) index + TEXT('A');
signatureFile = CreateFile( signatureFilePath, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL );
if (signatureFile != INVALID_HANDLE_VALUE) {
WriteFile (signatureFile, &index, sizeof(DWORD), &bytesWritten, NULL); CloseHandle (signatureFile); } } } }
VOID pAppendSystemRestore ( IN HANDLE FileHandle, IN PCWSTR SystemGuid ) { INT index; WCHAR outputStr[MAX_PATH]; DWORD dontCare;
DEBUGMSG ((DBG_VERBOSE, "Enumerating sr drives"));
for (index = 0; index < NUMDRIVELETTERS; index++) {
if (g_DriveLetters.ExistsOnSystem[index] && g_DriveLetters.Type[index] == DRIVE_FIXED ) { wsprintfW ( outputStr, L"%c:\\System Volume Information\\_restore%s\r\n", (WCHAR) index + L'A', SystemGuid );
DEBUGMSGW ((DBG_VERBOSE, "Adding %s to deldirs.txt file", outputStr)); SetFilePointer (FileHandle, 0, NULL, FILE_END); WriteFile (FileHandle, outputStr, ByteCountW (outputStr), &dontCare, NULL); } } }
VOID pAppendSystemRestoreToDelDirs ( IN PCTSTR DelDirsTxtPath ) { HANDLE delDirsFile = INVALID_HANDLE_VALUE; HKEY key = NULL; PCWSTR data = NULL;
__try { key = OpenRegKeyStr (TEXT("HKLM\\System\\CurrentControlSet\\Services\\sr\\Parameters")); if (!key) { DEBUGMSG ((DBG_ERROR, "Can't open SR Parameters key")); __leave; }
data = GetRegValueStringW (key, L"MachineGuid"); if (!data) { DEBUGMSG ((DBG_ERROR, "Can't get SR MachineGuid")); __leave; }
delDirsFile = CreateFile ( DelDirsTxtPath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (delDirsFile == INVALID_HANDLE_VALUE) { DEBUGMSG ((DBG_ERROR, "Can't open %s for writing", DelDirsTxtPath)); __leave; }
pAppendSystemRestore (delDirsFile, data); } __finally { if (delDirsFile != INVALID_HANDLE_VALUE) { CloseHandle (delDirsFile); }
if (data) { FreeMem (data); }
if (key) { CloseRegKey (key); } } }
BOOL WINAPI pCabNotificationSeekForDrive( IN PCTSTR FileName ) { if(!FileName){ MYASSERT(FALSE); return FALSE; }
MYASSERT(UNKNOWN_DRIVE == g_BootDrv);
g_BootDrv = (TCHAR)FileName[0];
return -1; }
BOOL GetBootDrive( IN PCTSTR BackUpPath, IN PCTSTR Path ) { OCABHANDLE cabHandle;
if(UNKNOWN_DRIVE != g_BootDrv){ return TRUE; }
cabHandle = CabOpenCabinet (Path); if (cabHandle) { SetCurrentDirectory (BackUpPath);
CabExtractAllFilesEx ( cabHandle, NULL, (PCABNOTIFICATIONW)pCabNotificationSeekForDrive);
CabCloseCabinet (cabHandle);
MYASSERT(UNKNOWN_DRIVE != g_BootDrv); } else { return FALSE; }
return TRUE; }
DWORD WINAPI pLongOperationUi ( PVOID DontCare ) { HWND h; RECT parentRect; MSG msg; TCHAR textBuf[256]; HKEY key; LONG rc; DWORD size; HFONT font; HDC hdc; LOGFONT lf; SIZE textSize; RECT rect; HWND parent; TCHAR title[128];
//
// Get dialog title
//
if (!LoadString (g_hInst, IDS_TITLE, title, ARRAYSIZE(title))) { return 0; }
//
// Get display text
//
key = OpenRegKeyStr (S_WIN9XUPG_KEY); if (!key) { return 0; }
size = sizeof (textBuf); rc = RegQueryValueEx (key, S_UNINSTALL_DISP_STR, NULL, NULL, (PBYTE) textBuf, &size);
CloseRegKey (key);
if (rc != ERROR_SUCCESS) { return 0; }
//
// Create font object and compute width/height
//
hdc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);
ZeroMemory (&lf, sizeof (lf)); lf.lfHeight = -MulDiv (9, GetDeviceCaps (hdc, LOGPIXELSY), 72); StringCopy (lf.lfFaceName, TEXT("MS Shell Dlg"));
font = CreateFontIndirect (&lf); SelectObject (hdc, font); GetTextExtentPoint32 (hdc, textBuf, TcharCount (textBuf), &textSize);
DeleteDC (hdc);
//
// Compute window position
//
GetWindowRect (GetDesktopWindow(), &parentRect);
rect.left = (parentRect.right - parentRect.left) / 2; rect.right = rect.left;
rect.left -= textSize.cx * 2; rect.right += textSize.cx * 2;
rect.top = (parentRect.bottom - parentRect.top) / 2; rect.bottom = rect.top;
rect.top -= textSize.cy * 4; rect.bottom += textSize.cy * 4;
parent = CreateWindow ( TEXT("STATIC"), title, WS_OVERLAPPED|WS_BORDER|WS_CAPTION|SS_WHITERECT, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, g_hInst, NULL );
//
// Create static control
//
GetClientRect (parent, &rect);
//
// Create window & let it run until verify is done
//
h = CreateWindow ( TEXT("STATIC"), textBuf, WS_CHILD|SS_CENTER|SS_CENTERIMAGE, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parent, NULL, g_hInst, NULL );
SendMessage (h, WM_SETFONT, (WPARAM) font, 0);
ShowWindow (parent, SW_SHOW); ShowWindow (h, SW_SHOW); UpdateWindow (parent);
while (GetMessage (&msg, NULL, 0, 0)) { if (msg.message == WMX_STOP) { DestroyWindow (parent); break; }
TranslateMessage (&msg); DispatchMessage (&msg); }
DeleteObject (font);
return 0; }
DWORD pStartLongOperationUi ( VOID ) { HANDLE h; DWORD threadId;
h = CreateThread ( NULL, 0, pLongOperationUi, NULL, 0, &threadId );
if (!h) { return 0; }
CloseHandle (h);
return threadId; }
VOID pKillLongOperationUi ( IN DWORD ThreadId ) { if (ThreadId) { PostThreadMessage (ThreadId, WMX_STOP, 0, 0); } }
BOOL CheckCabForAllFilesAvailability( IN PCTSTR CabPath ) { OCABHANDLE cabHandle; BOOL result = FALSE; DWORD threadId;
threadId = pStartLongOperationUi();
cabHandle = CabOpenCabinet (CabPath); if (cabHandle) { result = CabVerifyCabinet (cabHandle); CabCloseCabinet (cabHandle); }
pKillLongOperationUi (threadId);
return result; }
BOOL DoUninstall ( VOID ) { HINF inf = INVALID_HANDLE_VALUE; PINFSECTION section; PCTSTR path = NULL; PCTSTR path2 = NULL; PCTSTR sifPath = NULL; TCHAR bootPath[4] = TEXT("?:\\"); BOOL error = TRUE; OCABHANDLE cabHandle; PINFLINE infLine; DWORD attribs; PCTSTR backUpPath; PTSTR updatedData; BOOL cantSave; TCHAR textModeBootIniEntry[] = TEXT("?:\\$win_nt$.~bt\\bootsect.dat"); TCHAR bootDirPath[MAX_PATH] = TEXT(""); HANDLE fileHandle; DWORD bytesWritten; JOURNALSTATUS journalStatus; BOOL result;
__try { backUpPath = GetUndoDirPath();
SetCursor (LoadCursor (NULL, IDC_WAIT));
//
// Retrieve directory path of backup directory
//
if(!backUpPath) { LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to retrieve directory path")); __leave; }
//
// Recreate "backup.$$$" with correct content, if file was not in place.
//
path = JoinPaths (backUpPath, TEXT("backup.$$$")); if(0xffffffff == GetFileAttributes(path)){ MYASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
fileHandle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE != fileHandle){ journalStatus = BACKUP_COMPLETE; result = WriteFile(fileHandle, &journalStatus, sizeof(journalStatus), &bytesWritten, NULL);
CloseHandle(fileHandle);
if(!result){ LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to write to backup.$$$")); __leave; } } else { LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to create file backup.$$$")); __leave; } } FreePathString (path);
//
// Write a drive signature file to each drive
//
pWriteDrvLtrFiles();
//
// Prepare boot path, clean out existing $win_nt$.~bt
// directory
//
path = JoinPaths (backUpPath, TEXT("boot.cab"));
if(GetBootDrive(backUpPath, path)){ bootPath[0] = g_BootDrv; textModeBootIniEntry[0] = g_BootDrv; } else{ LOG ((LOG_WARNING, "Uninstall Cleanup: Unable to open %s", path)); __leave; } FreePathString (path);
path = JoinPaths (bootPath, TEXT("$win_nt$.~bt")); RemoveCompleteDirectory (path); StringCopy(bootDirPath, path); FreePathString (path); path = NULL;
//
// Extract the boot files from the boot.cab
//
path = JoinPaths (backUpPath, TEXT("boot.cab")); cabHandle = CabOpenCabinet (path);
if (cabHandle) { SetCurrentDirectory (backUpPath); CabExtractAllFiles (cabHandle, NULL); CabCloseCabinet (cabHandle); } else { LOG ((LOG_WARNING, "Uninstall Cleanup: Unable to open %s", path)); __leave; }
//
// Verify the CAB expanded properly
//
FreePathString (path); path = NULL;
path = JoinPaths (bootPath, TEXT("$win_nt$.~bt")); if (!DoesFileExist (path)) { LOG ((LOG_ERROR, "Files did not expand properly or boot.cab is damaged")); __leave; } FreePathString (path); path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_DELFILES_TXT); if (!DoesFileExist (path)) { LOG ((LOG_ERROR, "delfiles.txt not found")); __leave; } FreePathString (path); path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_DELDIRS_TXT); if (!DoesFileExist (path)) { LOG ((LOG_ERROR, "deldirs.txt not found")); __leave; } FreePathString (path); path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_MKDIRS_TXT); if (!DoesFileExist (path)) { LOG ((LOG_ERROR, "mkdirs.txt not found")); __leave; } FreePathString (path); path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_MOVED_TXT); if (!DoesFileExist (path)) { LOG ((LOG_ERROR, "moved.txt not found")); __leave; } FreePathString (path); path = NULL;
//
// Modify winnt.sif so that text mode knows what to do
//
sifPath = JoinPaths (bootPath, TEXT("$win_nt$.~bt\\winnt.sif"));
inf = OpenInfFile (sifPath); if (inf == INVALID_HANDLE_VALUE) { LOG ((LOG_ERROR, "Can't open %s", sifPath)); __leave; }
section = FindInfSectionInTable (inf, TEXT("data"));
if (section) {
//
// Write keys to winnt.sif...
//
if (!FindLineInInfSection (inf, section, TEXT("Rollback"))) { pAddSifEntry (inf, section, TEXT("Rollback"), TEXT("1")); }
//
// ...change %windir%\setup\uninstall\*.txt to %backuppath%\*.txt
//
// moved.txt
infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_MOVE); if (infLine) { DeleteLineInInfSection (inf, infLine); }
path = JoinPaths (backUpPath, S_ROLLBACK_MOVED_TXT); pAddSifEntry (inf, section, WINNT_D_ROLLBACK_MOVE, path); FreePathString (path); path = NULL;
// delfiles.txt
infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_DELETE); if (infLine) { DeleteLineInInfSection (inf, infLine); }
path = JoinPaths (backUpPath, S_ROLLBACK_DELFILES_TXT); pAddSifEntry (inf, section, WINNT_D_ROLLBACK_DELETE, path); FreePathString (path); path = NULL;
// deldirs.txt
infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_DELETE_DIR); if (infLine) { DeleteLineInInfSection (inf, infLine); }
path = JoinPaths (backUpPath, S_ROLLBACK_DELDIRS_TXT); pAddSifEntry (inf, section, WINNT_D_ROLLBACK_DELETE_DIR, path);
//
// append System Restore directories to deldirs.txt
//
DEBUGMSG ((DBG_VERBOSE, "Appending SR dirs to %s", path)); pAppendSystemRestoreToDelDirs (path);
FreePathString (path); path = NULL;
// mkdirs.txt
infLine = FindLineInInfSection (inf, section, S_ROLLBACK_MK_DIRS); if (infLine) { DeleteLineInInfSection (inf, infLine); }
path = JoinPaths (backUpPath, S_ROLLBACK_MKDIRS_TXT); pAddSifEntry (inf, section, S_ROLLBACK_MK_DIRS, path); FreePathString (path); path = NULL;
//
// ...write changed winnt.sif file
//
if (!SaveInfFile (inf, sifPath)) { LOG ((LOG_ERROR, "Unable to update winnt.sif")); __leave; }
//
// clone txtsetup.sif
//
path = JoinPaths (bootPath, TEXT("$win_nt$.~bt\\txtsetup.sif")); path2 = JoinPaths (bootPath, TEXT("txtsetup.sif"));
SetFileAttributes (path2, FILE_ATTRIBUTE_NORMAL); if (!CopyFile (path, path2, FALSE)) { LOG ((LOG_ERROR, "Can't copy %s to %s", path, path2)); __leave; }
FreePathString (path); path = NULL; FreePathString (path2); path2 = NULL;
} else { LOG ((LOG_ERROR, "[data] not found in winnt.sif")); }
CloseInfFile (inf); FreePathString (sifPath); sifPath = NULL;
//
// Edit the current boot.ini
//
sifPath = JoinPaths (bootPath, TEXT("boot.ini"));
inf = OpenInfFile (sifPath); if (inf == INVALID_HANDLE_VALUE) { LOG ((LOG_ERROR, "Can't open %s", sifPath)); __leave; }
section = FindInfSectionInTable (inf, TEXT("Operating Systems"));
if (!section) { LOG ((LOG_ERROR, "[Operating Systems] not found in boot.ini")); __leave; }
//
// Add /rollback to textmode entry
//
infLine = FindLineInInfSection (inf, section, textModeBootIniEntry); if (infLine) { if(!_tcsistr (infLine->Data, TEXT("/rollback"))){ updatedData = AllocText (TcharCount (infLine->Data) + 10);
StringCopy (updatedData, infLine->Data); StringCat (updatedData, TEXT(" /rollback"));
AddInfLineToTable (inf, section, infLine->Key, updatedData, infLine->LineFlags); DeleteLineInInfSection (inf, infLine);
FreeText (updatedData); } } else { updatedData = AllocText (256 + sizeof (TEXT("\" /rollback\"")) / sizeof (TCHAR)); StringCopy (updatedData, TEXT("\""));
if (!LoadString (g_hInst, IDS_TITLE, GetEndOfString (updatedData), 256)) { DEBUGMSG ((DBG_ERROR, "Can't load boot.ini text")); __leave; }
StringCat (updatedData, TEXT("\" /rollback"));
AddInfLineToTable (inf, section, textModeBootIniEntry, updatedData, 0); FreeText (updatedData); }
//
// Set timeout to zero and set default
//
section = FindInfSectionInTable (inf, TEXT("boot loader")); if (!section) { LOG ((LOG_ERROR, "[Boot Loader] not found in boot.ini")); __leave; }
infLine = FindLineInInfSection (inf, section, TEXT("timeout")); if (infLine) { DeleteLineInInfSection (inf, infLine); }
AddInfLineToTable (inf, section, TEXT("timeout"), TEXT("0"), 0);
infLine = FindLineInInfSection (inf, section, TEXT("default")); if (infLine) { DeleteLineInInfSection (inf, infLine); }
AddInfLineToTable (inf, section, TEXT("default"), textModeBootIniEntry, 0);
//
// Save changes
//
attribs = GetFileAttributes (sifPath); SetFileAttributes (sifPath, FILE_ATTRIBUTE_NORMAL);
cantSave = (SaveInfFile (inf, sifPath) == FALSE);
if (attribs != INVALID_ATTRIBUTES) { SetFileAttributes (sifPath, attribs); }
if (cantSave) { LOG ((LOG_ERROR, "Unable to update boot.ini")); __leave; }
//
// Rollback environment is ready to go
//
error = FALSE; } __finally { FreePathString (path); FreePathString (path2); FreePathString (sifPath);
if (backUpPath) { MemFree (g_hHeap, 0, backUpPath); }
if (inf != INVALID_HANDLE_VALUE) { CloseInfFile (inf); } }
//
// Shutdown on success
//
if (!error) { pEnablePrivilege(SE_SHUTDOWN_NAME,TRUE); ExitWindowsEx (EWX_REBOOT, 0); } else { RemoveCompleteDirectory (bootDirPath); return FALSE; }
return TRUE; }
|