installationservices/swi/source/swis/server/restoremachine.cpp
changeset 0 ba25891c3a9e
child 12 7ca52d38f8c3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/swis/server/restoremachine.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1098 @@
+/*
+* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+#include "restoremachine.h"
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+#include <usif/sts/sts.h>
+#else
+#include "integrityservices.h"
+#endif
+
+#include "installclientserver.h"
+#include "sisregistryentry.h"
+#include "restorecontroller.h"
+#include "restoreprocessor.h"
+#include "sisregistryfiledescription.h"
+#include "installationprocessor.h"
+#include "sisuihandler.h"
+#include "sishash.h"
+#include "sisinfo.h"
+#include "sisuid.h"
+#include "log.h"
+#include "swispubsubdefs.h"
+#include "securitycheckutil.h"
+#include "secutils.h"
+#include "cleanuputils.h"
+#include "sisversion.h"
+#include "sisregistrywritablesession.h"
+#include <f32file.h>
+#include "sisregistrypackage.h"
+
+using namespace Swi;
+
+
+//
+// CRestoreMachine
+//
+
+CRestoreMachine* CRestoreMachine::NewL(const RMessage2& aMessage)
+	{	
+	CRestoreMachine* self = CRestoreMachine::NewLC(aMessage);
+	CleanupStack::Pop(self);
+	return self;	
+	}
+	
+CRestoreMachine* CRestoreMachine::NewLC(const RMessage2& aMessage)
+	{	
+	CRestoreMachine* self = new (ELeave) CRestoreMachine;
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessage);
+	return self;	
+	}
+	
+void CRestoreMachine::ConstructL(const RMessage2& aMessage)
+	{
+	DEBUG_PRINTF(_L8("Restore - Starting new restore session"));
+	
+	iSystemDriveChar = RFs::GetSystemDriveChar();
+
+	TPckg<TUid> package(iPackageUid);
+	
+	TInt err = aMessage.Read(EMessageSlotRestoreUid, package, 0);
+	
+	if (err != KErrNone)
+		{
+		aMessage.Panic(KInstallServerName, KErrBadDescriptor);
+		}
+	
+	TInt len = aMessage.GetDesLengthL(EMessageSlotRestoreController);
+	iBuf = HBufC8::NewL(len);
+	TPtr8 bufPtr = iBuf->Des();
+	
+	err = aMessage.Read(EMessageSlotRestoreController, bufPtr, 0);
+	
+	if (err != KErrNone)
+		{
+		aMessage.Panic(KInstallServerName, KErrBadDescriptor);
+		}
+		
+	User::LeaveIfError(iFs.Connect());
+  	iSecurityManager = CSecurityManager::NewL();
+  	iRestoreController = CRestoreController::NewL(*iBuf, *iSecurityManager, iFs);
+	iFileMan = CFileMan::NewL(iFs);
+		
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	// Create an STS transaction
+	iStsSession.CreateTransactionL();
+	_LIT(KPathFormat, "%c:%S");	
+	TPath path;	
+	TUint driveCh(iSystemDriveChar); // can't pass TChar to Format
+
+	// Connect to the registry and start a transaction
+	User::LeaveIfError(iRegistrySession.Connect());
+	iRegistrySession.CreateTransactionL();
+#else
+	// Create an integrity services object
+	TTime currentTime;
+	currentTime.UniversalTime();
+	
+	_LIT(KPathFormat, "%c:%S");	
+	TUint driveCh(iSystemDriveChar); // can't pass TChar to Format
+	TPath path;	
+	
+	path.Format(KPathFormat, driveCh, &KSysInstallPath);
+	iIntegrityServices = CIntegrityServices::NewL(currentTime.Int64(), path);
+	
+	//Roll back partial, abortive installs before us
+	iIntegrityServices->RollBackL(ETrue);
+#endif
+
+	path.Format(KPathFormat, driveCh, &KSysInstallTempPath);
+	err = iFs.MkDirAll(path);
+ 	if (err != KErrAlreadyExists && err != KErrNone)
+ 		{
+		User::Leave(err);
+ 		}
+	
+	// Check if it is a valid upgrade
+ 	if (iSecurityManager->SecurityPolicy().AllowOverwriteOnRestore())    
+ 		{
+ 		// Fix PDEF129066: Pre-installed backed up content cannot be restored 
+ 		PrepareUpgradesL();
+ 		}
+ 	else
+ 		{
+ 		CheckVersionUpgradeL();
+ 		}
+
+ #ifdef SYMBIAN_USER_PROMPT_SERVICE
+	//connect to the SWI Observer
+	User::LeaveIfError(iObserver.Connect());
+	//Resgister to the SWI Observer
+	TRequestStatus status;
+	iObserver.Register(status);
+	User::WaitForRequest(status);
+	
+	RBuf logFileName;
+	logFileName.CreateL(KMaxFileName);
+	logFileName.CleanupClosePushL();
+	//Get created a log file and obtains its full name.
+	iObserver.GetFileHandleL(logFileName);
+	//Add the log file to the transaction
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	iStsSession.RegisterNewL(logFileName);
+#else
+	iIntegrityServices->AddL(logFileName);
+#endif
+	CleanupStack::PopAndDestroy(&logFileName);
+#endif
+	aMessage.Complete(KErrNone);
+	}
+	
+void CRestoreMachine::ServiceFileRequestL(const RMessage2& aMessage)
+	{
+	RFile restoreFile;
+	TInt err = restoreFile.AdoptFromClient(aMessage, EMessageSlotRestoreFs, EMessageSlotRestoreFile);
+	CleanupClosePushL(restoreFile);
+	
+	if (err != KErrNone)
+		{
+		aMessage.Panic(KInstallServerName, KErrBadDescriptor);
+		User::Leave(KErrBadDescriptor);
+		}
+		
+	TInt len = aMessage.GetDesLengthL(EMessageSlotRestorePath);
+	HBufC* buf = HBufC::NewLC(len);
+	TPtr filename = buf->Des();
+	
+	err = aMessage.Read(EMessageSlotRestorePath, filename, 0);
+	
+	if (err != KErrNone)
+		{
+		aMessage.Panic(KInstallServerName, KErrBadDescriptor);
+		User::Leave(KErrBadDescriptor);
+		}
+	
+	TFileName sbeFileName;
+	User::LeaveIfError(restoreFile.FullName(sbeFileName));
+	DEBUG_PRINTF3(_L("Restore - Servicing File Request for file '%S' from '%S'"),
+		&filename, &sbeFileName);
+
+	if (filename[0] == '!')			// install to user selected rive
+		{
+		filename[0] = iRestoreController->InstallDrive();
+		}
+	else if (filename[0] == '$')	// install to system drive
+		{
+		filename[0] = iFs.GetSystemDriveChar();
+		}
+		
+	// Check if the disk is in at present
+  	TInt drive;
+  	User::LeaveIfError(iFs.CharToDrive(filename[0], drive));
+  	TVolumeInfo volume;
+  	err = iFs.Volume(volume, drive);
+  	if (err != KErrNone)
+  		{
+  		User::Leave(KErrPathNotFound); // error code agreed with the connect team
+  		}
+	
+	if (!SecurityCheckUtil::CheckFileName(filename,iSystemDriveChar)
+		|| SecurityCheckUtil::IsSubstedDriveL(iFs, filename))
+		{
+		User::Leave(KErrBadName);
+		}
+		
+	// For TCB protected directories eclipsing checks are required. This is not necessary
+	// for public or private directories because SBE can restore these directly and the eclipsing
+	// checks do not really improve security.
+	TBool requiresHashCheck = EFalse;
+	if (SecurityCheckUtil::IsProtectedDirectoryL(filename) && ! SecurityCheckUtil::IsPrivateDirectory(filename))
+		{	
+		if (! IsUniqueL(filename, requiresHashCheck))
+			{
+			User::Leave(KErrInvalidEclipsing);
+			}
+		}
+	// Hash checks must be performed for TCB protected files
+	requiresHashCheck |= SecurityCheckUtil::IsTargetTcbWriteProtected(filename);
+	
+	TFileName tempFileName;
+	iRestoreController->AddFileDescriptionL(restoreFile, filename, tempFileName, requiresHashCheck);
+	
+	// move the file to it's temporary location and add it to the transaction
+	// as a temporary file.
+	// format of names is {drive}:\sys\install\temp\file-{uid}-{abs index}-{file index}-{hash of name in hex}
+	// this format differs slightly from the install format
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	iStsSession.RegisterTemporaryL(tempFileName);
+#else
+	iIntegrityServices->TemporaryL(tempFileName);
+#endif
+
+ 	err = iFs.MkDirAll(tempFileName);
+ 	if (err != KErrAlreadyExists && err != KErrNone)
+ 		{
+		User::Leave(err);
+ 		}
+
+ 	User::LeaveIfError(iFileMan->Copy(restoreFile, tempFileName));	
+	CleanupStack::PopAndDestroy(2, &restoreFile);
+	aMessage.Complete(KErrNone);
+	}
+
+TBool CRestoreMachine::IsUniqueL(const TDesC& aFileName, TBool& aCheckFileHashOut)
+	{	
+	aCheckFileHashOut = EFalse;
+	
+	if (aFileName.Length() == 0)
+		{
+		return ETrue;
+		}
+	
+	TPath path;
+	path.Copy(aFileName);
+	
+	// Find on which disks (if any) this file exists on	
+	TDriveList driveList;
+	User::LeaveIfError(iFs.DriveList(driveList));
+
+	TChar disk = 'a' - 1;
+	
+	for (TInt i = 0; i < driveList.Length(); i++)
+		{
+		disk+=1;
+		
+		if (driveList[i] == 0)
+			{
+			continue;
+			}
+		else if (disk == 'z')
+			{
+			continue; // eclipsing allowed, checked later
+			}
+		
+		path[0] = disk;
+		TEntry entry;
+		
+		if (iFs.Entry(path, entry) == KErrNone)
+			{
+			if (path.CompareF(aFileName) == KErrNone)
+				{
+				// If there is already a file here, check its hash
+				aCheckFileHashOut = ETrue;
+				}
+			else
+				{
+				// names must be unique across drives
+				return EFalse;
+				}
+			}
+		}
+		
+	return ETrue;	
+	}
+
+
+
+void CRestoreMachine::CheckVersionUpgradeL()
+	{
+	const RPointerArray<CPlan>& plans = iRestoreController->Plans();
+		
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	RSisRegistrySession session;
+	User::LeaveIfError(session.Connect());
+	CleanupClosePushL(session);
+#endif
+	
+    TInt count = plans.Count(); 
+    for (TInt i = 0; i < count; ++i)
+		{
+		// check only the first plan is a valid upgrade
+        const Sis::CController& controller = plans[i]->ApplicationL().ControllerL();
+		Sis::TInstallType type = controller.Info().InstallType();
+		TBool isBase = ((type == EInstInstallation) || (type == EInstPreInstalledApp));
+		
+		// ask the registry if the UID already exists.
+		RSisRegistryEntry entry;
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		TInt err = entry.Open(iRegistrySession, controller.Info().Uid().Uid());
+#else
+		TInt err = entry.Open(session, controller.Info().Uid().Uid());
+#endif
+		if (err == KErrNone)
+			{
+			CleanupClosePushL(entry);
+			
+			TVersion version = entry.VersionL();
+			if (isBase && !entry.IsInRomL())
+				{
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+				CleanupStack::PopAndDestroy(&entry);
+#else
+				CleanupStack::PopAndDestroy(2, &session); // entry
+#endif
+				
+				const CVersion& ctrlVersion = controller.Info().Version();
+				
+				if (version.iMajor == ctrlVersion.Major() &&
+					version.iMinor == ctrlVersion.Minor() &&
+					version.iBuild == ctrlVersion.Build())
+					{
+					DEBUG_PRINTF(_L8("Restore - Error, attempting to restore an application that is already on device"));
+					User::Leave(KErrAlreadyExists);
+					}
+				else
+					{
+					DEBUG_PRINTF(_L8("Restore - Error, attempting to restore an application that is not supported on device"));
+					User::Leave(KErrNotSupported);
+					}
+				}
+			CleanupStack::PopAndDestroy(&entry);
+            // check for Augmentations as well. Need to leave with KErrAlreadyExists, if the same augmentation exists
+            if (type == Sis::EInstAugmentation)
+                {
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK				
+				TBool foundEntryToOverwrite = FindInstalledAugmentationL(iRegistrySession, controller, entry);
+#else				
+                TBool foundEntryToOverwrite = FindInstalledAugmentationL(session, controller, entry);
+#endif				
+				entry.Close();
+                if ( foundEntryToOverwrite )
+                    {
+                    DEBUG_PRINTF(_L8("Restore - Error, attempting to restore an augmentation of an application that is already on device"));
+                    User::Leave(KErrAlreadyExists);
+                    }
+                }
+			}
+		}
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		CleanupStack::PopAndDestroy(&session);
+#endif
+	}
+
+/**
+ Scans the meta-data to restore and identifies any applications or upgrades that are already
+ installed and should be overwritten.
+ If an overwrite is required then this function removes all of the installed files 
+ belonging to application using the current integrity services transaction.
+ */
+void CRestoreMachine::PrepareUpgradesL()
+	{
+	const RPointerArray<CPlan>& plans = iRestoreController->Plans();
+
+
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	RSisRegistrySession session;
+	User::LeaveIfError(session.Connect());
+	CleanupClosePushL(session);
+#endif
+
+		
+	// Loop over the set of applications in the restore meta-data
+	// N.B. The set of upgrades in the restore meta-data can be DIFFERENT to 
+	// the set of upgrades on the device.
+	TInt count = plans.Count();	
+	for (TInt i = 0; i < count; ++i)
+		{
+		const Sis::CController& controller = plans[i]->ApplicationL().ControllerL();
+		Sis::TInstallType type = controller.Info().InstallType();
+		
+		// Ask the registry if the application already exists.				
+		RSisRegistryEntry entryToOverwrite;		
+		TBool foundEntryToOverwrite = EFalse;		
+		
+		if (type == Sis::EInstAugmentation)
+			{
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+			foundEntryToOverwrite = FindInstalledAugmentationL(iRegistrySession, controller, entryToOverwrite);
+#else
+			foundEntryToOverwrite = FindInstalledAugmentationL(session, controller, entryToOverwrite);
+#endif
+         
+			}
+		 else 
+			{
+			 
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+			TInt err = entryToOverwrite.Open(iRegistrySession, controller.Info().Uid().Uid());
+#else
+			TInt err = entryToOverwrite.Open(session, controller.Info().Uid().Uid());
+#endif
+			 
+			if (err == KErrNone)
+				{
+				foundEntryToOverwrite = ETrue;
+				}
+			else if (err != KErrNotFound)
+				{
+				User::Leave(err);
+				}
+			}
+		CleanupClosePushL(entryToOverwrite);
+				
+		if (foundEntryToOverwrite && entryToOverwrite.IsInRomL())
+			{
+			// Can't overwrite entries in ROM; however, this is not a fatal error
+			// because it is still valid to restore upgrades to ROM stubs. Consequently,
+			// only the removal of existing files is skipped.
+			DEBUG_PRINTF2(_L("Package 0x%08x is in ROM, skipping removal of files."),
+					entryToOverwrite.UidL().iUid);		
+			}
+		else if (foundEntryToOverwrite && ! entryToOverwrite.IsPresentL())
+			{
+			DEBUG_PRINTF2(_L("Package 0x%08x is registered but not fully present. Skipping restore."), 
+					entryToOverwrite.UidL().iUid);
+			// Package exists but can't be overwritten. Leaving with KErrAlreadyExists
+			// instructs SBE to skip this package but continue with the restore.
+			User::Leave(KErrAlreadyExists);	
+			}
+		else if (foundEntryToOverwrite)
+			{						
+			// The application in the registry is already installed and is not in the ROM
+			// This could be because the system drive has not been reformatted OR a firmware
+			// upgrade also flashed the user data area.
+			
+			// Identify the package to be overwritten and record this in the package
+			// being restored. This is needed by the SIS registry in order to overwrite
+			// the controller and .reg files to overwrite. 
+			CApplication* application = const_cast<CApplication*>(&plans[i]->ApplicationL());
+			// controller must be controller to restore not current controller	
+			application->SetUpgrade(controller);				
+			CSisRegistryPackage* originalPackage=entryToOverwrite.PackageL();
+			CleanupStack::PushL(originalPackage);
+			application->SetPackageL(*originalPackage);	
+			
+			DEBUG_PRINTF5(_L("Restoring package as upgrade 0x%08x, name=\"%S\" vendor=\"%S\" index=%d"), 
+					originalPackage->Uid().iUid, &originalPackage->Name(), 
+					&originalPackage->Vendor(), originalPackage->Index());			
+			CleanupStack::PopAndDestroy(originalPackage);
+
+			// Remove all files registered for this package if the package is an SA or SP
+			// and the version numbers mismatch.
+			// If the version numbers are exactly the same then SWI avoids deleting files 
+			// to work with applications that don't create full backups 
+			// N.B. Files should still be overwritten if they are present in the backup.
+			if (type == Sis::EInstInstallation || Sis::EInstAugmentation)
+				{
+				TVersion vToRestore(0,0,0);
+				if (type == Sis::EInstInstallation)
+					{
+					// The package in the restore image could have been upgrade with a PU
+					vToRestore = GetLatestVersionOfPackageToRestore();
+					}
+				else
+					{
+					// Augmentation so version number to restore is the one in the current controller
+					vToRestore.iMajor = controller.Info().Version().Major();
+					vToRestore.iMinor = controller.Info().Version().Minor();
+					vToRestore.iBuild = controller.Info().Version().Build();
+					}
+				
+				TVersion vCurrent(entryToOverwrite.VersionL());			
+				if (vToRestore.iMajor != vCurrent.iMajor || 
+					vToRestore.iMinor != vCurrent.iMinor || 
+					vToRestore.iBuild != vCurrent.iBuild)
+					{
+					DEBUG_PRINTF2(_L("Version mismatch for package 0x%08x removing currently registered files."),
+							originalPackage->Uid().iUid);
+					RemovePackageFilesL(entryToOverwrite);
+					}
+				}			
+			}
+		CleanupStack::PopAndDestroy(&entryToOverwrite);
+		}
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+       	CleanupStack::PopAndDestroy(&session);
+#endif
+	}
+
+/**
+ Gets the latest version number of the package to restore. This will either
+ be the version number of the SA application or the most recent partial upgrade.
+ 
+ @return the official version number of the package being restored.
+ */
+TVersion CRestoreMachine::GetLatestVersionOfPackageToRestore()
+	{
+	TVersion v(0,0,0);	
+	
+	const RPointerArray<CPlan>& plans = iRestoreController->Plans();		
+	for (TInt i = plans.Count() - 1; i >= 0; --i)
+		{
+		const Sis::CController& controller = plans[i]->ApplicationL().ControllerL();
+		Sis::TInstallType type(controller.Info().InstallType());
+		if (type == Sis::EInstInstallation || type == Sis::EInstPartialUpgrade)
+			{
+			v.iMajor = controller.Info().Version().Major();
+			v.iMinor = controller.Info().Version().Minor();
+			v.iBuild = controller.Info().Version().Build();
+			break;
+			}
+		}
+	return v;
+	}
+
+/**
+ Scans the set of installed augmentations to find one matching the supplied controller.
+ This is necessary because SWI does not have a non-localised application name.
+ Also, in order to overwrite a registry entry via UpdateEntryL the CSisRegistryPackage
+ must contain the correct Index; otherwise, the SIS registry server will not be able
+ to locate the correct .reg file.
+ 
+ @param aSession			Shared connection to the SIS registry server.
+ @param aControlller		The controller to restore.
+ @param aEntryToOverwrite	If a match is found then this parameter will be 
+							set to the registry entry to overwrite.
+ @return ETrue if a matching augmentation is found; otherwise EFalse is returned.
+ */
+TBool CRestoreMachine::FindInstalledAugmentationL(RSisRegistrySession& aSession, const Sis::CController& aController, RSisRegistryEntry& aEntryToOverwrite)
+	{
+	TBool foundEntryToOverwrite = EFalse;
+	
+	TUid puid = aController.Info().Uid().Uid();
+	const RPointerArray<CString>& names = aController.Info().Names();			
+	TInt nameCount = names.Count();	
+	
+	// Item being restored is an SP upgrade so try and find the base
+	// on the device. 
+	RSisRegistryEntry augBase;
+    TInt err = augBase.Open(aSession, puid);
+
+	
+	if (err != KErrNone && err != KErrNotFound)
+		{
+		User::Leave(err);
+		}
+	else if (err == KErrNone)
+		{
+		CleanupClosePushL(augBase);
+		RPointerArray<CSisRegistryPackage> augmentations;															
+		augBase.AugmentationsL(augmentations);
+		CleanupStack::PopAndDestroy(); // augBase
+		CleanupResetAndDestroyPushL(augmentations);
+
+		// Check each installed augmentation against the list of names for
+		// the augmentation to be restored in-case the language has changed
+		TInt augCount = augmentations.Count();
+		TInt i = 0;
+		while (i < augCount && ! foundEntryToOverwrite)
+			{				 					
+			for (TInt j = 0; j < nameCount; ++j)
+				{						
+				if (names[j]->Data().CompareF(augmentations[i]->Name()) == 0)
+					{
+					// This is the SP to overwrite
+                    TRAP(err, aEntryToOverwrite.OpenL(aSession, *augmentations[i]));
+					
+					if (err == KErrNone)
+						{
+						foundEntryToOverwrite = ETrue;
+						break;
+						}
+					else if (err != KErrNotFound)
+						{
+						User::Leave(err);
+						}					
+					}
+				}
+			++i;	// check next installed augmenation
+			}
+		CleanupStack::PopAndDestroy(); // augmentations
+		}
+		
+	return foundEntryToOverwrite;
+	}
+
+/**
+ Deletes all files belonging to a registry entry using the current integrity
+ services transaction. Private directories are NOT deleted because an restore
+ operation that overwrites an existing application should allow additional 
+ user-data that is not in the backup image to be preserved.
+ 
+ @param aEntry 	the SIS registry entry to process.
+ */
+void CRestoreMachine::RemovePackageFilesL(RSisRegistryEntry& aEntry)
+	{
+	RPointerArray<HBufC> files;
+	aEntry.FilesL(files);
+	CleanupResetAndDestroyPushL(files);
+	for (TInt i = files.Count() - 1; i >= 0; --i)
+		{
+		// Make sure drive characters have been resolved correctly
+		TPtr fileName = files[i]->Des();
+		if (fileName[0] == '$')
+			{
+			fileName[0] = RFs::GetSystemDriveChar();
+			}
+		else if (fileName[0] == '!')
+			{
+			fileName[0] = aEntry.SelectedDriveL();
+			}
+
+		if (iFs.IsValidName(fileName)) // Ensure wildcarded files aren't processed
+			{
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+			TRAPD(err, iStsSession.RemoveL(fileName));
+#else
+			TRAPD(err, iIntegrityServices->RemoveL(fileName));
+#endif
+			if (err != KErrNone && err != KErrNotFound && err != KErrPathNotFound)
+				{
+				DEBUG_PRINTF3(_L("Error %d failed to delete file %S"), err, &fileName);
+				User::LeaveIfError(err);
+				}
+
+			// If the file is in an exe or library then the hash must also be removed
+			TParsePtrC parse(fileName);
+			_LIT(KSysBin, "\\sys\\bin\\");
+			if (parse.Path().CompareF(KSysBin) == 0)
+				{
+				RBuf hashFileName;
+				hashFileName.CreateL(KMaxFileName);
+				CleanupClosePushL(hashFileName);
+				_LIT(KSysHash, "$:\\sys\\hash\\");
+				hashFileName.Append(KSysHash);
+				hashFileName[0] = iFs.GetSystemDriveChar();
+				hashFileName.Append(parse.NameAndExt());
+				DEBUG_PRINTF2(_L("Removing hash %S"), &hashFileName);
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+			TRAP(err, iStsSession.RemoveL(hashFileName));
+#else
+			TRAP(err, iIntegrityServices->RemoveL(hashFileName));
+#endif
+			
+				if (err != KErrNone && err != KErrNotFound && err != KErrPathNotFound)
+					{
+					DEBUG_PRINTF3(_L("Error %d failed to delete file %S"), err, &fileName);
+					User::LeaveIfError(err);
+					}
+				CleanupStack::PopAndDestroy(&hashFileName);
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy(&files);
+	}
+	
+void CRestoreMachine::ServiceCommitRequestL(const RMessage2& aMessage)
+	{
+	DEBUG_PRINTF(_L8("Restore - Commiting restore session"));
+	
+	// Finally, add remaining dummy stuff to the plan
+	iRestoreController->AddEmbeddedAppsAndFilesL();
+
+	// Dummy plan for use with the restore processor, we use
+	// CFileCopyDescriptions directly when doing a restore
+	const RPointerArray<CPlan>& plans = iRestoreController->Plans(); 
+
+	iCommitWatcher = CCommitWatcher::NewL(plans, *iSecurityManager,
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		iStsSession, iRegistrySession,
+#else
+		*iIntegrityServices, 
+#endif
+		*iRestoreController, aMessage, iFs, *this);
+
+	iCommitWatcher->StartL();
+	}
+	
+CRestoreMachine::~CRestoreMachine()
+	{
+	delete iRestoreController;
+	delete iSecurityManager;
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	iStsSession.Close();
+	iRegistrySession.Close();
+#else
+	delete iIntegrityServices;
+#endif
+	delete iBuf;
+	if (iCommitWatcher)
+		{
+		iCommitWatcher->Cancel();
+		}
+	delete iCommitWatcher;
+	delete iFileMan;
+	iFs.Close();
+
+	// close SWI Observer session
+	iObserver.Close();
+	}
+
+/**
+	@return SWI Observer session handle.
+ */
+RSwiObserverSession& CRestoreMachine::Observer()
+	{
+	return iObserver;
+	}
+		
+//
+// CCommitWatcher
+//
+	
+CRestoreMachine::CCommitWatcher* CRestoreMachine::CCommitWatcher::NewL(const RPointerArray<CPlan>& aPlans, CSecurityManager& aSecurityManager,
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	Usif::RStsSession& aStsSession, RSisRegistryWritableSession& aRegistrySession,
+#else
+	CIntegrityServices& aIntegrityServices,
+#endif
+	CRestoreController& aController, const RMessage2& aMessage, RFs& aFs, CRestoreMachine& aMachine)
+	{
+	CCommitWatcher* self = new (ELeave) CCommitWatcher(aPlans, aSecurityManager, 
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		aStsSession, aRegistrySession,
+#else
+		aIntegrityServices,
+#endif
+		aController, aMessage, aFs, aMachine);
+	return self;
+	
+	}
+
+CRestoreMachine::CCommitWatcher::CCommitWatcher(const RPointerArray<CPlan>& aPlans, CSecurityManager& aSecurityManager,
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	Usif::RStsSession& aStsSession, RSisRegistryWritableSession& aRegistrySession,
+#else
+	CIntegrityServices& aIntegrityServices,
+#endif
+	CRestoreController& aController, const RMessage2& aMessage, RFs& aFs, CRestoreMachine& aMachine)
+	: CActive(CActive::EPriorityStandard),
+	  iClientMessage(aMessage), 
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	  iStsSession(aStsSession),
+	  iRegistrySession(aRegistrySession),
+#else
+	  iIntegrityServices(aIntegrityServices),
+#endif
+	  iRestoreController(aController), iSecurityManager(aSecurityManager),
+	  iPlans(aPlans), iFs(aFs), iMachine(aMachine)
+	{
+	CActiveScheduler::Add(this);
+	iPlanIndex = -1;
+	iVerifierIndex = -1;	
+	}
+	
+void CRestoreMachine::CCommitWatcher::RunL()
+	{
+	SwitchStateL();
+	}
+	 
+void CRestoreMachine::CCommitWatcher::DoCancel()
+	{
+	if (iProcessor)
+		{
+		iProcessor->Cancel();
+		}
+	}	
+
+CRestoreMachine::CCommitWatcher::~CCommitWatcher()
+	{
+	Cancel();
+	delete iProcessor;
+	}
+
+void CRestoreMachine::CCommitWatcher::StartL()
+	{
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}	
+	
+void CRestoreMachine::CCommitWatcher::SwitchStateL()
+	{
+	if (++iVerifierIndex < iRestoreController.Verifiers().Count() && iStatus.Int() == KErrNone)
+		{
+		
+		iRestoreController.Verifiers()[iVerifierIndex]->StartL(iStatus);
+		SetActive();
+		}
+	else if (++iPlanIndex < iPlans.Count() && iStatus.Int() == KErrNone)
+		{
+		
+		CApplication& app = const_cast <CApplication&> (iPlans[iPlanIndex]->ApplicationL());
+		// Check the application is installed based on su cert rules
+		Sis::TInstallType type = app.ControllerL().Info().InstallType();
+		Sis::TInstallFlags flag = app.ControllerL().Info().InstallFlags();
+		TBool allowedType = (type == EInstInstallation || (type == EInstAugmentation) || type == EInstPartialUpgrade );
+		TBool allowedFlag = (flag & EInstFlagROMUpgrade);
+	
+		if (app.ControllerL().IsSignedBySuCert() && allowedType && allowedFlag && 
+			!app.IsStub() && app.ControllerL().TrustStatus().ValidationStatus()
+			>= EValidatedToAnchor)
+			{
+			app.SetInstallSuCertBased();
+			}
+
+		RArray<TUid> baseSids;
+		CleanupClosePushL(baseSids);
+		
+		// check to see if the plan we are about to process is a valid upgrade
+		if (!IsValidUpgradeL(app.ControllerL(), baseSids))
+			{
+			User::Leave(KErrInvalidUpgrade);
+			}
+		
+		if (!ValidEclipsingL(app))
+			{
+			User::Leave(KErrInvalidEclipsing);
+			}
+		
+		delete iProcessor;
+
+		const RPointerArray<TPtrC8>& controllerBinaries = iRestoreController.ControllerBinaries();
+		ASSERT(controllerBinaries.Count() == iPlans.Count());
+		DEBUG_PRINTF3(_L8("Restoring plan %d out of %d"), iPlanIndex, iPlans.Count());
+		const TDesC8& controllerBinary = *controllerBinaries[iPlanIndex];
+		iProcessor = CRestoreProcessor::NewL(*(iPlans[iPlanIndex]), controllerBinary, iSecurityManager,
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+			iStsSession, iRegistrySession,
+#else
+			iIntegrityServices,
+#endif
+			iRestoreController.Verifiers(), baseSids, iMachine.Observer()); 
+		iProcessor->ProcessPlanL(iStatus);
+		CleanupStack::PopAndDestroy(&baseSids);
+		
+		SetActive();
+		}
+	else
+		{
+		CompleteL();
+		}
+	}
+	
+TBool CRestoreMachine::CCommitWatcher::ValidEclipsingL(const CApplication& aApplication)
+	{
+	if (aApplication.IsInstallSuCertBased())
+		{
+		return ETrue;
+		}
+
+	RPointerArray<HBufC> eclipsableFiles;
+	CleanupResetAndDestroyPushL(eclipsableFiles);
+	
+	// check which (if any) files we're allowed to eclipse
+	Sis::TInstallType type = aApplication.ControllerL().Info().InstallType();
+	if (type != EInstPreInstalledApp &&
+		aApplication.ControllerL().TrustStatus().ValidationStatus() >= EValidatedToAnchor)
+		{
+		// we're an upgrade (includes SA with RU flag upgrade over ROM) and trusted sufficiently. 
+		// Check if we're a suitable candidate.
+
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		RSisRegistrySession session;
+		User::LeaveIfError(session.Connect());
+		CleanupClosePushL(session);
+#endif
+		
+		RSisRegistryEntry entry;
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		TInt err = entry.Open(iRegistrySession, aApplication.ControllerL().Info().Uid().Uid());
+#else
+		TInt err = entry.Open(session, aApplication.ControllerL().Info().Uid().Uid());
+#endif
+		if (err == KErrNone)
+			{
+			CleanupClosePushL(entry);
+
+			if (entry.IsInRomL())
+				{
+				// we can eclipse files from this package
+				entry.FilesL(eclipsableFiles);
+				}
+				
+			CleanupStack::PopAndDestroy(&entry);
+			}
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		CleanupStack::PopAndDestroy(&session);
+#endif
+		}
+		
+	// check for files that eclipse Z:
+	
+	TBool ret = ETrue;
+	const RPointerArray<CSisRegistryFileDescription>& files = aApplication.FilesToAdd();
+	TInt count(files.Count());
+
+	TFileName file;
+	for (TInt i = 0; i < count; ++i)
+		{
+		// find file descriptions that eclipse Z:
+		file.Zero();
+		file.Copy(files[i]->Target());
+		file[0] = 'z';
+		
+		TEntry entry;
+		if (KErrNone == iFs.Entry(file, entry))
+			{
+			TBool found = EFalse;
+			// we've got an eclipse, check it against the list of allowed eclipses
+			for (TInt j = 0; j < eclipsableFiles.Count(); ++j)
+				{
+				if (0 == file.CompareF(*eclipsableFiles[j]))
+					{
+					found = ETrue;
+					break;
+					}
+				}
+			
+			if (!found)
+				{
+				ret = EFalse;
+				break; // return immediately.
+				}	
+			}
+		}
+
+	CleanupStack::PopAndDestroy(&eclipsableFiles);
+	return ret;
+	}
+TBool CRestoreMachine::CCommitWatcher::IsValidUpgradeL(const Sis::CController& aController, RArray<TUid>& aSids)
+	{
+	
+	Sis::TInstallType type = aController.Info().InstallType();
+	TBool isBase = ((type == EInstInstallation) || (type == EInstPreInstalledApp));
+	TBool inROM(EFalse);
+	
+	// ask the registry if the UID already exists.
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	RSisRegistrySession session;
+	User::LeaveIfError(session.Connect());
+	CleanupClosePushL(session);
+#endif
+
+	RSisRegistryEntry installedBase;
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+    TInt err = installedBase.Open(iRegistrySession, aController.Info().Uid().Uid());
+#else
+	TInt err = installedBase.Open(session, aController.Info().Uid().Uid());
+#endif
+
+	if (err == KErrNone)
+		{
+		CleanupClosePushL(installedBase);
+		
+		// Found the package entry. Check status
+		TSisTrustStatus status = installedBase.TrustStatusL();
+			
+		// Add the SIDs belonging to the base package
+		installedBase.SidsL(aSids);
+		
+        
+
+
+		// Check weather the package is ROM based or not.
+		inROM = installedBase.IsInRomL();
+		
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		CleanupStack::PopAndDestroy(&installedBase);
+#else
+		CleanupStack::PopAndDestroy(2, &session); //session, entry
+#endif
+
+		if (inROM)
+			{
+			// return true if we're sufficiently trusted to upgrade this package
+			return SecurityCheckUtil::IsSufficientlyTrusted(aController, status.ValidationStatus());
+			}		
+		else
+			{
+			// SP or PU upgrade where the base package has been overwritten
+			return ETrue;
+			}
+		}
+	
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	CleanupStack::PopAndDestroy(&session);
+#endif
+
+	// No match found. If this is an upgrade, the we'd return false 
+	// (missing base package)
+	if (!isBase)
+		{
+		return EFalse;
+		}
+			
+	// Otherwise, if this is just a regular install, just return true.
+	return ETrue;
+	}
+	
+	
+void CRestoreMachine::CCommitWatcher::CompleteL()
+	{
+	DEBUG_PRINTF2(_L8("Restore - Restore completed with status %d"), iStatus.Int());
+	
+	TUid pubsubCategory;
+	pubsubCategory.iUid = KUidSystemCategoryValue;
+	
+	if (iStatus.Int() == KErrNone)
+		{
+		
+		TInt err = RProperty::Set(pubsubCategory, KUidSoftwareInstallKey, ESwisStatusSuccess | ESwisRestore);
+		User::LeaveIfError(err);
+		
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		// NOTE: There is a caveat here as we need to commit two independant transactions and there 
+		// exists a possibility that the second commit fails and this would leave the device in an 
+		// inconsistent state - there is no known solution for this
+		// Due to the fact that SCR allows only one transaction at a time (one writer, many readers), 
+		// the possibility of the registry commit (SCR commit) failing is less likely than an STS commit 
+		// failure - therefore we commit STS first and then the registry 
+		iStsSession.CommitL();
+		iRegistrySession.CommitTransactionL();
+#else
+		iIntegrityServices.CommitL();
+#endif
+		iMachine.Observer().CommitL();
+		}
+	else 
+		{
+		
+		TInt err = RProperty::Set(pubsubCategory, KUidSoftwareInstallKey, ESwisStatusAborted | ESwisRestore);
+		User::LeaveIfError(err);
+		iMachine.Observer().Close();
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		iStsSession.RollBackL();
+		iRegistrySession.RollbackTransactionL();
+#else
+		iIntegrityServices.RollBackL(EFalse);
+#endif
+		}
+	
+	User::LeaveIfError(RProperty::Set(pubsubCategory, KUidSoftwareInstallKey, ESwisNone));
+	iClientMessage.Complete(iStatus.Int());
+	}
+	
+TInt CRestoreMachine::CCommitWatcher::RunError(TInt aError)
+	{
+	//Close the swi observer session handle to allow transaction service
+	//to delete the observation log file.
+	iMachine.Observer().Close();
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+	TRAP_IGNORE(iStsSession.RollBackL());
+	TRAP_IGNORE(iRegistrySession.RollbackTransactionL());
+#else
+	TRAP_IGNORE(iIntegrityServices.RollBackL(EFalse));
+#endif
+	iClientMessage.Complete(aError);
+	return KErrNone;
+	}