/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
undoinst.c
Abstract:
This program undoes the actions described by an Installation Modification Log file
created by the INSTALER program
Author:
Steve Wood (stevewo) 15-Jan-1996
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "instutil.h"
#include "iml.h"
BOOLEAN RedoScript;
BOOLEAN VerboseOutput;
int
ProcessUndoIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PINSTALLATION_MODIFICATION_LOGFILE pImlRedo
);
int
_CRTAPI1
main(
int argc,
char *argv[]
)
{
int Result;
char *s;
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo;
PINSTALLATION_MODIFICATION_LOGFILE pImlRedo;
USHORT RedoScriptId;
InitCommonCode( "UNDOINST",
"[-r] [-v]",
"-r replace contents of input .IML file with redo script to undo the undo\n"
"-v verbose output\n"
);
RedoScript = FALSE;
VerboseOutput = FALSE;
while (--argc) {
s = *++argv;
if (*s == '-' || *s == '/') {
while (*++s) {
switch( tolower( *s ) ) {
case 'r':
RedoScript = TRUE;
break;
case 'v':
VerboseOutput = TRUE;
break;
default:
CommonSwitchProcessing( &argc, &argv, *s );
break;
}
}
}
else
if (!CommonArgProcessing( &argc, &argv )) {
Usage( "Arguments not supported - '%s'", (ULONG)s );
}
}
if (ImlPath == NULL) {
Usage( "Must specify an installation name as first argument", 0 );
}
if (!SetCurrentDirectory( InstalerDirectory )) {
FatalError( "Unable to change to '%ws' directory (%u)",
(ULONG)InstalerDirectory,
GetLastError()
);
}
pImlUndo = LoadIml( ImlPath );
if (pImlUndo == NULL) {
FatalError( "Unable to open '%ws' (%u)",
(ULONG)ImlPath,
GetLastError()
);
}
if (RedoScript) {
RedoScriptId = 0;
if (CreateBackupFileName( &RedoScriptId ) == NULL) {
FatalError( "Unable to create temporary file for redo script (%u)\n",
GetLastError(),
0
);
}
pImlRedo = CreateIml( FormatTempFileName( InstalerDirectory, &RedoScriptId ), TRUE );
if (pImlRedo == NULL) {
FatalError( "Unable to create redo script '%ws' (%u)\n",
(ULONG)FormatTempFileName( InstalerDirectory, &RedoScriptId ),
GetLastError()
);
}
}
else {
pImlRedo = NULL;
}
Result = ProcessUndoIml( pImlUndo, pImlRedo );
CloseIml( pImlUndo );
if (pImlRedo != NULL) {
CloseIml( pImlRedo );
if (!MoveFileEx( FormatTempFileName( InstalerDirectory, &RedoScriptId ),
ImlPath,
MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED
)
) {
FatalError( "Unable to rename redo script '%ws' (%u)\n",
(ULONG)FormatTempFileName( InstalerDirectory, &RedoScriptId ),
GetLastError()
);
}
}
exit( Result );
return Result;
}
BOOLEAN
DeleteFileOrDirectory(
PWSTR Name
)
{
DWORD FileAttributes;
FileAttributes = GetFileAttributes( Name );
if (FileAttributes == 0xFFFFFFFF) {
return TRUE;
}
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
return RemoveDirectory( Name );
}
else {
return DeleteFile( Name );
}
}
BOOLEAN
ProcessUndoFileIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PIML_FILE_RECORD pFile
)
{
PIML_FILE_RECORD_CONTENTS pOldFile;
PIML_FILE_RECORD_CONTENTS pNewFile;
USHORT UniqueId = 0;
HANDLE FileHandle;
PWSTR BackupFileName;
DWORD FileAttributes;
DWORD BytesWritten;
pOldFile = MP( PIML_FILE_RECORD_CONTENTS, pImlUndo, pFile->OldFile );
pNewFile = MP( PIML_FILE_RECORD_CONTENTS, pImlUndo, pFile->NewFile );
printf( " %ws - ", MP( PWSTR, pImlUndo, pFile->Name ) );
switch( pFile->Action ) {
case CreateNewFile:
printf( "deleting" );
SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ),
FILE_ATTRIBUTE_NORMAL
);
if (!DeleteFileOrDirectory( MP( PWSTR, pImlUndo, pFile->Name ) )) {
printf( " - error (%u)", GetLastError() );
}
printf( "\n" );
break;
case ModifyOldFile:
case DeleteOldFile:
FileAttributes = GetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ) );
printf( "restoring old file" );
if (FileAttributes != 0xFFFFFFFF) {
SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ),
FILE_ATTRIBUTE_NORMAL
);
BackupFileName = CreateBackupFileName( &UniqueId );
if (BackupFileName == NULL) {
printf( " - unable to find temporary name for restore\n" );
break;
}
else
if (!MoveFile( MP( PWSTR, pImlUndo, pFile->Name ),
BackupFileName
)
) {
printf( " - unable to rename existing to temporary name (%u)\n",
GetLastError()
);
break;
}
}
else {
BackupFileName = NULL;
}
if (pOldFile != NULL) {
if (pOldFile->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (!CreateDirectory( MP( PWSTR, pImlUndo, pFile->Name ), NULL )) {
printf( " - unable to create directory (%u)",
GetLastError()
);
}
}
else {
FileHandle = CreateFile( MP( PWSTR, pImlUndo, pFile->Name ),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_NEW,
0,
NULL
);
if (FileHandle != INVALID_HANDLE_VALUE) {
if (WriteFile( FileHandle,
MP( PVOID, pImlUndo, pOldFile->Contents ),
pOldFile->FileSize,
&BytesWritten,
NULL
) &&
BytesWritten == pOldFile->FileSize
) {
if (!SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ),
pOldFile->FileAttributes
)
) {
printf( " - unable to restore attributes (%u)",
GetLastError()
);
}
else
if (!SetFileTime( FileHandle,
&pOldFile->LastWriteTime,
&pOldFile->LastWriteTime,
&pOldFile->LastWriteTime
)
) {
printf( " - unable to restore last write time (%u)",
GetLastError()
);
}
else
if (BackupFileName != NULL) {
DeleteFile( BackupFileName );
BackupFileName = NULL;
}
}
else {
printf( " - unable to restore contents (%u)",
GetLastError()
);
}
CloseHandle( FileHandle );
}
else {
printf( " - unable to create file (%u)",
GetLastError()
);
}
}
}
else {
printf( " - old contents missing from .IML file" );
}
if (BackupFileName != NULL) {
DeleteFile( MP( PWSTR, pImlUndo, pFile->Name ) );
MoveFile( BackupFileName, MP( PWSTR, pImlUndo, pFile->Name ) );
}
printf( "\n" );
break;
case ModifyFileDateTime:
printf( "restoring date/time\n" );
FileHandle = CreateFile( MP( PWSTR, pImlUndo, pFile->Name ),
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (FileHandle != INVALID_HANDLE_VALUE) {
if (!SetFileTime( FileHandle,
&pOldFile->LastWriteTime,
&pOldFile->LastWriteTime,
&pOldFile->LastWriteTime
)
) {
printf( " - unable to restore last write time (%u)",
GetLastError()
);
}
CloseHandle( FileHandle );
}
else {
printf( " - unable to open file (%u)",
GetLastError()
);
}
break;
case ModifyFileAttributes:
printf( "restoring attributes" );
if (!SetFileAttributes( MP( PWSTR, pImlUndo, pFile->Name ),
pOldFile->FileAttributes
)
) {
printf( " - unable to restore attributes (%u)",
GetLastError()
);
}
printf( "\n" );
break;
}
return TRUE;
}
BOOLEAN
ProcessRedoFileIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PIML_FILE_RECORD pFile,
PINSTALLATION_MODIFICATION_LOGFILE pImlRedo
)
{
HANDLE FindHandle;
WIN32_FIND_DATA FindFileData;
if (pFile->Action == CreateNewFile) {
//
// Created a new file. So do the same in the redo
// script, with the existing contents of the new file
//
ImlAddFileRecord( pImlRedo,
CreateNewFile,
MP( PWSTR, pImlUndo, pFile->Name ),
NULL,
NULL,
0
);
}
else
if (pFile->Action == ModifyOldFile) {
//
// Modified an existing file. Create a similar record
// in the redo script that will hold the new contents
//
ImlAddFileRecord( pImlRedo,
ModifyOldFile,
MP( PWSTR, pImlUndo, pFile->Name ),
NULL,
NULL,
0
);
}
else {
//
// Modified the file attributes and/or date and time. Get the current
// values and save them in the redo script
//
FindHandle = FindFirstFile( MP( PWSTR, pImlUndo, pFile->Name ),
&FindFileData
);
if (FindHandle != INVALID_HANDLE_VALUE) {
ImlAddFileRecord( pImlRedo,
ModifyFileDateTime,
MP( PWSTR, pImlUndo, pFile->Name ),
NULL,
&FindFileData.ftLastWriteTime,
FindFileData.dwFileAttributes
);
FindClose( FindHandle );
}
}
return TRUE;
}
BOOLEAN
ProcessUndoKeyIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PIML_KEY_RECORD pKey
)
{
PIML_VALUE_RECORD pValue;
PIML_VALUE_RECORD_CONTENTS pOldValue;
PIML_VALUE_RECORD_CONTENTS pNewValue;
NTSTATUS Status;
UNICODE_STRING KeyName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
UNICODE_STRING ValueName;
KeyHandle = NULL;
if (pKey->Values != 0 || pKey->Action == CreateNewKey) {
printf( " %ws - ", MP( PWSTR, pImlUndo, pKey->Name ) );
RtlInitUnicodeString( &KeyName, MP( PWSTR, pImlUndo, pKey->Name ) );
InitializeObjectAttributes( &ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
if (pKey->Action != DeleteOldKey) {
if (pKey->Action == CreateNewKey) {
printf( "deleting" );
}
else {
printf( "modifying" );
}
Status = NtOpenKey( &KeyHandle, DELETE | GENERIC_WRITE, &ObjectAttributes );
}
else {
printf( "creating" );
Status = NtCreateKey( &KeyHandle,
GENERIC_WRITE,
&ObjectAttributes,
0,
NULL,
0,
NULL
);
}
if (!NT_SUCCESS( Status )) {
KeyHandle = NULL;
printf( " - failed (0x%08x)", Status );
}
printf( "\n" );
if (KeyHandle != NULL) {
pValue = MP( PIML_VALUE_RECORD, pImlUndo, pKey->Values );
while (pValue != NULL) {
pOldValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->OldValue );
pNewValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->NewValue );
printf( " %ws - ", MP( PWSTR, pImlUndo, pValue->Name ) );
RtlInitUnicodeString( &ValueName,
MP( PWSTR, pImlUndo, pValue->Name )
);
if (pValue->Action == CreateNewValue) {
printf( "deleting" );
Status = NtDeleteValueKey( KeyHandle, &ValueName );
}
else {
if (pValue->Action == DeleteOldValue) {
printf( "creating" );
}
else {
printf( "restoring" );
}
Status = NtSetValueKey( KeyHandle,
&ValueName,
0,
pOldValue->Type,
MP( PWSTR, pImlUndo, pOldValue->Data ),
pOldValue->Length
);
}
if (!NT_SUCCESS( Status )) {
printf( " - failed (0x%08x)", Status );
}
printf( "\n" );
pValue = MP( PIML_VALUE_RECORD, pImlUndo, pValue->Next );
}
}
}
if (KeyHandle != NULL) {
if (pKey->Action == CreateNewKey) {
Status = NtDeleteKey( KeyHandle );
if (!NT_SUCCESS( Status )) {
printf( " *** delete of above key failed (0x%08x)", Status );
}
}
NtClose( KeyHandle );
}
return TRUE;
}
BOOLEAN
ProcessRedoKeyIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PIML_KEY_RECORD pKey,
PINSTALLATION_MODIFICATION_LOGFILE pImlRedo
)
{
PIML_VALUE_RECORD pValue;
PIML_VALUE_RECORD_CONTENTS pOldValue;
PIML_VALUE_RECORD_CONTENTS pNewValue;
POFFSET Values;
Values = 0;
if ((pKey->Values != 0 || pKey->Action == CreateNewKey) &&
pKey->Action != DeleteOldKey
) {
//
// Created or modified an existing key and/or values.
//
pValue = MP( PIML_VALUE_RECORD, pImlUndo, pKey->Values );
while (pValue != NULL) {
pOldValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->OldValue );
pNewValue = MP( PIML_VALUE_RECORD_CONTENTS, pImlUndo, pValue->NewValue );
if (pValue->Action == CreateNewValue) {
if (pNewValue != NULL) {
ImlAddValueRecord( pImlRedo,
pValue->Action,
MP( PWSTR, pImlUndo, pValue->Name ),
pNewValue->Type,
pNewValue->Length,
MP( PWSTR, pImlUndo, pNewValue->Data ),
0,
0,
NULL,
&Values
);
}
}
else
if (pValue->Action == ModifyOldValue) {
if (pOldValue != NULL && pNewValue != NULL) {
ImlAddValueRecord( pImlRedo,
pValue->Action,
MP( PWSTR, pImlUndo, pValue->Name ),
pNewValue->Type,
pNewValue->Length,
MP( PWSTR, pImlUndo, pNewValue->Data ),
pOldValue->Type,
pOldValue->Length,
MP( PWSTR, pImlUndo, pOldValue->Data ),
&Values
);
}
}
else
if (pValue->Action == DeleteOldValue) {
if (pOldValue != NULL) {
ImlAddValueRecord( pImlRedo,
pValue->Action,
MP( PWSTR, pImlUndo, pValue->Name ),
0,
0,
NULL,
pOldValue->Type,
pOldValue->Length,
MP( PWSTR, pImlUndo, pOldValue->Data ),
&Values
);
}
}
pValue = MP( PIML_VALUE_RECORD, pImlUndo, pValue->Next );
}
}
ImlAddKeyRecord( pImlRedo,
pKey->Action,
MP( PWSTR, pImlUndo, pKey->Name ),
Values
);
return TRUE;
}
BOOLEAN
ProcessUndoIniIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PIML_INI_RECORD pIni
)
{
PIML_INISECTION_RECORD pSection;
PIML_INIVARIABLE_RECORD pVariable;
HANDLE FileHandle;
BOOLEAN FileNameShown;
BOOLEAN SectionNameShown;
FileNameShown = FALSE;
pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pIni->Sections );
while (pSection != NULL) {
SectionNameShown = FALSE;
pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pSection->Variables );
while (pVariable != NULL) {
if (!FileNameShown) {
printf( "%ws\n", MP( PWSTR, pImlUndo, pIni->Name ) );
FileNameShown = TRUE;
}
if (!SectionNameShown) {
printf( " [%ws]", MP( PWSTR, pImlUndo, pSection->Name ) );
if (pSection->Action == DeleteOldSection) {
printf( " - deleting" );
}
printf( "\n" );
SectionNameShown = TRUE;
}
printf( " %ws = ", MP( PWSTR, pImlUndo, pVariable->Name ) );
if (pVariable->Action == CreateNewVariable) {
printf( "deleting" );
if (!WritePrivateProfileString( MP( PWSTR, pImlUndo, pSection->Name ),
MP( PWSTR, pImlUndo, pVariable->Name ),
NULL,
MP( PWSTR, pImlUndo, pIni->Name )
)
) {
printf( " - failed (%u)", GetLastError() );
}
printf( "\n" );
}
else {
printf( "restoring" );
if (!WritePrivateProfileString( MP( PWSTR, pImlUndo, pSection->Name ),
MP( PWSTR, pImlUndo, pVariable->Name ),
MP( PWSTR, pImlUndo, pVariable->OldValue ),
MP( PWSTR, pImlUndo, pIni->Name )
)
) {
printf( " - failed (%u)", GetLastError() );
}
printf( "\n" );
}
pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pVariable->Next );
}
if (pSection->Action == CreateNewSection) {
if (!FileNameShown) {
printf( "%ws\n", MP( PWSTR, pImlUndo, pIni->Name ) );
FileNameShown = TRUE;
}
if (!SectionNameShown) {
printf( " [%ws]", MP( PWSTR, pImlUndo, pSection->Name ) );
if (pSection->Action == CreateNewSection) {
printf( " - deleting" );
}
SectionNameShown = TRUE;
printf( "\n" );
}
if (!WritePrivateProfileSection( MP( PWSTR, pImlUndo, pSection->Name ),
NULL,
MP( PWSTR, pImlUndo, pIni->Name )
)
) {
printf( " *** delete of above section name failed (%u)\n",
GetLastError()
);
}
}
pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pSection->Next );
}
if (pIni->Action == CreateNewIniFile) {
printf( "%ws - deleting", MP( PWSTR, pImlUndo, pIni->Name ) );
if (!DeleteFile( MP( PWSTR, pImlUndo, pIni->Name ) )) {
printf( " - failed (%u)", GetLastError() );
}
printf( "\n" );
FileNameShown = TRUE;
}
else {
FileHandle = CreateFile( MP( PWSTR, pImlUndo, pIni->Name ),
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (FileHandle != INVALID_HANDLE_VALUE) {
SetFileTime( FileHandle,
&pIni->LastWriteTime,
&pIni->LastWriteTime,
&pIni->LastWriteTime
);
CloseHandle( FileHandle );
}
}
if (FileNameShown) {
printf( "\n" );
}
return TRUE;
}
BOOLEAN
ProcessRedoIniIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PIML_INI_RECORD pIni,
PINSTALLATION_MODIFICATION_LOGFILE pImlRedo
)
{
PIML_INISECTION_RECORD pSection;
PIML_INIVARIABLE_RECORD pVariable;
POFFSET Variables, Sections;
pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pIni->Sections );
Sections = 0;
while (pSection != NULL) {
pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pSection->Variables );
Variables = 0;
while (pVariable != NULL) {
ImlAddIniVariableRecord( pImlRedo,
pVariable->Action,
MP( PWSTR, pImlUndo, pVariable->Name ),
MP( PWSTR, pImlUndo, pVariable->OldValue ),
MP( PWSTR, pImlUndo, pVariable->NewValue ),
&Variables
);
pVariable = MP( PIML_INIVARIABLE_RECORD, pImlUndo, pVariable->Next );
}
if (Variables != 0) {
ImlAddIniSectionRecord( pImlRedo,
pSection->Action,
MP( PWSTR, pImlUndo, pSection->Name ),
Variables,
&Sections
);
}
pSection = MP( PIML_INISECTION_RECORD, pImlUndo, pSection->Next );
}
if (Sections != 0) {
ImlAddIniRecord( pImlRedo,
pIni->Action,
MP( PWSTR, pImlUndo, pIni->Name ),
&pIni->LastWriteTime,
Sections
);
}
return TRUE;
}
int
ProcessUndoIml(
PINSTALLATION_MODIFICATION_LOGFILE pImlUndo,
PINSTALLATION_MODIFICATION_LOGFILE pImlRedo
)
{
PIML_FILE_RECORD pFile;
PIML_KEY_RECORD pKey;
PIML_INI_RECORD pIni;
if (pImlUndo->NumberOfFileRecords > 0) {
printf( "Undoing File Modifications:\n" );
pFile = MP( PIML_FILE_RECORD, pImlUndo, pImlUndo->FileRecords );
while (pFile != NULL) {
if (pFile->Name != 0) {
if (pImlRedo != NULL) {
ProcessRedoFileIml( pImlUndo, pFile, pImlRedo );
}
ProcessUndoFileIml( pImlUndo, pFile );
}
pFile = MP( PIML_FILE_RECORD, pImlUndo, pFile->Next );
}
printf( "\n" );
}
if (pImlUndo->NumberOfKeyRecords > 0) {
printf( "Undoing Registry Modifications:\n" );
pKey = MP( PIML_KEY_RECORD, pImlUndo, pImlUndo->KeyRecords );
while (pKey != NULL) {
if (pImlRedo != NULL) {
ProcessRedoKeyIml( pImlUndo, pKey, pImlRedo );
}
ProcessUndoKeyIml( pImlUndo, pKey );
pKey = MP( PIML_KEY_RECORD, pImlUndo, pKey->Next );
}
printf( "\n" );
}
if (pImlUndo->NumberOfIniRecords > 0) {
printf( "Undoing .INI File modifications:\n" );
pIni = MP( PIML_INI_RECORD, pImlUndo, pImlUndo->IniRecords );
while (pIni != NULL) {
if (pImlRedo != NULL) {
ProcessRedoIniIml( pImlUndo, pIni, pImlRedo );
}
ProcessUndoIniIml( pImlUndo, pIni);
pIni = MP( PIML_INI_RECORD, pImlUndo, pIni->Next );
}
}
return 0;
}