installationservices/swi/source/swis/server/packageremover.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/swis/server/packageremover.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,896 @@
+/*
+* Copyright (c) 2007-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 <s32file.h>
+#include "pkgremovererrors.h"
+#include "siscontroller.h"
+#include "sisinstallblock.h"
+#include "sisinfo.h"
+#include "sisstring.h"
+#include "packageremover.h"
+#include "sisuid.h"
+#include "sisversion.h"
+#include "sisfieldtypes.h"
+#include "cleanuputils.h"
+#include "securitycheckutil.h"
+#include "secutils.h"
+#include "log.h"
+#include "sissupportedlanguages.h"
+#include <hash.h>
+
+using namespace Swi;
+using namespace Swi::Sis;
+
+
+// SIS registry main path
+_LIT(KRegistryPath, "\\sys\\install\\sisregistry\\");
+
+// SWI daemon private directory
+_LIT(KSwiDaemonPrivateDirectory, "\\private\\10202dce\\");
+
+// Controller and SIS file extensions
+_LIT(KControllerFileExt, ".ctl");
+_LIT(KSisFileExt, ".sis");
+_LIT(KSisXFileExt, ".sisx");
+
+// Maximum embedding depth allowed in SIS files
+const TInt KMaximumEmbeddingDepth = 8;
+
+// Length of UIDs in hex
+const TInt KUidHexLength = 8;
+
+//
+// Implementation of class CUninstalledPkgEntry
+//
+
+CUninstalledPkgEntry* CUninstalledPkgEntry::NewLC(const TUid& aUid, const TDesC& aPackageName,
+	const TDesC& aVendorName, const TVersion& aVersion, const TPackageType aPackageType,
+	const TDesC& aSisCtlFileName, const TDesC& aAssociatedStubSisName, const TDesC8& aControllerHash)
+ 	{
+ 	CUninstalledPkgEntry* self = new(ELeave) CUninstalledPkgEntry();
+ 	CleanupStack::PushL(self);
+ 	self->ConstructL(aUid, aPackageName, aVendorName, aVersion, aPackageType,
+ 					aSisCtlFileName, aAssociatedStubSisName, aControllerHash);
+ 	return self;
+ 	}
+
+CUninstalledPkgEntry::CUninstalledPkgEntry()
+	{
+	}
+
+CUninstalledPkgEntry::~CUninstalledPkgEntry()
+	{
+	delete iVendorName;
+	delete iPackageName;
+	delete iSisCtlFileName;
+	delete iAssociatedStubSisName;
+	delete iHashController;
+	}
+
+// Constructs the objects using the property values
+void CUninstalledPkgEntry::ConstructL(const TUid& aUid, const TDesC& aPackageName,
+	const TDesC& aVendorName, const TVersion& aVersion, const TPackageType aPackageType,
+	const TDesC& aSisCtlFileName, const TDesC& aAssociatedStubSisName, const TDesC8& aControllerHash)
+	{
+	iUid = aUid;
+	iPackageName = aPackageName.AllocL();
+	iVendorName = aVendorName.AllocL();
+	iVersion = aVersion;
+	iPackageType = aPackageType;
+	iSisCtlFileName = aSisCtlFileName.AllocL();
+	iAssociatedStubSisName = aAssociatedStubSisName.AllocL();	
+	iHashController = aControllerHash.AllocL();
+	}
+
+void CUninstalledPkgEntry::SetAssociatedStubSisNameL(const TDesC& aAssociatedStubSisName)
+	{
+	delete iAssociatedStubSisName;
+	iAssociatedStubSisName = NULL;
+	iAssociatedStubSisName = aAssociatedStubSisName.AllocL();
+	}
+
+//
+// Implementation of class CPackageRemover
+//
+
+CPackageRemover* CPackageRemover::NewLC(const RMessage2& aMessage)
+	{
+	CPackageRemover* self=new(ELeave) CPackageRemover(aMessage);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CPackageRemover* CPackageRemover::NewL(const RMessage2& aMessage)
+	{
+	CPackageRemover* self=NewLC(aMessage);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+// Constructor
+CPackageRemover::CPackageRemover(const RMessage2& aMessage) :
+	iMessage(aMessage)
+	{
+	}
+
+void CPackageRemover::ConstructL()
+	{
+	DEBUG_PRINTF(_L8("Constructing CPackageRemover"));
+
+	// connect to SIS helper 
+	User::LeaveIfError(iSisHelper.Connect());
+	User::LeaveIfError(iFs.Connect());
+	User::LeaveIfError(iFs.ShareProtected());
+	// connect to SIS registry
+	User::LeaveIfError(iSisRegistry.Connect());
+	}
+
+// Delete objects, close connection to the servers
+CPackageRemover::~CPackageRemover()
+	{	
+	iFs.Close();
+	iSisHelper.Close(); 
+	iSisRegistry.Close();
+	iUninstalledPkgEntry.ResetAndDestroy();
+
+	iFileList.ResetAndDestroy();
+	iControllerList.ResetAndDestroy();
+	delete iMainController;
+	delete iControllerData;
+	}
+
+// Logic for finding uninstalled packages:
+// FIRST : Controller file path processed and added the entries into the array
+// SECOND: Stub sis path processed and verified with already added enties, if
+// not-added, then add this as new entry. 
+// There are following possibilities:
+// 1. Autopropagation enabled then both sis file and ctl file will exist - (ctl added and sis won't added)
+// In this case ctl files added into array and also the sis file path is 
+// referened from the same array entry.
+// 2. Autopropagation disabled then only ctl file exist - ctl added.
+// 3. For PA and PP type, only stub sis file exist - sis file added
+void CPackageRemover::ListL()
+	{
+	TInt driveNumber = iMessage.Int0();
+	TDriveInfo info;
+	
+	User::LeaveIfError(iFs.Drive(info, driveNumber));
+	if (!(info.iDriveAtt & KDriveAttRemovable) || (info.iDriveAtt & KDriveAttSubsted))
+		{
+		User::Leave(KErrNotRemovable);
+		}
+
+	TPath stubSisPath;
+	TPath ControllerFilePath;
+	TChar drive;
+	CDir* dir = NULL;
+	User::LeaveIfError(RFs::DriveToChar(driveNumber, drive));
+	
+	// Construct the Controller file path
+	ControllerFilePath.Append(drive);
+	ControllerFilePath.Append(KDriveDelimiter);
+	ControllerFilePath.Append(KRegistryPath);
+
+	// Get the list of controller file
+	// List the directory contents including directories
+	TInt err = KErrNone;
+	err = iFs.GetDir(ControllerFilePath, KEntryAttDir, ESortByName, dir);
+	if (err == KErrNone)
+		{
+		CleanupStack::PushL(dir);
+
+		TInt count(dir->Count());
+		for (TInt i = 0; i < count; ++i)
+			{
+			const TDesC& directoryName = (*dir)[i].iName;
+			// we expect uid directories to be 8 characters long, ignore others
+			if (directoryName.Length() != KUidHexLength)
+				{
+				continue;
+				}
+			else if (!((*dir)[i].IsDir()))
+				{
+				continue;
+				}
+			else
+				{
+				TPath ctlPath;
+				CDir* ctlFileList = NULL;
+				ctlPath.Append(ControllerFilePath);
+				ctlPath.Append((*dir)[i].iName);
+				ctlPath.Append(KPathDelimiter);
+				// List the directory contents, excluding directories, system and hidden files.
+				// i.e. just normal files
+				err = iFs.GetDir(ctlPath, KEntryAttMatchExclude | KEntryAttDir, ESortByName, ctlFileList);
+				if (err == KErrNone)
+					{
+					CleanupStack::PushL(ctlFileList);
+					// Add the un-installed controller file into an array
+					AddIfUninstalledL(*ctlFileList, ctlPath);
+					CleanupStack::PopAndDestroy(ctlFileList);
+					}
+				}
+			}
+		CleanupStack::PopAndDestroy(dir); 
+		}
+	if (err == KErrNone || err == KErrNotFound || err == KErrPathNotFound)
+		{
+		// Construct the Stub sis file path
+		stubSisPath.Append(drive);
+		stubSisPath.Append(KDriveDelimiter);
+		stubSisPath.Append(KSwiDaemonPrivateDirectory);
+	
+		// Get the list of stub sis file 
+		CDir* stubFileList = NULL;
+		// List the directory contents, excluding directories, system and hidden files.
+		// i.e. just normal files
+		err = iFs.GetDir(stubSisPath, KEntryAttMatchExclude | KEntryAttDir, ESortByName, stubFileList);
+		if (err == KErrNone)
+			{
+			CleanupStack::PushL(stubFileList);
+			// Add the un-installed stub sis file into an array
+			AddIfUninstalledL(*stubFileList, stubSisPath);
+			CleanupStack::PopAndDestroy(stubFileList);
+			}
+		}
+	if (err == KErrNone || err == KErrNotFound || err == KErrPathNotFound)
+		{
+		// write the array entries into the buffer
+		HBufC8* buffer = WriteListToBufferLC();
+		TPtr8 pBuffer = buffer->Des();
+	
+		if (iMessage.GetDesMaxLengthL(1) < pBuffer.Length())
+			{
+			TInt bufferSize = pBuffer.Size();
+			TPckgC<TInt> bufferSizePackage(bufferSize);
+			iMessage.WriteL(1, bufferSizePackage);
+			err = KErrOverflow;
+			}
+		else
+			{
+			iMessage.WriteL(1, pBuffer);
+			err = KErrNone;
+			}
+		CleanupStack::PopAndDestroy(buffer); //buffer
+		}
+	iMessage.Complete(err);
+	}
+
+void CPackageRemover::AddIfUninstalledL(const CDir& aDirName, const TDesC& aPathName)
+	{
+	TInt fileCount = aDirName.Count();
+	if(fileCount)
+		{
+		for(TInt i = 0; i < fileCount; i++)
+			{
+			const TEntry &entry = (aDirName)[i];
+
+			HBufC* fileName = HBufC::NewLC(aPathName.Length() + entry.iName.Length());
+			TPtr localFilename = fileName->Des();
+			localFilename.Copy(aPathName);
+			localFilename.Append(entry.iName);
+
+ 			// Sanity check the filename
+ 			TParsePtrC fileParser(*fileName);
+			TBool isControllerFile = (fileParser.Ext().CompareF(KControllerFileExt)) ? EFalse : ETrue;
+			TBool isSisFile = EFalse;
+			
+			if ((fileParser.Ext().CompareF(KSisFileExt)) ||
+				(fileParser.Ext().CompareF(KSisXFileExt)))
+				{
+				isSisFile = ETrue;
+				}
+			
+			if (!isSisFile && !isControllerFile)
+				{
+				// ctl and sis file only processed other files skipped
+				CleanupStack::PopAndDestroy(fileName);
+ 				continue;
+				}
+				
+			// Get hold of the controller
+			HBufC8* bufController = NULL;
+			TInt err = KErrNone;
+			
+			if (isControllerFile)
+   				{
+				// Get the controller data from the file
+				TRAP(err, bufController = GetControllerFromControllerFileLC(*fileName);
+							CleanupStack::Pop(bufController));
+   				}
+   			else 
+   				{
+   				// Get controller data from sishelper (may need to deflate controller)
+				TRAP(err, bufController = iSisHelper.GetControllerFromSisFileLC(*fileName);
+							CleanupStack::Pop(bufController));
+   				}
+			if (err != KErrNone)
+				{
+				CleanupStack::PopAndDestroy(fileName);
+ 				continue;
+				}
+	
+			CleanupStack::PushL(bufController);
+			
+			// Ensure the application is not installed
+			// Discard the 4 byte type field for consistency with
+			// all other registry entries
+			TPtrC8 typeController(bufController->Mid(4));
+			
+			if (iSisRegistry.IsInstalledL(typeController))
+				{
+				CleanupStack::PopAndDestroy(2, fileName); //fileName, bufcontroller
+				continue;
+				}
+
+			HBufC8* hashController = ComputeHashL(typeController);
+			CleanupStack::PushL(hashController);
+			TPtrC8 hashControllerPtr(hashController->Des());
+			if (IsAlreadyAddedL(hashControllerPtr, *fileName))
+				{
+				CleanupStack::PopAndDestroy(3, fileName); //fileName, bufcontroller, hashController
+				continue;
+				}
+				
+			// Create controller
+			TPtrProvider provider(bufController->Des());
+			CController* currentController = NULL;
+			TRAP(err, currentController = CController::NewL(provider));
+			if (err != KErrNone)
+				{
+				CleanupStack::PopAndDestroy(3, fileName); // filename , bufController, hashController
+ 				continue;
+				}
+				
+			CleanupStack::PushL(currentController);
+
+			TUid pkgUid = currentController->Info().Uid().Uid();
+			if (isControllerFile)
+   				{
+   				// Determine the uid from the directory name
+	   			TLex lex(aPathName.Right(9).Left(8));
+   				TUint uidValue;
+   				User::LeaveIfError(lex.Val(uidValue, EHex));
+   				TUid uuid = TUid::Uid(uidValue);
+				if (uuid != pkgUid)
+					{
+					// shouldn't add this entry as it may be malware
+					// where ctl file is placed under  a uid different from the controller'S UID
+					CleanupStack::PopAndDestroy(4, fileName); //fileName, bufcontroller, hashController, currentController
+					continue;
+					}
+   				}
+
+			Sis::TInstallType installType = currentController->Info().InstallType();
+			CUninstalledPkgEntry::TPackageType pkgType = CUninstalledPkgEntry::ESaPackage; // to suppress warning
+			switch(installType)
+				{
+				case EInstInstallation:
+					pkgType = CUninstalledPkgEntry::ESaPackage;
+					break;
+				case EInstAugmentation:
+					pkgType = CUninstalledPkgEntry::ESpPackage;
+					break;
+				case EInstPartialUpgrade:
+					pkgType = CUninstalledPkgEntry::EPuPackage;
+					break;
+				case EInstPreInstalledApp:
+					pkgType = CUninstalledPkgEntry::EPaPackage;
+					break;
+				case EInstPreInstalledPatch:
+					pkgType = CUninstalledPkgEntry::EPpPackage;
+					break;
+				default:
+					// shouldn't come here
+					User::Leave(KErrNotSupported);							
+				}
+					
+			// Localise dependency name
+			TLanguage systemLanguage = User::Language();    // Language of the current locale
+    		// Check whether the current locale is in the list of languages in the SIS file
+    		const CSupportedLanguages& languages = currentController->SupportedLanguages();
+			TInt langIndex = 0;
+			for (TInt i = 0; i < languages.Count(); i++)
+				{
+				if (systemLanguage == languages[i])
+					{
+					langIndex = i;
+					break;
+					}
+				}
+    	
+			HBufC* pkgName = currentController->Info().Names()[langIndex]->Data().AllocLC();
+			HBufC* pkgVendor = currentController->Info().VendorNames()[langIndex]->Data().AllocLC();
+			TInt major = currentController->Info().Version().Major();
+			TInt minor = currentController->Info().Version().Minor();
+			TInt build = currentController->Info().Version().Build();
+			TVersion pkgVersion(major,minor,build);
+			
+			HBufC* associateStubFile = KNullDesC().AllocLC(); // later this will be set
+			CUninstalledPkgEntry* PkgEntry = CUninstalledPkgEntry::NewLC(pkgUid, *pkgName,
+					*pkgVendor, pkgVersion, pkgType, *fileName, *associateStubFile, *hashController);
+			iUninstalledPkgEntry.AppendL(PkgEntry); // ownership is transfered to array.
+			CleanupStack::Pop(PkgEntry); 			// PkgEntry
+			// associateStubFile, pkgVendor, pkgName ,currentController, bufController, hashController and fileName
+			CleanupStack::PopAndDestroy(7, fileName); 	
+			}
+		}
+	}
+
+HBufC8* CPackageRemover::ComputeHashL(TDesC8& aController)
+	{
+	// calculate the controller hash
+	CMessageDigest* digest = CMessageDigestFactory::NewDigestLC(CMessageDigest::ESHA1);
+	digest->Update(aController);
+	TPtrC8 hash = digest->Final();	
+	HBufC8* hashBuffer = hash.AllocL();
+	CleanupStack::PopAndDestroy(digest);
+	return hashBuffer;
+	}
+
+TBool CPackageRemover::IsAlreadyAddedL(TDesC8& aHashController, const TDesC& aFileName)
+	{
+	// Ensure this entry is not already added into the array using ctl files.
+	// check with existing RArray<TUninstalledAppEntry> which contains 
+	// a list of uninstalled entries.
+	TInt count = iUninstalledPkgEntry.Count();
+	TBool same = EFalse;
+	for (TInt j = 0; j < count; ++j)
+		{
+		const TDesC8& existingHash = iUninstalledPkgEntry[j]->HashController();
+		if (aHashController.CompareF(existingHash) == 0)
+			{
+			TBool isSisFile = EFalse;
+			if ( (aFileName.Right(4).CompareF(KSisFileExt)) || 
+				 (aFileName.Right(4).CompareF(KSisXFileExt)))
+				{
+				isSisFile = ETrue;
+				}
+			if (!isSisFile)
+				{
+				// already a ctl file added in the array
+				// it may happen as copy - paste the ctl file with different name
+				// e.g copy 00000000_0000.ctl  and paste it as 00000000_1000.ctl or abc.ctl....
+				same = ETrue;
+				break;
+				}
+			if (iUninstalledPkgEntry[j]->AssociatedStubSisName() == KNullDesC)
+				{
+				iUninstalledPkgEntry[j]->SetAssociatedStubSisNameL(aFileName); 
+				}
+			same = ETrue;
+			break;
+			}
+		}
+	return same;
+	}
+
+HBufC8* CPackageRemover::WriteListToBufferLC()
+	{
+	TInt fileCount = iUninstalledPkgEntry.Count();
+	TInt length = (fileCount + 1) * sizeof (CUninstalledPkgEntry);
+	// Write the object out to a buffer, send to client
+	CBufSeg* buf = CBufSeg::NewL(length);
+	CleanupStack::PushL(buf);
+	
+	// create write stream
+	RBufWriteStream writeStream(*buf);
+	CleanupClosePushL(writeStream);
+	
+	// write the files to the stream
+	writeStream.WriteInt32L(fileCount);
+	for(TInt i = 0; i < fileCount; i++)
+		{
+		writeStream.WriteInt32L(iUninstalledPkgEntry[i]->Uid().iUid);
+		
+		const TDesC& pkgName = iUninstalledPkgEntry[i]->PackageName();
+		writeStream.WriteInt32L(pkgName.Length());
+		writeStream.WriteL(pkgName);
+		
+		const TDesC& vendorName = iUninstalledPkgEntry[i]->VendorName();
+		writeStream.WriteInt32L(vendorName.Length());
+		writeStream.WriteL(vendorName);
+		
+		writeStream.WriteInt32L(iUninstalledPkgEntry[i]->Version().iMajor);
+		writeStream.WriteInt32L(iUninstalledPkgEntry[i]->Version().iMinor);
+		writeStream.WriteInt32L(iUninstalledPkgEntry[i]->Version().iBuild);
+		writeStream.WriteInt32L(iUninstalledPkgEntry[i]->PackageType());	
+
+		const TDesC& sisCtlFileName = iUninstalledPkgEntry[i]->SisCtlFileName();
+		writeStream.WriteInt32L(sisCtlFileName.Length());
+		writeStream.WriteL(sisCtlFileName);
+		
+		const TDesC& assocatedStubName = iUninstalledPkgEntry[i]->AssociatedStubSisName();
+		writeStream.WriteInt32L(assocatedStubName.Length());
+		writeStream.WriteL(assocatedStubName);
+		}
+	
+	HBufC8* buffer = HBufC8::NewLC(buf->Size());
+	TPtr8 ptr(buffer->Des());
+	buf->Read(0, ptr, buf->Size());
+	CleanupStack::Pop(buffer);
+	CleanupStack::PopAndDestroy(2, buf); // writeStream , buf
+	CleanupStack::PushL(buffer);
+	return buffer;
+	}
+
+// Method to remove a specified uninstalled package
+void CPackageRemover::RemoveL()
+	{
+	// Get the package file
+	HBufC* packageFileName = HBufC::NewLC(iMessage.GetDesLengthL(0));
+	TPtr ptr(packageFileName->Des());
+	iMessage.ReadL(0, ptr);
+
+	// Get the associated stub file (if any)
+	HBufC* stubSisFileName = HBufC::NewLC(iMessage.GetDesLengthL(1));
+	TPtr ptrStub(stubSisFileName->Des());
+	iMessage.ReadL(1, ptrStub);
+
+	// Sanity check the filename
+	TBool isControllerFile = CheckFileL(*packageFileName);
+
+	// Get hold of the controller
+	if (isControllerFile)
+		{
+		// Get the controller data from the file
+		iControllerData = GetControllerFromControllerFileLC(*packageFileName);
+		CleanupStack::Pop(iControllerData);
+		}
+	else
+		{
+		// Get controller data from sishelper (may need to deflate controller)
+		iControllerData = iSisHelper.GetControllerFromSisFileLC(*packageFileName);
+		CleanupStack::Pop(iControllerData);
+		}
+
+
+	// Process the controller and compile a list of their referenced files
+	ProcessControllerL();
+
+	// Delete the files
+	ValidateAndDeleteFilesL();
+
+	// Delete the sis / controller file
+	// And remove the folders if they are empty
+	DeleteFile(*packageFileName);
+	DeletePathIfEmpty(*packageFileName);
+
+	// For controller files check if a corresponding stub exists
+	if (isControllerFile && (*stubSisFileName != KNullDesC))
+		{
+		// Sanity check file and ensure its a sis file
+		if (CheckFileL(*stubSisFileName) == EFalse)
+			{
+			DeleteFile(*stubSisFileName);
+			DeletePathIfEmpty(*stubSisFileName);
+			}
+		}
+
+	CleanupStack::PopAndDestroy(2, packageFileName); // stubSisFileName
+	iMessage.Complete(KErrNone);
+	}
+
+// Process the given controller (including embedded controllers) to get referenced files
+void CPackageRemover::ProcessControllerL()
+	{
+	// Create the controller
+	TPtrProvider provider(iControllerData->Des());
+	iMainController = Sis::CController::NewL(provider);
+
+	// Process the controller (including the embedded ones)
+	// Collect all the file descriptions from the install block
+	// No need to close this array!
+	Sis::CController* currentController = iMainController;
+	const RPointerArray<CFileDescription>& files = currentController->InstallBlock().FileDescriptions();
+	TInstallType installType = currentController->Info().InstallType();
+	
+	for (TInt index = 0; index < files.Count(); ++index)
+		{
+		iFileList.AppendL(new (ELeave) TFileDescAndInstallType(installType, files[index]));
+		}
+
+	TInt nestingLevel = 0;
+	iControllerList.AppendL(new (ELeave) TControllerAndLevel(nestingLevel, currentController));
+	TInt controllerIndex = -1;
+	
+	while (++controllerIndex < iControllerList.Count())
+		{
+		currentController = iControllerList[controllerIndex]->iController;
+		nestingLevel = iControllerList[controllerIndex]->iLevel;
+		
+		if (nestingLevel++ >= KMaximumEmbeddingDepth)
+			{
+			User::Leave(KErrSISTooDeeplyEmbedded);
+			}
+
+		// Get a list of embedded controllers and process them
+		const RPointerArray<Sis::CController>& subControllers = currentController->InstallBlock().EmbeddedControllers();
+		
+		for (TInt index = 0; index < subControllers.Count(); ++index)
+			{
+			currentController = subControllers[index];
+			
+			// Check if the embedded controller is installed on the device
+			// If installed do not process
+			TInt controllerDataOffset = (TInt)currentController->DataOffset();
+			TPtrC8 typeController(iControllerData->Mid(controllerDataOffset));
+			
+			// Pass on the controller plus the data after DataIndex field;
+			// otherwise CController::NewLC will crash when addition data not found.
+			if (!iSisRegistry.IsInstalledL(typeController))
+				{
+				const RPointerArray<CFileDescription>& files = currentController->InstallBlock().FileDescriptions();
+				TInstallType installType = currentController->Info().InstallType();
+				
+				for (TInt indexFiles = 0; indexFiles < files.Count(); ++indexFiles)
+					{
+					iFileList.AppendL(new (ELeave) TFileDescAndInstallType(installType, files[indexFiles]));
+					}
+				}
+
+			// Append the controller to the list
+			TControllerAndLevel* currentControllerAndLevel = new (ELeave) TControllerAndLevel(nestingLevel, currentController);
+			CleanupStack::PushL(currentControllerAndLevel);
+			iControllerList.AppendL(currentControllerAndLevel);
+			CleanupStack::Pop(currentControllerAndLevel);
+			}
+		}
+	}
+
+// Read the controller file and return the controller data
+HBufC8* CPackageRemover::GetControllerFromControllerFileLC(const TDesC& aFileName)
+	{
+	RFile file;
+	User::LeaveIfError(file.Open(iFs, aFileName, EFileRead | EFileShareReadersOnly));
+	CleanupClosePushL(file);
+	TInt fileSize;
+	User::LeaveIfError(file.Size(fileSize));
+
+	// Allocate size for controller data and controller field type (4 bytes)
+	HBufC8* bufController = HBufC8::NewLC(fileSize + 4);
+	TPtr8 ptrFileContents(bufController->Des());
+	RDesWriteStream write(ptrFileContents);
+	CleanupClosePushL(write);
+
+	RFileReadStream read(file);
+	CleanupClosePushL(read);
+
+	// Write the controller type
+	write.WriteInt32L(EFieldTypeController);
+
+	// Stream in the rest of the controller
+	write.WriteL(read);
+
+	CleanupStack::PopAndDestroy(2, &write); // read
+	CleanupStack::Pop(bufController);
+	CleanupStack::PopAndDestroy(&file);
+	CleanupStack::PushL(bufController);
+
+	return bufController;
+	}
+
+// Validate the referenced files and delete them
+// Also deletes the path if found empty
+void CPackageRemover::ValidateAndDeleteFilesL()
+	{
+	// Get the filename with full path
+	TInt driveNum;
+	User::LeaveIfError(RFs::CharToDrive(iRemovableDriveChar, driveNum));
+
+	// Validate and create final list of files to be removed
+	RPointerArray<HBufC> filesList;
+	CleanupResetAndDestroy<RPointerArray<HBufC> >::PushL(filesList);
+	TInt fileCount = iFileList.Count();
+	for (TInt index = 0; index < fileCount; ++index)
+		{
+		Sis::CFileDescription* fileDesc = iFileList[index]->iFileDesc;
+		const Sis::CString& stringTarget = iFileList[index]->iFileDesc->Target();
+		HBufC* bufFileName = stringTarget.Data().AllocLC();
+		TPtr ptr(bufFileName->Des());
+		TBool skipFile = EFalse;
+
+		// Handle special drive markers
+		if (bufFileName->Length() == 0)
+			{
+			skipFile = ETrue;
+			}
+		else if (ptr[0] == '!')
+			{
+			// For PA and PP install types replace with the removable drive
+			ptr[0] = iRemovableDriveChar;
+			// For others we have no idea what drive the user would've chosen!
+			// anyhow we will delete if the file available in removable drive and 
+			// not owned by any other package.
+			}
+		else if (ptr[0] == '$')
+			{
+			// Replace with system drive
+			// Doing this just for the heck of it (since system drive is not removable!)
+			ptr[0] = iFs.GetSystemDriveChar();
+			}
+
+		// Ensure a valid drive and path are present
+		if (!skipFile)
+			{
+			TParsePtr fileName(ptr);
+			if (!fileName.DrivePresent() || !fileName.PathPresent() || !fileName.NamePresent())
+				{
+				skipFile = ETrue;
+				}
+
+			// The file being deleted should belong to the same drive as the controller / stub sis file
+			TInt delFileDrive;
+			User::LeaveIfError(RFs::CharToDrive(ptr[0], delFileDrive));
+			if (delFileDrive != driveNum)
+				{
+				skipFile = ETrue;
+				}
+
+			// Ensure the file is not in a data-caged area
+			TFileName directory = fileName.Path();
+			if (fileDesc->Operation() == EOpNull)
+				{
+				// For FN ensure file is not in \sys or \resource
+				TPtrC sysPath(KSysPath);
+				TPtrC resourcePath(KResourcePath);
+				if ((directory.Left(sysPath.Length()).CompareF(sysPath) == 0) ||
+					(directory.Left(resourcePath.Length()).CompareF(resourcePath) == 0))
+					{
+					skipFile = ETrue;
+					}
+				}
+
+			TEntry entry;
+			TInt err = iFs.Entry(*bufFileName, entry);
+			if ((err != KErrNone) && 
+				(entry.IsTypeValid() && (!SecUtils::IsExe(entry) && !SecUtils::IsDll(entry))))
+				{
+				// Only EXE and DLL are allowed in \sys\bin
+				TPtrC binPath(KBinPath);
+				if (directory.Left(binPath.Length()).CompareF(binPath) == 0)
+					{
+					skipFile = ETrue;
+					}
+				}
+			}
+
+		if (skipFile)
+			{
+			DEBUG_PRINTF2(_L8("CPackageRemover: Skipping delete %S"), bufFileName);
+			CleanupStack::PopAndDestroy(bufFileName);
+			continue;	// Skip this file
+			}
+		else
+			{
+			// Add the file to the list of files to be removed
+			filesList.AppendL(bufFileName);
+			CleanupStack::Pop(bufFileName);		// Ownership transferred to array
+			}
+		}
+ 
+	// Filter out unorphaned files (is not part of another valid installation)
+	fileCount = filesList.Count();
+	if (fileCount > 0)
+		{
+		SecurityCheckUtil::FilterOrphanedFilesL(filesList);
+		}
+
+	// Delete files and remove empty directories
+	fileCount = filesList.Count();
+	for (TInt indx = 0; indx < fileCount; ++indx)
+		{
+		DEBUG_PRINTF2(_L8("CPackageRemover: Deleting "), filesList[indx]);
+		DeleteFile(*filesList[indx]);
+		DeletePathIfEmpty(*filesList[indx]);
+		}
+
+	CleanupStack::PopAndDestroy(&filesList);
+	}
+
+TInt CPackageRemover::DeleteFile(const TDesC& aName)
+	{
+	TInt err = iFs.Delete(aName);
+	if (err == KErrAccessDenied)
+		{
+		// File may be read-only. Clear the attribute and try again
+		iFs.SetAtt(aName, 0, KEntryAttReadOnly);
+		err = iFs.Delete(aName);
+		}
+
+	return err;
+	}
+
+// Recursively deletes all folders in the path (as long as they are empty)
+void CPackageRemover::DeletePathIfEmpty(const TDesC& aPath)
+	{
+	TParse path;
+	path.Set(aPath, NULL, NULL);
+
+	if (path.PathPresent())
+		{
+		while ((iFs.RmDir(path.DriveAndPath()) == KErrNone) && (path.PopDir() == KErrNone))
+			;
+		}
+	}
+
+// Sanity checks the filename and path
+// Returns ETrue if the file is a controller file
+TBool CPackageRemover::CheckFileL(TDesC& aFile)
+	{
+	// Sanity check the filename
+	HBufC* bufFileName = aFile.AllocLC();
+	TPtr ptrFileName(bufFileName->Des());
+	TParsePtr fileName(ptrFileName);
+	if (!fileName.DrivePresent() || !fileName.PathPresent() || !iFs.IsValidName(aFile))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	// Ensure the drive is a removable one
+	TInt driveNum;
+	iRemovableDriveChar = fileName.Drive()[0];
+	User::LeaveIfError(RFs::CharToDrive(iRemovableDriveChar, driveNum));
+
+	TDriveInfo info;
+	User::LeaveIfError(iFs.Drive(info, driveNum));
+	if (!(info.iDriveAtt & KDriveAttRemovable) || (info.iDriveAtt & KDriveAttSubsted))
+		{
+		User::Leave(KErrNotRemovable);
+		}
+
+	// Check if volume is present
+	TVolumeInfo volumeInfo;
+	User::LeaveIfError(iFs.Volume(volumeInfo, driveNum));
+
+	// Ensure the file still exists
+	RFile file;
+	TInt err = file.Open(iFs, aFile, EFileShareAny | EFileRead);
+	if (err != KErrNone)
+		{
+		User::Leave(KErrNotFound);
+		}
+	file.Close();
+
+	// Get the file type and sanity check its location and contents
+	TBool isControllerFile = EFalse;
+	isControllerFile = (fileName.Ext().Compare(KControllerFileExt)) ? EFalse : ETrue;
+	if (isControllerFile)
+		{
+		// Should be present in sys registry folder
+		User::LeaveIfError(fileName.PopDir());
+		if (fileName.Path().Compare(KRegistryPath) != 0)
+			{
+			User::Leave(KErrNotSupported);
+			}
+		}
+	else
+		{
+		// Should be present in the SWI Daemon private folder
+		if (fileName.Path().Compare(KSwiDaemonPrivateDirectory) != 0)
+			{
+			User::Leave(KErrNotSupported);
+			}
+		}
+
+	CleanupStack::PopAndDestroy(bufFileName);
+	return isControllerFile;
+	}
+