--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lowlevellibsandfws/pluginfw/Framework/frame/RegistryData.cpp Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,2557 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// This file contains the implementations of the classes
+// which manage the internal structure of the registry.
+//
+//
+
+#include <e32base.h>
+#include <e32uid.h>
+#include <s32stor.h>
+#include <s32file.h>
+#include <startup.hrh> // for EStartupStateNonCritical
+#include <e32ldr.h> // for hash checking
+#include <e32ldr_private.h> // for RLoader
+#include <bautils.h> // for BaflUtils::FileExists
+
+#include "EComDebug.h"
+#include <ecom/ecom.h>
+#include <ecom/ecomerrorcodes.h>
+#include <ecom/ecomresolverparams.h>
+#include <ecom/implementationinformation.h>
+#include "RegistryData.h"
+#include "DowngradePath.h"
+#include "DriveInfo.h"
+#include "FileUtils.h"
+#include "EComUidCodes.h"
+#include "EComInternalErrorCodes.h"
+#define UNUSED_VAR(a) a = a
+
+const TInt KRegVersion = -9999;
+const TInt KDllExtensionLength=4;
+_LIT(KDllExtension,".dll");
+//
+//CRegistryData::TInterfaceStruct
+
+/**
+Constructor for TInterfaceStruct
+@post Its member variable is granulated as (1)
+*/
+CRegistryData::TInterfaceStruct::TInterfaceStruct():
+ iImpData(1)
+ {
+ // Do nothing here
+ }
+
+/**
+This method determins the order of two TInterfaceIndex objects
+@param indexEntry1 first TInterfaceIndex object
+@param indexEntry2 second TInterfaceIndex object
+@return integer indicating the order of these two
+@pre This object is fully constructed
+*/
+TInt CRegistryData::TInterfaceStruct::CompareInfUid(const TInterfaceIndex& indexEntry1,
+ const TInterfaceIndex& indexEntry2)
+ {
+ return CompareTUidValues(indexEntry1.iInterfaceUid.iUid,indexEntry2.iInterfaceUid.iUid);
+ }
+
+//
+//CRegistryData::TImplStruct
+
+/**
+Constructor for TImplStruct
+@post Its member variables are initialised
+*/
+CRegistryData::TImplStruct::TImplStruct():
+ iCurrentImpl(NULL),
+ iUnusedImpls(1)
+ {
+ // Do nothing here
+ }
+
+/**
+This method determins the order of two TImplStruct objects
+@param aEntry1 first TImplStruct object
+@param aEntry2 second TImplStruct object
+@return integer indicating the order of these two
+@pre This object is fully constructed
+*/
+ TInt CRegistryData::TImplStruct::CompareImplStructUid(const TImplStruct& aEntry1,
+ const TImplStruct& aEntry2)
+ {
+ return CompareTUidValues(aEntry1.iCurrentImpl->iImplInfo->ImplementationUid().iUid,
+ aEntry2.iCurrentImpl->iImplInfo->ImplementationUid().iUid);
+ }
+
+/** Comparer to determine the order of a TUid object (implementation UID) in relation to and a TImplStruct object.
+@param aUid the Implementation UID to compare with.
+@param aEntry the TImplStruct object to compare aUid against.
+@return integer indicating the order of the two.
+*/
+TInt CRegistryData::TImplStruct::CompareUidAgainstImplStruct(
+ const TUid* aUid,
+ const TImplStruct& aEntry)
+ {
+ return CompareTUidValues(aUid->iUid,aEntry.iCurrentImpl->iImplInfo->ImplementationUid().iUid);
+ }
+
+//
+// CRegistryData::CImplementationData class
+
+/**
+Creates a new CImplemenatationData object. Note that CImplementationInformation needs to be constructed too,
+for this object to be fully constructed.
+@param aParent A pointer to the parent instance of CInterfaceData
+@return A pointer to the newly created object.
+@post This object is partly constructed and initialized and is on
+ the CleanupStack.
+*/
+CRegistryData::CImplementationData* CRegistryData::CImplementationData::NewLC(CInterfaceData* aParent)
+ {
+ CImplementationData* self=new(ELeave) CImplementationData(aParent);
+ CleanupStack::PushL(self);
+ return self;
+ }
+
+/**
+Creates a new CImplemenatationData object. It takes parameters to create a CImplementationInformation object,
+during 2nd phase construction and initializes iImplInfo to reference to this CImplementationInformation object.
+@param aParent A pointer to the parent instance of CInterfaceData
+@param aUid The unique Id of the new implementation
+@param aVersion The version number of the new implementation
+@param aName The display name of the new implementation
+@param aDataType The data type supported by the new implementation
+@param aOpaqueData Data for the new implementation which is not used by the ECom framework
+@param aDrive The drive that the new implementation is on
+@param aRomOnly The flag recording whether the new implementation may be loaded from ROM only
+@param aRomBased The flag recording whether the new implementation is on ROM or is a later version of one on ROM
+@return A pointer to the newly created object
+@post This object is fully constructed and initialized.
+*/
+CRegistryData::CImplementationData* CRegistryData::CImplementationData::NewL(CInterfaceData* aParent,
+ TUid aUid,
+ TInt aVersion,
+ HBufC* aName,
+ HBufC8* aDataType,
+ HBufC8* aOpaqueData,
+ TDriveUnit aDrive,
+ TBool aRomOnly,
+ TBool aRomBased)
+ {
+ CImplementationData* self=new(ELeave) CImplementationData(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL(aUid,
+ aVersion,
+ aName,
+ aDataType,
+ aOpaqueData,
+ aDrive,
+ aRomOnly,
+ aRomBased);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Creates a new CImplemenatationData object. It takes parameters to create a CImplementationInformation object,
+during 2nd phase construction and initializes iImplInfo to reference to this CImplementationInformation object.
+@param aParent A pointer to the parent instance of CInterfaceData
+@param aUid The unique Id of the new implementation
+@param aVersion The version number of the new implementation
+@param aName The display name of the new implementation
+@param aDataType The data type supported by the new implementation
+@param aOpaqueData Data for the new implementation which is not used by the ECom framework
+@param aDrive The drive that the new implementation is on
+@param aRomOnly The flag recording whether the new implementation may be loaded from ROM only
+@param aRomBased The flag recording whether the new implementation is on ROM or is a later version of one on ROM
+@param aExtendedInterfaces The pointer to the array recording the extended interfaces supported by this implementation.
+ NULL is available for PLUGIN without extended interfaces support.
+@return A pointer to the newly created object
+@post This object is fully constructed and initialized.
+*/
+CRegistryData::CImplementationData* CRegistryData::CImplementationData::NewL(CInterfaceData* aParent,
+ TUid aUid,
+ TInt aVersion,
+ HBufC* aName,
+ HBufC8* aDataType,
+ HBufC8* aOpaqueData,
+ TDriveUnit aDrive,
+ TBool aRomOnly,
+ TBool aRomBased,
+ RExtendedInterfacesArray* aExtendedInterfaces)
+ {
+ CImplementationData* self=new(ELeave) CImplementationData(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL(aUid,
+ aVersion,
+ aName,
+ aDataType,
+ aOpaqueData,
+ aDrive,
+ aRomOnly,
+ aRomBased,
+ aExtendedInterfaces);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Constructor for CImplementationData
+@param aParent The parent interface data of this implementation
+@post Its member variables are initialised
+*/
+CRegistryData::CImplementationData::CImplementationData( CInterfaceData* aParent):
+ CBase(),
+ iImplInfo(NULL),
+ iParent(aParent)
+ {
+ // Do nothing here
+ }
+
+/**
+Destructor of CImplementationData
+*/
+CRegistryData::CImplementationData::~CImplementationData()
+ {
+ if(iImplInfo)
+ {
+ delete iImplInfo;
+ iImplInfo = NULL;
+ }
+ iParent = NULL;
+ }
+
+/**
+The object's memory has been allocated.
+@param aUid The unique Id of the new implementation
+@param aVersion The version number of the new implementation
+@param aName The display name of the new implementation
+@param aDataType The data type supported by the new implementation
+@param aOpaqueData Data for the new implementation which is not used by the ECom framework
+@param aDrive The drive that the new implementation is on
+@param aRomOnly The flag recording whether the new implementation may be loaded from ROM only
+@param aRomBased The flag recording whether the new implementation is on ROM or is a later version of one on ROM
+@pre This object is fully constructed.
+@post This object is fully constructed and initialized.
+*/
+void CRegistryData::CImplementationData::ConstructL(TUid aUid,
+ TInt aVersion,
+ HBufC* aName,
+ HBufC8* aDataType,
+ HBufC8* aOpaqueData,
+ TDriveUnit aDrive,
+ TBool aRomOnly,
+ TBool aRomBased)
+ {
+ CImplementationInformation* newImpl = CImplementationInformation::NewL(aUid,
+ aVersion,
+ aName,
+ aDataType,
+ aOpaqueData,
+ aDrive,
+ aRomOnly,
+ aRomBased);
+ this->iImplInfo = newImpl;
+ }
+
+/**
+The object's memory has been allocated.
+@param aUid The unique Id of the new implementation
+@param aVersion The version number of the new implementation
+@param aName The display name of the new implementation
+@param aDataType The data type supported by the new implementation
+@param aOpaqueData Data for the new implementation which is not used by the ECom framework
+@param aDrive The drive that the new implementation is on
+@param aRomOnly The flag recording whether the new implementation may be loaded from ROM only
+@param aRomBased The flag recording whether the new implementation is on ROM or is a later version of one on ROM
+@param aExtendedInterfaces The pointer to the array recording the extended interfaces supported by this implementation.
+ NULL is available for PLUGIN without extended interfaces support.
+@pre This object is fully constructed.
+@post This object is fully constructed and initialized.
+*/
+void CRegistryData::CImplementationData::ConstructL(TUid aUid,
+ TInt aVersion,
+ HBufC* aName,
+ HBufC8* aDataType,
+ HBufC8* aOpaqueData,
+ TDriveUnit aDrive,
+ TBool aRomOnly,
+ TBool aRomBased,
+ RExtendedInterfacesArray* aExtendedInterfaces)
+ {
+ CImplementationInformation* newImpl = CImplementationInformation::NewL(aUid,
+ aVersion,
+ aName,
+ aDataType,
+ aOpaqueData,
+ aDrive,
+ aRomOnly,
+ aRomBased,
+ aExtendedInterfaces);
+ this->iImplInfo = newImpl;
+ }
+
+/**
+Initialises member variable with the CImplementationInformation state specified in aStore.
+@param aStore The stream to read the data from.
+@pre This object is full constructed.
+@post This object is set to the state specified in aStore.
+*/
+void CRegistryData::CImplementationData::InternalizeL(RReadStream& aStore)
+ {
+ if (iImplInfo)
+ {
+ delete iImplInfo;
+ iImplInfo = NULL;
+ }
+ iImplInfo=CImplementationInformation::NewLC(EFalse,aStore);
+ //as we never store the drive name we need to get this from the parent
+ iImplInfo->SetDrive(iParent->iParent->iParent->iDrive);
+ CleanupStack::Pop(1);
+ }
+
+
+/**
+Writes out the state of this member variable of type CImplementationInformation to aStore.
+@param aStore The stream to store the data in.
+@pre This object is fully constructed.
+*/
+void CRegistryData::CImplementationData::ExternalizeL(RWriteStream& aStore) const
+ {
+ iImplInfo->ExternalizeL(EFalse,aStore);
+ }
+
+/**
+This method determines the order of two CImplementationData objects.
+For backward compatibility reason, ECom allows different I/Fs using
+the same implementation UID for when the device has an implementation UID
+that is not unique. Although this is not a valid or supported situation ECOM
+server should be robust.
+@see FindImplementation
+@see CompareTUidValues
+@param aImpl1 first reference to CImplementationData object
+@param aImpl2 second reference to CImplementationData object
+@return integer indicating the order of these two
+@pre This object is fully constructed
+*/
+TInt CRegistryData::CImplementationData::CompareImplUid(const CImplementationData& aImpl1,
+ const CImplementationData& aImpl2)
+ {
+ TInt ret = CompareTUidValues(aImpl1.iImplInfo->ImplementationUid().iUid, aImpl2.iImplInfo->ImplementationUid().iUid);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ // Implementation UIDs are equal, use I/F UID as tie breaker
+ return CompareTUidValues(aImpl1.iParent->iInterfaceUid.iUid, aImpl2.iParent->iInterfaceUid.iUid);
+ }
+
+/**
+Similar to CompareImplUid above. This comparer only compare the Impl UID
+and ignore the I/F UID part.
+@param aImpl1 first reference to CImplementationData object
+@param aImpl2 second reference to CImplementationData object
+@return integer indicating the order of these two
+@pre This object is fully constructed
+*/
+TInt CRegistryData::CImplementationData::CompareImplUidIgnoreIfUid(const CImplementationData& aImpl1,
+ const CImplementationData& aImpl2)
+ {
+ return CompareTUidValues(aImpl1.iImplInfo->ImplementationUid().iUid,
+ aImpl2.iImplInfo->ImplementationUid().iUid);
+ }
+
+/**
+This method determines the order of an CImplementationData object in relation
+to aUid.
+@param aUid is really TUid. Cast it back before compare.
+@param aImplData reference to CImplementationData object
+@return integer indicating the order of the two.
+*/
+TInt CRegistryData::CImplementationData::CompareUidAgainstImplData(
+ const CImplementationData& aUid,
+ const CImplementationData& aImplData)
+ {
+ // The first argument aUid is really TUid.
+ const TUid* ImplUid = reinterpret_cast<const TUid*>(&aUid);
+ return CompareTUidValues(ImplUid->iUid,
+ aImplData.iImplInfo->ImplementationUid().iUid);
+ }
+
+//
+// CRegistryData::CInterfaceData class
+
+/**
+Creates a new CInterfaceData object and leave it on the CleanupStack
+@param aInterface The unique Id of this interface.
+@param aParent A pointer to the parent dll data
+@return A pointer to the newly created class.
+@post This object is fully constructed and initialized and is on
+ the CleanupStack.
+*/
+CRegistryData::CInterfaceData* CRegistryData::CInterfaceData::NewLC(TUid aInterfaceUid,CDllData* aParent)
+ {
+ CInterfaceData* self=new(ELeave) CInterfaceData(aInterfaceUid,aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+
+/**
+Creates a new CInterfaceData object using the supplied interface id
+and leave it on the CleanupStack
+@param aParent A pointer to the parent dll data
+@return A pointer to the newly created class.
+@post This object is fully constructed and initialized and is on
+ the CleanupStack.
+*/
+CRegistryData::CInterfaceData* CRegistryData::CInterfaceData::NewLC(CDllData* aParent)
+ {
+ CInterfaceData* self=new(ELeave) CInterfaceData(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+
+CRegistryData::CInterfaceData::~CInterfaceData()
+ {
+ if(iImplementations)
+ {
+ iImplementations->ResetAndDestroy();
+ delete iImplementations;
+ iImplementations = NULL;
+ }
+ iParent = NULL;
+ }
+
+/**
+Adds the specified implementation to this interface in the registry.
+@param aImplementation The implementation to add to this interface.
+@pre This object is fully constructed.
+@post aImplementation is added to the list of implementations for this interface.
+*/
+void CRegistryData::CInterfaceData::AddL(const CImplementationData* aImplementation)
+ {
+#ifdef ECOM_TRACE
+ static int counter = 0; counter++;
+ __ECOM_TRACE6("ECOM: Implementation discovered (%04d) UID:0x%X interfaceUID:0x%X version:%d on drive:%d \"%S\"", counter, aImplementation->iImplInfo->ImplementationUid().iUid, aImplementation->iParent->iInterfaceUid.iUid, aImplementation->iImplInfo->Version(), (TInt)(aImplementation->iImplInfo->Drive()), &(aImplementation->iImplInfo->DisplayName()));
+
+#endif
+
+ User::LeaveIfError(iImplementations->Append(aImplementation));
+ }
+
+/**
+Sets the uid of this interface to aInterfaceUid.
+@param aInterfaceUid The Uid which this object should take.
+@pre This object is fully constructed.
+@post The Uid of this interface is set to aInterfaceUid
+*/
+void CRegistryData::CInterfaceData::SetInterfaceUid(TUid aInterfaceUid)
+ {
+ iInterfaceUid = aInterfaceUid;
+ }
+
+/**
+Writes out this CInterfaceData to aStore.
+@param aStore The stream to store the data in.
+@pre The state of this object is stored in the stream aStore.
+*/
+void CRegistryData::CInterfaceData::ExternalizeL(RWriteStream& aStore) const
+ {
+ aStore.WriteInt32L(iInterfaceUid.iUid);
+
+ if(iImplementations)
+ {
+ const TInt entryCount = iImplementations->Count();
+ aStore.WriteInt32L(entryCount);
+ for(TInt i = 0; i < entryCount; ++i)
+ ((*iImplementations)[i])->ExternalizeL(aStore);
+ }
+ else
+ aStore.WriteInt32L(0);
+ }
+
+/**
+Restores this CInterfaceData to the state specified in aStore.
+@param aStore The stream to read the data from.
+@param aPresent A boolean indicating whether the dll is still present
+@pre This object is full constructed.
+@post This object is set to the state specified in aStore.
+*/
+void CRegistryData::CInterfaceData::InternalizeL(RReadStream& aStore)
+ {
+ iInterfaceUid.iUid = aStore.ReadInt32L();
+
+ const TInt entryCount = aStore.ReadInt32L();
+ if(entryCount < 0)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ for(TInt i = 0; i < entryCount; ++i)
+ {
+ CImplementationData* implementation = CImplementationData::NewLC(this);
+ implementation->InternalizeL(aStore);
+ AddL(implementation);
+ CleanupStack::Pop(implementation); //now owned by this interface
+ }
+ }
+
+/**
+@param aParent A pointer to the parent dll data
+*/
+CRegistryData::CInterfaceData::CInterfaceData(CDllData* aParent) :
+ CBase(),
+ iParent(aParent)
+ {
+ // Do nothing here
+ }
+
+/**
+@param aInterfaceUid The unique Id of this interface
+@param aParent A pointer to the parent dll data
+*/
+CRegistryData::CInterfaceData::CInterfaceData(TUid aInterfaceUid, CDllData* aParent) :
+ CBase(),
+ iInterfaceUid(aInterfaceUid),
+ iParent(aParent)
+ {
+ // Do nothing here
+ }
+
+/**
+Standard second phase construction function
+@pre This object is fully constructed.
+@post This object is fully constructed and initialized.
+*/
+void CRegistryData::CInterfaceData::ConstructL()
+ {
+ iImplementations = new(ELeave) RPointerArray<CImplementationData>;
+ }
+
+//
+// CRegistryData::CDllData class
+
+/**
+Creates a new CDllData object using aEntry and leaves it on the CleanupStack
+@param aDllName the name of this dll
+@param aDllModTime the modified time of this dll
+@param aSecondUid Identifies type of the DLL. (PLUGIN or PLUGIN3)
+@param aThirdUid Identifies a component uniquely.
+@param aParent A pointer to the parent drive data
+@return A pointer to the newly created object.
+@post This object is fully constructed and initialized and on the CleanupStack.
+*/
+CRegistryData::CDllData* CRegistryData::CDllData::NewLC(const TDesC& aDllName,const TTime& aDllModTime,const TUid& aSecondUid,const TUid& aThirdUid,CDriveData* aParent)
+ {
+ CDllData* self=new(ELeave) CDllData(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL(aDllName,aDllModTime,aSecondUid,aThirdUid);
+ return self;
+ }
+
+/**
+Creates a new CDllData object using aParent and leaves it on the CleanupStack
+@param aParent A pointer to the parent drive data
+@return A pointer to the newly created object.
+@post This object is fully constructed and initialized and on the CleanupStack.
+*/
+CRegistryData::CDllData* CRegistryData::CDllData::NewLC( CDriveData* aParent)
+ {
+ CDllData* self=new(ELeave) CDllData(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+CRegistryData::CDllData::~CDllData()
+ {
+ if(iIfList)
+ {
+ // Clear the interface list and destroy its objects
+ iIfList->ResetAndDestroy();
+ delete iIfList;
+ iIfList = NULL;
+ }
+
+ // Unload this implementation dll.
+ delete iDllEntry;
+ iDllEntry = NULL;
+ iParent = NULL;
+ delete iRscFileExtension;
+ }
+
+/**
+Adds the specified interface to this dll in the registry.
+@param aInterface The interface to add to this dll
+@pre This object is fully constructed.
+@post aInterface is added to the list of interfaces in this dll.
+*/
+void CRegistryData::CDllData::AddL(const CInterfaceData* aInterface)
+ {
+ User::LeaveIfError(iIfList->Append(aInterface));
+ }
+
+/**
+Sets the resource extension for the plugin. Not set for read only internal drives.
+@param aExt The resource extension to set
+@pre This object is fully constructed.
+@post aExt is added to the object.
+*/
+void CRegistryData::CDllData::SetResourceExtL(const TDesC& aExt)
+ {
+ delete iRscFileExtension;
+ iRscFileExtension = NULL;
+ iRscFileExtension = aExt.AllocL();
+ }
+
+/**
+Set the capability,the VID and do the Security check for this DLL.
+@pre This object is fully constructed.
+@return ETrue if the security check is done successfully. Otherwise EFalse is returned.
+*/
+TBool CRegistryData::CDllData::SaveSecurityInfoL()
+ {
+ iSecurityChecked = EFalse;
+
+ //need to construct the full filename i.e. appending with the
+ //preconstructed drivepath name in CDriveData
+ TFileName dllFullName;
+ dllFullName.Append(iParent->iDrive.Name());
+ dllFullName.Append(_L("\\sys\\bin\\"));
+ dllFullName.Append(iDllEntry->GetName());
+ RLibrary::TInfoBuf infoBuf;
+ TInt ret = RLibrary::GetInfo(dllFullName, infoBuf);
+ if(ret != KErrNone)
+ {
+ return EFalse;
+ }
+ // Set the DLL's capability
+ iCapSet = infoBuf().iSecurityInfo.iCaps;
+ // Set the DLL's VID
+ iVid = infoBuf().iSecurityInfo.iVendorId;
+ // Now verify that SID identified in the resource file matches the SID of the Dll file
+ TBool match=iDllEntry->GetThirdUid() ==infoBuf().iSecurityInfo.iSecureId;
+ if (!match)
+ {
+#ifdef __ECOM_TRACE
+ __ECOM_TRACE1("ERROR: Plugin SID Mismatch ERROR for %S.", &dllFullName);
+#endif
+ return EFalse;
+ }
+
+ // Now verify the two DLL's second Uid are of the same Uid type (used for distinguising between collection/collection3)
+ match=iDllEntry->GetSecondUid() ==infoBuf().iUids[1];
+ if (!match)
+ {
+#ifdef __ECOM_TRACE
+ __ECOM_TRACE1("ERROR: Plugin UID2 Mismatch ERROR for %S.", &iDllEntry->GetName());
+#endif
+ return EFalse;
+ }
+
+ // On the emulator RLoader::CheckLibraryHash() returns KErrNotSupported.
+ // Also on the emulator RLoader does no hash checking for DLL's on removable drives.
+ // Therefore to be consistent ECOM does not do any hash checking itself on the emulator.
+ // Hence code is removed for emulator builds.
+#if !defined(__WINSCW__)
+ // Verify hash is available
+ if(iParent->iParent->iCachedDriveInfo->DriveIsRemovableL(iParent->iDrive))
+ {
+ RLoader loader;
+ TInt err = loader.Connect();
+ if(err != KErrNone)
+ {
+ return EFalse;
+ }
+ err = loader.CheckLibraryHash(dllFullName, ETrue);
+ if(err != KErrNone)
+ {
+#ifdef __ECOM_TRACE
+ __ECOM_TRACE2("INFO: Hash Check Failed for %S with error %d.", &dllFullName, err);
+#endif
+ return EFalse;
+ }
+ }
+#endif
+ iSecurityChecked = ETrue;
+ return ETrue;
+ }
+
+/**
+Check whether security check has been performed if not go retrieve it.
+@pre This object is fully constructed.
+@return ETrue if the security check is done successfully. Otherwise EFalse is returned.
+*/
+TBool CRegistryData::CDllData::ProcessSecurityCheckL()
+ {
+ if(iSecurityChecked)
+ {
+ return ETrue;
+ }
+ return SaveSecurityInfoL();
+ }
+
+
+/**
+Writes out the state of this CDllData to aStore.
+@param aStore The stream to store the data in.
+@pre This object is fully constructed.
+*/
+void CRegistryData::CDllData::ExternalizeL(RWriteStream& aStore) const
+ {
+ const CEComEntry& dllEntryData = *iDllEntry;
+ TInt size=dllEntryData.GetName().Length()-KDllExtensionLength;
+ aStore.WriteUint32L(size);
+ aStore.WriteL(dllEntryData.GetName(),size);
+
+ aStore.WriteInt32L(dllEntryData.GetSecondUid().iUid);
+ aStore.WriteInt32L(dllEntryData.GetThirdUid().iUid);
+ TPckg<TTime> modified(dllEntryData.GetModified());
+ aStore.WriteL(modified);
+
+ if(!iParent->iParent->iCachedDriveInfo->DriveIsReadOnlyInternalL(iParent->iDrive))
+ {
+ if(iRscFileExtension)
+ {
+ size = iRscFileExtension->Length();
+ aStore.WriteUint32L(size);
+ aStore.WriteL(iRscFileExtension->Des(),size);
+ }
+ else
+ {
+ aStore.WriteUint32L(0);
+ }
+ }
+
+ if(iIfList)
+ {
+ const TInt entryCount = iIfList->Count();
+ aStore.WriteInt32L(entryCount);
+ for(TInt i = 0; i < entryCount; ++i)
+ ((*iIfList)[i])->ExternalizeL(aStore);
+ }
+ else
+ aStore.WriteInt32L(0);
+ }
+
+/**
+Restores this CDllData to the state specified in aStore.
+@param aStore The stream to read the data from.
+@pre This object is fully constructed.
+@post The state of this object is restored to that specified in aStore.
+*/
+void CRegistryData::CDllData::InternalizeL(RReadStream& aStore)
+ {
+ TInt size=aStore.ReadUint32L();
+ //The next "if" checks if size < 0 not size <= 0 because it seems the ECOM server externalizes
+ //the last file name as a string with length 0. If the fix is <= 0, then it makes it
+ //incompatible with the existing applications
+ if(size < 0 || size > KMaxFileName)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ HBufC* name = HBufC::NewLC(size+KDllExtensionLength);
+ TPtr ptr=name->Des();
+ aStore.ReadL(ptr,size);
+ ptr.Append(KDllExtension);
+
+ TUid secondUid=TUid::Uid(aStore.ReadInt32L());
+ TUid thirdUid=TUid::Uid(aStore.ReadInt32L());
+ TTime dllModifiedTime;
+ TPckg<TTime> modified(dllModifiedTime);
+ aStore.ReadL(modified);
+
+ if(!iParent->iParent->iCachedDriveInfo->DriveIsReadOnlyInternalL(iParent->iDrive))
+ {
+ size = aStore.ReadUint32L();
+ if(size < 0 || size > KMaxFileName)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ if(size)
+ {
+ iRscFileExtension = HBufC::NewL(size);
+ TPtr extPtr = iRscFileExtension->Des();
+ aStore.ReadL(extPtr,size);
+ }
+ }
+
+ const TInt entryCount = aStore.ReadInt32L();
+ if(entryCount < 0)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Security check is deferred until the DLL is needed.
+ for(TInt i = 0; i < entryCount; ++i)
+ {
+ CInterfaceData* interface = CInterfaceData::NewLC(this);
+ interface->InternalizeL(aStore);
+ AddL(interface);
+ CleanupStack::Pop(interface); // now owned by dll
+ }
+ iDllEntry = CEComEntry::NewL(*name,secondUid,thirdUid);
+ iDllEntry->SetModified(dllModifiedTime);
+ CleanupStack::PopAndDestroy(name);
+ }
+
+/**
+@param aParent The parent drive data of this implementation
+*/
+CRegistryData::CDllData::CDllData( CDriveData* aParent) :
+ CBase(),
+ iParent(aParent)
+ {
+ // Do nothing here
+ //Initialize empty capabilities here
+ iCapSet.SetEmpty();
+ }
+
+/**
+Standard second phase construction function.
+@pre This object is fully constructed.
+@post This object is fully constructed and initialized.
+*/
+void CRegistryData::CDllData::ConstructL()
+ {
+ iIfList = new(ELeave) RInterfaceList(2);
+ }
+
+/**
+Standard second phase construction function with parameter.
+@param aDllName the name of this dll
+@param aDllModTime the modified time of this dll
+@param aSecondUid Distinguishes between components having the same UID1 (which distinguishes between EXEs and DLLs)
+ UID2 identifies Interface Implementation Collections (collection and collection 3)
+@param aThirdUid Identifies a component uniquely. In order to ensure that each binary that needs a distinguishing
+ UID is assigned a genuinely unique value. Symbian manages UID allocation through central database.
+@pre This object is fully constructed.
+@post This object is fully constructed and initialized.
+*/
+void CRegistryData::CDllData::ConstructL(const TDesC& aDllName,const TTime& aDllModTime,const TUid& aSecondUid,const TUid& aThirdUid)
+ {
+ iIfList = new(ELeave) RInterfaceList(2);
+ iDllEntry=CEComEntry::NewL(aDllName,aSecondUid,aThirdUid);
+ iDllEntry->SetModified(aDllModTime);
+ }
+
+
+/**
+Populate a caller-supplied TEntry instance with the data from this dll.
+@param aEntry An entry to be populated (destination)
+*/
+void CRegistryData::CDllData::PopulateAnEntry(TEntry& aEntry) const
+ {
+ TPtr bufPtr=aEntry.iName.Des();
+ bufPtr.Zero();
+ bufPtr.Append(iParent->iDrive.Name());
+ bufPtr.Append(_L("\\sys\\bin\\"));
+ bufPtr.Append(iDllEntry->GetName());
+ aEntry.iType = TUidType(KDynamicLibraryUid,iDllEntry->GetSecondUid(),iDllEntry->GetThirdUid());
+ aEntry.iModified= iDllEntry->GetModified();
+ }
+
+
+//
+// CRegistryData::CDriveData class
+
+
+/**
+Creates a new CDriveData object and places it on the CleanupStack
+@param aDrive Information on this drive
+@param aParent A pointer to the parent registry data
+@return A pointer to the newly created class.
+@post This object is fully constructed and initialized and on the CleanupStack.
+*/
+CRegistryData::CDriveData* CRegistryData::CDriveData::NewLC(TDriveUnit aDrive, CRegistryData* aParent)
+ {
+ CDriveData* self=new(ELeave) CDriveData(aDrive,aParent); // calls c'tor
+ CleanupStack::PushL(self); // Make the construction safe by using the cleanup stack
+ self->ConstructL(); // Complete the 'construction'.
+ return self;
+ }
+
+/**
+Destructor of CDriveData
+*/
+CRegistryData::CDriveData::~CDriveData()
+ {
+ if(iDllList)
+ {
+ // Clear the interface list and destroy its objects
+ iDllList->ResetAndDestroy();
+ delete iDllList;
+ iDllList = NULL;
+ }
+ iParent=NULL;
+ }
+
+/**
+Adds the specified CDllData to this drive data in the registry.
+@param aDll The Dll to add to this drive
+@pre This object is fully constructed.
+@post aDll is added to the list of dll on this drive.
+*/
+void CRegistryData::CDriveData::AddL(const CDllData* aDll)
+ {
+ User::LeaveIfError(iDllList->Append(aDll));
+ }
+
+/**
+Returns the index of the DLL with this Uid in the Dll list.
+@param aDllUid the UID of to be found DLL.
+@return The index of this DLL in the DLL list. KErrNotFound if not found.
+@pre This object is fully constructed.
+*/
+TInt CRegistryData::CDriveData::FindDllIndex(const TUid aDllUid) const
+ {
+ const TInt dllCount = iDllList->Count();
+ for(TInt j = 0; j < dllCount; ++j)
+ {
+ // For each dll structure check the dll UID
+ CDllData* dll = (*iDllList)[j];
+ if (aDllUid == dll->iDllEntry->GetThirdUid())
+ {
+ // it is a match
+ return j;
+ }
+ }
+ return KErrNotFound;
+ }
+
+/**
+Writes out the state of this CDriveData to file.
+@param aFs A handle to an open file server session.
+@param aDatFileName the dat file to persist to
+@pre This object is fully constructed.
+*/
+void CRegistryData::CDriveData::ExternalizeL(RFs& aFs,const TDesC& aDatFileName)
+ {
+ // attempt to create the folders if they don't already exist
+ TInt mkDirError = aFs.MkDirAll(aDatFileName);
+
+ if((mkDirError == KErrNone) || (mkDirError == KErrAlreadyExists))
+ {
+ RFileWriteStream registryStream;
+ if(registryStream.Replace(aFs,aDatFileName, EFileWrite) == KErrNone)
+ {
+ CleanupClosePushL(registryStream);
+ // Write the version number as the first thing in the file stream.
+ registryStream.WriteInt32L(KRegVersion);
+ if(iDllList)
+ {
+ TInt entryCount = iDllList->Count();
+ registryStream.WriteInt32L(entryCount);
+ // Now stream out the data
+ for(TInt i = 0; i < entryCount; ++i)
+ ((*iDllList)[i])->ExternalizeL(registryStream);
+ }
+ else
+ registryStream.WriteInt32L(0);
+ CleanupStack::PopAndDestroy(); // registryStream
+ }
+ }
+ else
+ {
+ User::Leave(mkDirError);
+ }
+ }
+
+/**
+Restores the state of this CDriveData from file.
+@param aFs A handle to an open file server session.
+@param aDatFileName the dat file name to internalize from
+@pre This object is fully constructed.
+@post The state of this object is restored to that specified
+ in the file on this drive.
+*/
+
+void CRegistryData::CDriveData::InternalizeL(RFs& aFs,const TDesC& aDatFileName)
+ {
+ DoInternalizeL(aFs, aDatFileName);
+ }
+/**
+The method internalizes the data from aRegistryStream.
+@param aFileName The ECOM registry file name.
+@leave KErrNoMemory
+@leave Some other system-wide error codes as well.
+*/
+void CRegistryData::CDriveData::DoInternalizeL(RFs& aFs, const TDesC& aFileName)
+ {
+ RFileReadStream registryStream;
+ User::LeaveIfError(registryStream.Open(aFs, aFileName, EFileRead));
+ CleanupClosePushL(registryStream);
+ // Read in version number. If its not what expected - the file is treated as corrupted.
+ const TInt version = registryStream.ReadInt32L();
+ if(version != KRegVersion)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ const TInt entryCount = registryStream.ReadInt32L();
+ if(entryCount < 0)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ for(TInt i = 0; i < entryCount; ++i)
+ {
+ CDllData* dll = CDllData::NewLC(this);
+ dll->InternalizeL(registryStream);
+ // always add the DLL, DLL security check will be deferred
+ // until the DLL is needed.
+ AddL(dll);
+ CleanupStack::Pop(dll); // now owned by drive
+ }
+ CleanupStack::PopAndDestroy();//registryStream
+ }
+
+/**
+Constructor for CDriveData
+@param aDrive Information on this drive
+@param aParent A pointer to the parent registry data
+*/
+CRegistryData::CDriveData::CDriveData(TDriveUnit aDrive, CRegistryData* aParent) :
+ CBase(),
+
+ iDrive(aDrive),
+ iParent(aParent),
+ iDriveChanged(ETrue),
+ iRegistryChanged(EFalse)
+ {
+ }
+
+/**
+Standard second phase construction function.
+@pre This object is fully constructed.
+@post This object is fully constructed and initialized.
+*/
+void CRegistryData::CDriveData::ConstructL()
+ {
+ iDllList = new(ELeave)TDll;
+ }
+
+//
+// CRegistryData class
+
+/**
+Standardized safe construction which leaves nothing on the cleanup stack.
+This overload is used by CEComImplIndexPerfTest which plots
+discovery time vs. granularity settings.
+@leave KErrNoMemory.
+@param aFs The open file session.
+@param aInterfaceImplIndexGranularity granularity of main index.
+@param aImplIndexGranularity granularity of auxiliary index.
+@return The newly created instance of the registry data.
+@post CRegistryData is fully constructed, and initialized.
+*/
+CRegistryData* CRegistryData::NewL(RFs& aFs, TInt aInterfaceImplIndexGranularity, TInt aImplIndexGranularity)
+ {
+ CRegistryData* self=new(ELeave) CRegistryData(aFs, aInterfaceImplIndexGranularity, aImplIndexGranularity); // calls c'tor
+ CleanupStack::PushL(self); // Make the construction safe by using the cleanup stack
+ self->ConstructL(); // Complete the 'construction'.
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Standardized safe construction which leaves nothing on the cleanup stack.
+This overload uses default granularities for the two indexes. These
+default values were found to provide reasonably good performance at
+the time of testing.
+@leave KErrNoMemory.
+@param aFs The open file session.
+@return The newly created instance of the registry data.
+@post CRegistryData is fully constructed, and initialized.
+*/
+CRegistryData* CRegistryData::NewL(RFs& aFs)
+ {
+ return NewL(aFs, KDefaultInterfaceImplIndexGranularity, KDefaultImplIndexGranularity);
+ }
+
+CRegistryData::~CRegistryData()
+ {
+ for(TInt index = 0; index < iInterfaceImplIndex.Count(); ++index)
+ {
+ iInterfaceImplIndex[index].Reset();
+ }
+ iInterfaceImplIndex.Reset();
+
+ // Reset only. It does not own the pointers!
+ iImplIndex.Reset();
+
+ if(iRegistrations)
+ {
+ iRegistrations->ResetAndDestroy();
+ delete iRegistrations;
+ iRegistrations = NULL;
+ }
+ // reset the cached language settings
+ RDowngradePath::Reset();
+
+ delete iCachedDriveInfo;
+ }
+
+/**
+Lists the implementations given the interface UID. The filtered list is returned in the client provided
+RImplDataArray parameter.
+@param aInterfaceUid The Uid of the interface which the implementations should provide
+@param aImplementationData Return value. The filtered list.
+*/
+void CRegistryData::ListImplementationsL(TUid aInterfaceUid,
+ RImplDataArray& aImplementationData) const
+ {
+ // If discoveries are taking place then the index is invalid so we cannot do
+ // this request
+ if(iCurrentlyDiscovering)
+ User::Leave(KEComErrListCurrentlyUnavailable);
+
+ TBool securityPassed = EFalse;
+ //Do the security check
+ TInt index = 0;
+ while (!securityPassed)
+ {
+ aImplementationData.Reset();
+ index = IndexedFind(aInterfaceUid);
+ if(index == KErrNotFound)
+ {
+ User::Leave(KEComErrNoInterfaceIdentified);
+ }
+ User::LeaveIfError(index);
+
+ TImplContainerArray& implementationList = iInterfaceImplIndex[index].iImpData;
+ for (TInt j = 0; j < implementationList.Count(); j++)
+ {
+ CImplementationData* currentImplementation = implementationList[j].iCurrentImpl;
+ CDllData* dll = currentImplementation->iParent->iParent;
+
+ securityPassed = dll->ProcessSecurityCheckL();
+ if(!securityPassed)
+ {
+ // remove the implementations of the DLL from iInterfaceImplIndex
+ // and remove the DLL from its parent DLL list.
+ DeleteDllL(dll);
+ delete dll;
+ dll = NULL;
+ // don't continue processing implementations after we have deleted the DLL
+ // because the implementations list will have changed, so we need to
+ // re-do the IndexedFind
+ break;
+ }
+ else
+ {
+ User::LeaveIfError(aImplementationData.Append(currentImplementation));
+ }
+ }
+ }
+ }
+
+/**
+Enables or disables the specified interface implementation within the registry.
+@param aImplementationUid The interface implementation to change.
+@param aState ETrue to enable the implementation, EFalse to disable it
+@return KErrNone, KEComErrEnableFailed or KEComErrDisableFailed
+@pre CRegistry is fully constructed,
+@post The implementation is now enabled or disabled as described
+ by aState.
+*/
+TInt CRegistryData::SetEnabledState(TUid aImplementationUid, TBool aState)
+ {
+ CImplementationData* impData = NULL;
+ TUid dummy={0x00000000};
+
+ (void)FindImplementation(aImplementationUid, dummy, impData);
+
+ if(impData != NULL)
+ {
+ impData->iImplInfo->SetDisabled((aState) ? EFalse : ETrue);
+ return KErrNone;
+ }
+
+ return (aState) ? KEComErrEnableFailed : KEComErrDisableFailed;
+ }
+
+
+/**
+Temporarily uninstalls the interface implementation groups upon the specified drive.
+(ie this can be undone later).
+@param aDrive The identifier of the drive to uninstall.
+@pre CRegistry is fully constructed
+@post The registered implementation groupings
+ stored upon the specified drive are no
+ longer available for use.
+*/
+void CRegistryData::TemporaryUninstallL(const TDriveUnit& aDrive)
+ {
+ // Find the appropriate drive entry and remove it...
+ // Note : the drive may have already been taken offline, so no save is possible!
+ CDriveData* drive = NULL;
+ TInt driveIndex = FindDriveL(aDrive, drive);
+ if(driveIndex != KErrNotFound)
+ {
+ TInt dllIndex = drive->iDllList->Count();
+ while(dllIndex > 0)
+ {
+ --dllIndex;
+ RemoveFromIndexL((*drive->iDllList)[dllIndex]);
+ }
+ iRegistrations->Remove(driveIndex);
+ delete drive;
+
+ DriveChanged(aDrive, ETrue);
+ }
+ // The flag iRegistryChanged has been moved to each drive.
+ }
+
+/**
+Undoes a temporary uninstall of the interface
+implementation groups upon the specified drive.
+(ie this can be undone later).
+@leave KErrNoMemory, KErrReinstallFailed.
+@param aDrive The identifier of the drive to reinstate.
+@pre CRegistry is fully constructed
+@post The registered implementation groupings
+ stored upon the specified drive are again
+ made available for use.
+*/
+void CRegistryData::UndoTemporaryUninstallL(const TDriveUnit& aDrive)
+ {
+ CDriveData* driveData = NULL;
+ // If the drive was not found then install it, otherwise do nothing because it
+ // is already there. NB. We could leave here but the problem with that is the
+ // use case where the drive has been mounted during registry load but the registrar
+ // is started afterwards, and makes calls to this method as it discovers drives
+ // for the first time.
+ if(FindDriveL(aDrive, driveData) == KErrNotFound)
+ {
+ // Add the drive entry
+ CDriveData* drive = CDriveData::NewLC(aDrive,this);
+ AddImplDataL(drive);
+ User::LeaveIfError(iRegistrations->Append(drive));
+ CleanupStack::Pop(drive); // now owned by iRegistrations
+
+ DriveChanged(aDrive, EFalse);
+
+ // NB We DO need to set iRegistryChanged = ETrue because the idx file needs to be
+ // rewritten to include the reinstalled drive
+ }
+ }
+
+/**
+Update the staus of drives in the system
+@param aDrive The drive that has changed
+@param aDriveRemoved Indicates whether a drive has been removed or added
+@pre CRegistry is fully constructed.
+@post The state of the drive has been stored
+*/
+void CRegistryData::DriveChanged(const TDriveUnit& aDrive, TBool aDriveRemoved)
+ {
+ if(aDriveRemoved)
+ {
+ iRemovedDrives |= (0x1 << aDrive);
+ }
+ else
+ {
+ iRemovedDrives &= ~(0x1 << aDrive);
+ }
+ }
+
+/**
+Find if any Dll is regsitered in the drive unit.
+@param aDrive The identifier of the drive to find if any Dll is registered.
+@return ETrue if any Dll is registered in the drive, otherwise EFalse.
+@pre CRegistry is fully constructed.
+@post If any Dll is registered in the drive is returned if successfully.
+*/
+TBool CRegistryData::IsAnyDllRegisteredWithDriveL(const TDriveUnit& aDrive)const
+ {
+ CDriveData* driveData = NULL;
+ if(FindDriveL(aDrive, driveData) == KErrNotFound)
+ {
+ User::Leave(KEComErrDriveNotFound);
+ }
+ return driveData->iDllList->Count() > 0;
+ }
+
+/**
+Determine if the specified implementation grouping already registered, but needs an update.
+@param aDllUid The interface implementation collection data to add.
+ CRegistryData takes ownership of this object
+ so it should not be on the CleanupStack.
+@param aModified The date of the last modification of the Interface
+ Implementation Collection.
+@param aUpdate An output to indicate if the registry entry requires an update.
+ (Only valid if the return is ETrue).
+@param aDriveData The drive data used to find DLL.
+@return ETrue if the Interface Implementation Collection already has a registry entry.
+ EFalse otherwise.
+@pre This object is fully constructed and there is also a valid drive entry
+ in the registry for aDrive
+@post The new data is added to the registry
+*/
+TBool CRegistryData::IsRegisteredWithDate (TUid aDllUid,
+ const TTime& aModified,
+ TBool& aUpdate,
+ CDriveData* aDriveData)
+ {
+ // Find the appropriate drive entry for this
+ // Interface Implementation Collection
+ TBool found = EFalse;
+ TInt index = aDriveData->FindDllIndex(aDllUid);
+ if(index != KErrNotFound)
+ {
+ TDll* dllList = aDriveData->iDllList;
+ CDllData* dll = (*dllList)[index];
+ const CEComEntry& dllEntry =*(dll->iDllEntry);
+ aUpdate = dllEntry.GetModified().Int64() < aModified.Int64();
+ found = ETrue;
+ }
+ return found;
+ }
+
+/**
+Adds data on a specific dll to the registry. The data to be added
+is parsed by CRegistryParser.
+@leave KErrNoMemory If the item could not be appended to the registry
+@leave KEComErrDriveNotFound If aDrive is not a valid drive
+@param aDrive The drive the registry data has been found on
+@param aFoundDriveIndex The index of the registry data for the drive
+ the interface implementation collection data has been found on.
+@param aDllData The dll data to add. CRegistryData takes ownership of this object
+ so it should not be on the CleanupStack.
+@pre This object is fully constructed and there is also a valid drive entry
+ in the registry for aDrive
+@post The new data is added to the registry
+*/
+void CRegistryData::AddDllDataL(const TDriveUnit& aDrive, TInt aFoundDriveIndex, CRegistryData::CDllData* aDllData)
+ {
+ const TInt regCount = iRegistrations->Count();
+ if(regCount == 0)
+ User::Leave(KEComErrDriveNotFound);
+
+ // Find the appropriate drive entry
+ CDriveData* drive = NULL;
+ if(aFoundDriveIndex == KErrNotFound)
+ {
+ if(FindDriveL(aDrive, drive) == KErrNotFound)
+ User::Leave(KEComErrDriveNotFound);
+ }
+ else
+ drive = (*iRegistrations)[aFoundDriveIndex];
+
+ // Append the new data to the list
+ TDll* dllList = drive->iDllList;
+
+ // NOTE : This function MUST NOT leave after the following line because
+ // aDllData will potentially be 'owned' in two places (dllList and the caller)
+ // until we return and the caller can Pop.
+ TBool checkNeeded = ETrue;
+ TInt ifListCount=aDllData->iIfList->Count();
+ for(TInt ifListCounter=0; ifListCounter < ifListCount; ifListCounter++)
+ {
+ // For each interface structure
+ CInterfaceData* interface = (*aDllData->iIfList)[ifListCounter];
+ for(TInt impNum = 0; impNum < interface->iImplementations->Count(); ++impNum)
+ {
+ CImplementationData* implData = (*interface->iImplementations)[impNum];
+ if(!InsertIntoIndexL(implData,checkNeeded))
+ {
+ interface->iImplementations->Remove(impNum); //remove from implementation array
+ delete implData; //delete object
+ }
+ }
+ }
+ //add filtered list for legitimate implementations into registry
+ User::LeaveIfError(dllList->Append(aDllData));
+
+ drive->iRegistryChanged = ETrue;
+ }
+
+/**
+Updates the data for a dll in the registry.
+@leave KErrNoMemory If the indexes cannot be rebuilt
+@param aFoundDriveIndex The index of the registry data for the drive
+ the interface implementation collection data has been found on.
+@param aDllData The updated interface implementation collection data.
+ CRegistryData takes ownership of this object
+ so it should not be on the CleanupStack.
+@pre This object is fully constructed
+@post The dll data is updated in the registry
+*/
+void CRegistryData::UpdateDllDataL(const TDriveUnit& aDrive,TInt aFoundDriveIndex, CDllData* aDllData)
+ {
+ const TInt regCount = iRegistrations->Count();
+ if(regCount == 0)
+ User::Leave(KEComErrDriveNotFound);
+
+ // Find the appropriate drive entry
+ CDriveData* drive = (*iRegistrations)[aFoundDriveIndex];
+
+ TInt index = drive->FindDllIndex(aDllData->iDllEntry->GetThirdUid());
+
+ // find the dll entry and clear that too
+ if(index != KErrNotFound)
+ {
+ // Ok its a match, so remove this registry entry and call AddDllData()
+ //to add the new dll
+ TDll* dllList = drive->iDllList;
+ CDllData* olddll = (*dllList)[index];
+ //remove 'old'implementations from iInterfaceImplIndex
+ RemoveFromIndexL(olddll);
+ //now remove old dll from the array and registry
+ dllList->Remove(index);
+ delete olddll;
+ AddDllDataL(aDrive,aFoundDriveIndex,aDllData);
+ drive->iRegistryChanged = ETrue;
+
+ }
+ if (index == KErrNotFound)
+ {
+ __ECOM_TRACE("ECOM: PANIC in CRegistryData::UpdateDllDataL(), expected DLL data missing from ECOM registry");
+ __ASSERT_DEBUG(EFalse, User::Panic (KEComServerPanicCategory, EEComPanic_CRegistryData_UpdateDllDataL_DllRegistrationMissing));
+ }
+ }
+
+/**
+The cue that newly discovered Dlls are about to be registered,
+and, therefore, the registry index will be out of date until
+DiscoveriesCompleteL is called.
+@pre CRegistrar is fully constructed
+@post iCurrentlyDiscovering is set and the index list is cleared.
+*/
+void CRegistryData::DiscoveriesBeginning() const
+ {
+ iCurrentlyDiscovering = ETrue;
+ // The registry is about to start changing so the index is now invalid
+ }
+
+/**
+The cue to rebuild the registry indexes
+@leave KErrNoMemory
+@see CStore
+@param aSuccessful Indicates whether discovery completed fully or not
+@param aProcessingType indicates the type of processing for plugins
+ for ensuring that plugins are not processed multiple times
+ during start-up phase
+@param aHasRegistryChanged The flag to indicate whether registry data has been changed
+@pre CRegistrar is fully constructed
+@post The internal access indexes have been rebuilt
+*/
+void CRegistryData::DiscoveriesCompleteL(TBool aSuccessful, TPluginProcessingTypeIdentifier aProcessingType, TBool& aHasRegistryChanged)
+ {
+ iCurrentlyDiscovering = EFalse;
+ if (!aSuccessful)
+ {
+ return;
+ }
+ //if the rediscovery is a result of iLanguageChanged, we should reset it to false
+ iLanguageChanged=EFalse;
+ // Warning: this method may be called from the CEComServer destructor.
+ // E.g. ecomservertest running OOM test on CEComServer::NewLC.
+ // The call stack:
+ // ~CEComServer delete iRegistrar, ~CRegistrar delete iDiscoverer,
+ // ~CDiscoverer calls CRegistrar::DiscoveriesComplete,
+ // then here.
+ // Hence if ! aSuccessful do not validate.
+
+ if(aProcessingType != EPluginProcessingTypeCriticalOnly)
+ {
+ ValidateRegistryL();
+ }
+ if(aProcessingType==EPluginProcessingTypeNonCriticalOnly || aProcessingType==EPluginProcessingTypeAll)
+ {
+ //first find whether there is any registry data changed
+ TInt regCount=iRegistrations->Count();
+ for(TInt i = 0; i <regCount; i++)
+ {
+ if ((*iRegistrations)[i]->iRegistryChanged)
+ {
+ aHasRegistryChanged = ETrue;
+ //now having cached that the registry has changed we need
+ //to reset this flag in ALL the CDriveData, note that it is
+ //possible that more than one drive will have the flag set
+ (*iRegistrations)[i]->iRegistryChanged=EFalse;
+ }
+ }
+ //Also indicate registry change if any drives have been removed
+ aHasRegistryChanged |= (iRemovedDrives != 0);
+ iRemovedDrives = 0;
+ }
+ }
+
+/**
+ @fn SetDiscoveryFlag(const TDriveUnit aDrive)
+ Intended Usage : Set the flag to indicate the drive has change(s)
+ Error Condition : None.
+ @param aDrive The identifier of the drive changed.
+ @pre The CRegistrar must be fully constructed
+ @post The flag is set.
+*/
+
+void CRegistryData::SetDiscoveryFlagL(const TDriveUnit& aDriveUnit)
+ {
+ CDriveData* drive = NULL;
+ TInt driveIndex = FindDriveL(aDriveUnit, drive);
+ if(driveIndex != KErrNotFound)
+ {
+ drive->iDriveChanged = ETrue;
+ }
+
+ }
+/**
+Indicates whether the registry index is currently valid. The
+index will not be valid if discoveries are currently taking place.
+If the index is not currently valid then calls to
+ListImplementationsL() cannot be serviced.
+@return ETrue if the index is currently valid, EFalse otherwise.
+@pre CRegistrar is fully constructed
+*/
+TBool CRegistryData::IndexValid() const
+ {
+ return !iCurrentlyDiscovering;
+ }
+
+/**
+@param aCapabilitySet A capability set
+@param aImplUid The Uid of the implementation for which info is required
+@param aInterfaceUid The uid of the interface associated with aImplUid to find or less than
+ 0 if uid is unknown.
+@param aEntry Output parameter which will contain the dll information
+@param aImplInfo An output parameter. If the call succeeds it will point to the found implementation information,
+ NULL otherwise.
+@param aIsOnRWDrive an output parameter. If the call is successful, this will
+ be set to ETrue if the implementation is on RW drive. EFalse if the
+ implementation is on ReadOnly drive.
+@return KErrNone if the call succeeds, KErrNotFound - no implementation found,
+ KErrPermissionDenied - the caller has not enough capabilities to load the plugin.
+@pre CRegistrar is fully constructed
+*/
+TInt CRegistryData::GetImplementationDllInfoForServer(
+ const TCapabilitySet& /*aCapabilitySet*/,
+ const TUid aImplUid,
+ const TUid aInterfaceUid,
+ TEntry& aEntry,
+ CImplementationInformation*& aImplInfo,
+ TBool& aIsOnRWDrive) const
+ {
+ aImplInfo = NULL;
+ CImplementationData* implData;
+
+ TInt res = FindImplementation(aImplUid, aInterfaceUid, implData);
+ if (KErrNone != res)
+ {
+ return res;
+ }
+
+ aImplInfo = implData->iImplInfo;
+ const CDllData* dll = implData->iParent->iParent;
+ dll->PopulateAnEntry(aEntry);
+
+ TEComCachedDriveInfoIterator iter(*iCachedDriveInfo);
+ if (! iter.SetPos(dll->iParent->iDrive))
+ {
+ res = KErrNotFound;
+ }
+ else
+ {
+ aIsOnRWDrive = iter.DriveIsWritable();
+ }
+ return res;
+ }
+
+/**
+@param aClientRequest A client request
+@param aImplUid The Uid of the implementation for which info is required
+@param aInterfaceUid The uid of the interface associated with aImplUid to find or less than
+ 0 if uid is unknown.
+@param aEntry Output parameter which will contain the dll information
+@param aImplInfo An output parameter. If the call succeeds it will point to the found implementation information,
+ NULL otherwise.
+@param aSecurityCheckNeeded The bool value to identify whether the security check is needed here. The default value is false.
+@return KErrNone if the call succeeds, KErrNotFound - no implementation found,
+ KErrPermissionDenied - the caller has not enough capabilities to load the plugin.
+@pre CRegistrar is fully constructed
+*/
+TInt CRegistryData::GetImplementationDllInfoForClientL(
+ const TClientRequest& aClientRequest,
+ const TUid aImplUid,
+ const TUid aInterfaceUid,
+ TEntry& aEntry,
+ CImplementationInformation*& aImplInfo,
+ TBool aSecurityCheckNeeded)const
+ {
+ aImplInfo = NULL;
+ TInt res = KErrNotFound;
+ CImplementationData* implData;
+ if (!aSecurityCheckNeeded)
+ {
+ //The security check has been done already. All the invalid dll have been removed.
+ res = FindImplementation(aImplUid, aInterfaceUid, implData);
+ if (KErrNone != res)
+ {
+ return res;
+ }
+ CDllData* dll = implData->iParent->iParent;
+ dll->PopulateAnEntry(aEntry);
+ aImplInfo = implData->iImplInfo;
+ }
+ else
+ {
+ TBool securityPassed = EFalse;
+ while(!securityPassed) // go out of this loop either Security check is passed or no DLL found.
+ {
+ res = FindImplementation(aImplUid, aInterfaceUid, implData);
+ if (KErrNone != res)
+ {
+ return res;
+ }
+ CDllData* dll = implData->iParent->iParent;
+ // security check is deferred to here.
+ securityPassed = dll->ProcessSecurityCheckL();
+ if(securityPassed)
+ {
+ if (!aClientRequest.CheckCapability(dll->iCapSet, *(implData->iImplInfo)))
+ {
+ return KErrPermissionDenied;
+ }
+ dll->PopulateAnEntry(aEntry);
+ aImplInfo = implData->iImplInfo;
+ }
+ else
+ {
+ // remove the implementations of the DLL from iInterfaceImplIndex
+ // and remove the DLL from its parent DLL list.
+ DeleteDllL(dll);
+ delete dll;
+ dll = NULL;
+ }
+ }
+ }
+ return res;
+ }
+
+/**
+This method removes all implementations of This Dll from the iInterfaceImplIndex,
+then delete this Dll from its parent Dll list.
+@param aDllData the Dll to be cleaned.
+@pre CRegistrar is fully constructed
+*/
+void CRegistryData::DeleteDllL(CDllData* aDllData) const
+ {
+ // find the index of the passed aDllData in its parent's Dll list.
+ TInt index = aDllData->iParent->FindDllIndex(aDllData->iDllEntry->GetThirdUid());
+
+ //removes all implementations of This Dll from the iInterfaceImplIndex
+ RemoveFromIndexL(aDllData);
+ if(index != KErrNotFound)
+ {
+ //now remove the dll from the array and registry
+ TDll* dllList = aDllData->iParent->iDllList;
+ dllList->Remove(index);
+ }
+ }
+
+
+/**
+Indicates whether the language downgrade path has changed.
+This means we need to call NearestLanguageFile again
+@return ETrue if the language downgrade path has changed, EFalse otherwise.
+@pre CRegistrar is fully constructed
+*/
+TBool CRegistryData::HasLanguageChanged() const
+ {
+ return iLanguageChanged;
+ }
+
+
+/**
+@param aFs A handle to a connected file server.
+*/
+CRegistryData::CRegistryData(RFs& aFs,
+ TInt aInterfaceImplIndexGranularity,
+ TInt aImplIndexGranularity) :
+ CBase(),
+ iFs(aFs),
+ iInterfaceImplIndex(aInterfaceImplIndexGranularity),
+ iImplIndex(aImplIndexGranularity)
+ {
+ }
+
+
+/**
+Completes the safe construction of the CRegistryData object.
+@leave KErrNoMemory.
+@pre This object is constructed
+@post This object is fully initialized
+*/
+void CRegistryData::ConstructL()
+ {
+ iCachedDriveInfo = CEComCachedDriveInfo::NewL(iFs);
+
+ // Construction of the empty registration data structure here
+ iRegistrations = new(ELeave)TRegistration;
+ iSystemDrive=iFs.GetSystemDrive();
+ // during construction we always need to call this function in
+ // order to initialise and store the language settings at boot time
+ TRAPD(err,iLanguageChanged=RDowngradePath::HasChangedL(iFs))
+ if (err==KErrNoMemory)
+ {
+ User::LeaveNoMemory();
+ }
+ }
+
+/**
+To find the index entry for aImplementationUid.
+@return The index of the item or KErrIndexEntryNotFound.
+@pre This object is fully constructed
+*/
+TInt CRegistryData::IndexedFind(TUid aInterfaceUid) const
+ {
+ // Find the correct implementation
+ TInterfaceIndex key;
+ key.iInterfaceUid = aInterfaceUid;
+ return iInterfaceImplIndex.FindInOrder(key,TLinearOrder<TInterfaceIndex>(TInterfaceStruct::CompareInfUid));
+ }
+
+/**
+Used by a TIdentityRelation to decide if two CDriveData match.
+@return ETrue if the TDriveUnit inside the indexes match.
+@param aIndexOne The first CDriveData to compare
+@param aIndexTwo The second CDriveData to compare
+*/
+TBool CRegistryData::MatchOnDrive(const CRegistryData::CDriveData& aIndexOne,
+ const CRegistryData::CDriveData& aIndexTwo)
+ {
+ return aIndexOne.iDrive == aIndexTwo.iDrive;
+ }
+
+TInt CRegistryData::FindDriveL(const TDriveUnit& aDrive,
+ CRegistryData::CDriveData*& aDriveData)const
+ {
+ TInt index = KErrNotFound;
+
+ // Set up the find parameters
+ TIdentityRelation<CRegistryData::CDriveData> identity(MatchOnDrive);
+ CDriveData* driveToMatch = CDriveData::NewLC(aDrive,const_cast<CRegistryData*>(this));
+
+ index = iRegistrations->Find(driveToMatch, identity);
+
+ CleanupStack::PopAndDestroy(driveToMatch);
+
+ if(index != KErrNotFound)
+ aDriveData = (*iRegistrations)[index];
+ else
+ aDriveData = NULL;
+
+ return index;
+ }
+
+/**
+Finds the instance of CImplementationData for given impl uid and interface uid if known.
+@return KErrNone if impl found, otherwise KErrNotFound.
+@param aImplUid The uid of the impl to find
+@param aInterfaceUid The uid of the interface associated with the impl to find or less than
+ 0 if uid is unknown
+@param aImplData Set to the instance CImplementationData found in the index or if
+ not found set to NULL. This argument is always overwritten.
+*/
+TInt CRegistryData::FindImplementation(const TUid aImplUid, const TUid aInterfaceUid,
+ CImplementationData*& aImplData) const
+ {
+ aImplData = NULL;
+ TInt i;
+ // Index is kept up to date even when discoveries are occurring
+ // therefore always search index for implementation
+
+ // if aInterfaceUid is non zero use it to find position in index list
+ if(aInterfaceUid.iUid != 0)
+ {
+ i = IndexedFind(aInterfaceUid);
+ if(i == KErrNotFound)
+ {
+ return KErrNotFound;
+ }
+
+ TInterfaceIndex listItem = iInterfaceImplIndex[i];
+ i = listItem.iImpData.FindInOrder(aImplUid,
+ TImplStruct::CompareUidAgainstImplStruct);
+ if (i >= 0)
+ {
+ aImplData = listItem.iImpData[i].iCurrentImpl;
+ return KErrNone;
+ }
+ }
+ else // not given I/F UID. Use the iImplIndex.
+ {
+ // NB: 1. Impl UID should be globally unique. It is an error if impls
+ // have same Impl UID but different i/f UIDs. It means one of the
+ // plug-in supplier made an error in the .RSS file or it could be a
+ // deliberate attach. But to maintain backward compatibility, ECOM
+ // allows this error.
+ // (Multiple impls can have same i/f UID and same Impl UID. That is
+ // the upgrade situation and only one of them get stored in iImplIndex.)
+
+ // 2. Entries in iImplIndex are ordered by Impl UID, and if duplicated,
+ // ordered by i/f UID. Here i/f UID is wild card. The situation is
+ // analogous to the array was built with InsertInOrderAllowRepeats.
+ // RPointerArray::SpecificFindInOrder is for ordered search in array
+ // with duplicates. Note: it is very expensive to instantiate
+ // a CImplementationData* just for binary search. Hence reinterpret
+ // cast the TUid* as CImplementationData*. CompareUidAgainstImplData
+ // knows to cast the first argument back to TUid.
+ i = iImplIndex.SpecificFindInOrder(
+ reinterpret_cast<const CImplementationData*>(&aImplUid),
+ TLinearOrder<CImplementationData>(CImplementationData::CompareUidAgainstImplData),
+ EArrayFindMode_First);
+ if (i == KErrNotFound)
+ {
+ return KErrNotFound;
+ }
+
+ aImplData = iImplIndex[i];
+
+ // If duplicates exist, they are sorted according to i/f UID
+ // but we cannot take advantage of this order. To miniize risk
+ // of malware using duplicate Impl UID as DOS attack, ECOM applies
+ // the rule that ROMBased plug-in preferred over non-ROMBased,
+ // higher drive letter preferred over lower drive letter, and
+ // lastly lower i/f UID preferred over higher i/f UID. Must visit
+ // every duplicate to compare their ROMBasedness and driver letter
+
+ TInt count = iImplIndex.Count();
+ for (TInt j = i + 1; j < count; j++)
+ {
+ if ( iImplIndex[j]->iImplInfo->ImplementationUid().iUid != aImplUid.iUid )
+ {
+ break;
+ }
+
+ aImplData = SelectDuplicatedImpl(aImplData, iImplIndex[j]);
+ }
+
+ return KErrNone;
+ }
+
+ return KErrNotFound;
+ }
+
+/**
+This function helps FindImplementation() to decide which of two
+implementations with duplicated implementation UID to choose.
+The selection rules are:
+1. ROM based plugins > non-ROM based.
+2. Higher drive letter > lower drive letter
+3. Lower I/F UID > Higher I/F UID (for backward compatibility reason)
+
+@param aImpl1 - one of the two implementations to compare.
+@param aImpl2 - the other implementation to compare.
+@return the preferred implementation.
+*/
+CRegistryData::CImplementationData* CRegistryData::SelectDuplicatedImpl(
+ const CImplementationData* aImpl1,
+ const CImplementationData* aImpl2) const
+ {
+
+#ifdef ECOM_TRACE
+ TPtrC oldName = aImpl1->iImplInfo->DisplayName().Left(60);
+ TPtrC newName = aImpl2->iImplInfo->DisplayName().Left(60);
+ TPtrC oldDll = aImpl1->iParent->iParent->iDllEntry->GetName();
+ TPtrC newDll = aImpl2->iParent->iParent->iDllEntry->GetName();
+#endif
+
+ const TInt KRomBasedFactor = 0x100;
+
+ TInt drive1 = aImpl1->iImplInfo->Drive();
+ if (aImpl1->iImplInfo->RomBased())
+ {
+ drive1 |= KRomBasedFactor;
+ }
+
+ TInt drive2 = aImpl2->iImplInfo->Drive();
+ if (aImpl2->iImplInfo->RomBased())
+ {
+ drive2 |= KRomBasedFactor;
+ }
+
+ if (drive1 > drive2)
+ {
+#ifdef ECOM_TRACE
+ if ((drive1 & KRomBasedFactor) && !(drive2 & KRomBasedFactor))
+ {
+ __ECOM_TRACE5("ECOM dup impl UID resolution: rejected \"%S\" i/f UID 0x%X impl UID 0x%X, select ROM based %S over R/W %S", &newName, aImpl2->iParent->iInterfaceUid.iUid, aImpl2->iImplInfo->ImplementationUid().iUid, &oldDll, &newDll);
+ }
+ else
+ {
+ __ECOM_TRACE5("ECOM dup impl UID resolution: rejected \"%S\" i/f UID 0x%X impl UID 0x%X, select higher drive %S over %S", &newName, aImpl2->iParent->iInterfaceUid.iUid, aImpl2->iImplInfo->ImplementationUid().iUid, &oldDll, &newDll);
+ }
+#endif
+
+ return const_cast<CImplementationData*>(aImpl1);
+ }
+ else if (drive1 < drive2)
+ {
+#ifdef ECOM_TRACE
+ if ((drive2 & KRomBasedFactor) && !(drive1 & KRomBasedFactor))
+ {
+ __ECOM_TRACE5("ECOM dup impl UID resolution: rejected \"%S\" i/f UID 0x%X impl UID 0x%X, select ROM based %S over R/W %S", &oldName, aImpl1->iParent->iInterfaceUid.iUid, aImpl1->iImplInfo->ImplementationUid().iUid, &newDll, &oldDll);
+ }
+ else
+ {
+ __ECOM_TRACE5("ECOM dup impl UID resolution: rejected \"%S\" i/f UID 0x%X impl UID 0x%X, select higher drive %S over %S", &oldName, aImpl1->iParent->iInterfaceUid.iUid, aImpl1->iImplInfo->ImplementationUid().iUid, &newDll, &oldDll);
+ }
+#endif
+
+ return const_cast<CImplementationData*>(aImpl2);
+ }
+ // They are on the same drive. Choose the one with lower I/F UID.
+ else if (aImpl2->iParent->iInterfaceUid.iUid < aImpl1->iParent->iInterfaceUid.iUid)
+ {
+#ifdef ECOM_TRACE
+ __ECOM_TRACE5("ECOM dup impl UID resolution: rejected \"%S\" i/f UID 0x%X impl UID 0x%X, select %S with lower i/f UID 0x%X", &oldName, aImpl1->iParent->iInterfaceUid.iUid, aImpl1->iImplInfo->ImplementationUid().iUid, &newDll, aImpl2->iParent->iInterfaceUid.iUid);
+#endif
+
+ return const_cast<CImplementationData*>(aImpl2);
+ }
+
+#ifdef ECOM_TRACE
+ __ECOM_TRACE5("ECOM dup impl UID resolution: rejected \"%S\" i/f UID 0x%X impl UID 0x%X, select %S with lower i/f UID 0x%X", &newName, aImpl2->iParent->iInterfaceUid.iUid, aImpl2->iImplInfo->ImplementationUid().iUid, &oldDll, aImpl1->iParent->iInterfaceUid.iUid);
+#endif
+
+ return const_cast<CImplementationData*>(aImpl1);
+ }
+
+/**
+Checks each entry in the registry to ensure that both the RSC file and the
+corresponding dll exist. If not the dll branch is removed
+from the tree. If a drive branch is found which contains no dlls
+it is also removed.
+@pre This object is fully constructed.
+@post Any out of date registry entries are removed from the tree.
+*/
+void CRegistryData::ValidateRegistryL()
+ {
+ TInt driveIndex = iRegistrations->Count();
+ TFileName rscFileName;
+ while(driveIndex > 0)
+ {
+ --driveIndex;
+ CDriveData* drive = (*iRegistrations)[driveIndex];
+
+ if( !iCachedDriveInfo->DriveIsReadOnlyInternalL(drive->iDrive) &&
+ drive->iDriveChanged)
+ {
+ TInt dllIndex = drive->iDllList->Count();
+ while(dllIndex > 0)
+ {
+ --dllIndex;
+ CDllData* dll = (*drive->iDllList)[dllIndex];
+ //reset the buffer first
+ rscFileName.Zero();
+ rscFileName.Append(dll->iParent->iDrive.Name());
+ rscFileName.Append(KEComResourceFilePath);
+ rscFileName.Append(dll->iDllEntry->GetName().Left(dll->iDllEntry->GetName().Length()-4));
+ if(dll->iRscFileExtension)
+ {
+ rscFileName.Append(dll->iRscFileExtension->Des());
+ }
+
+ // check the existence of RSC file in resource\plugins\ directory.
+ // RSC filename is already a full name here.
+ TBool rscFileExistence = BaflUtils::FileExists(iFs, rscFileName);
+
+ //save the security info, this will both check existence of the dll
+ //and cache the information for future use
+ TBool success=dll->SaveSecurityInfoL();
+ // If this dll is not found or the corresponding RSC file is not found, then remove it from the registry
+ if(!success || !rscFileExistence)
+ {
+ //remove all implementations of this dll from iInterfaceImplIndex
+ RemoveFromIndexL(dll);
+ drive->iDllList->Remove(dllIndex);
+ //set flag to indicate registry data has been changed
+ drive->iRegistryChanged = ETrue;
+ delete dll;
+ }
+ }
+ }
+ }
+ }
+
+/**
+Determines whether the new implmentation should be preferred over the existing implementation.
+Validates later version implementations from R/W drives.
+@param aOldImpl The array to append to
+@param aNewImpl The item to append
+@param aLegitimateImpl Flag, indicating whether current implementation is secure
+@return The preferred implementation
+@pre This object is fully constructed.
+*/
+CRegistryData::CImplementationData* CRegistryData::SelectPreferredImplL(CImplementationData* aOldImpl,
+ CImplementationData* aNewImpl,
+ TBool& aLegitimateImpl,
+ TBool aCheckIsNeeded) const
+ {
+ aLegitimateImpl = ETrue;
+
+ TBool newIsRomOnly = aNewImpl->iImplInfo->RomOnly();
+ TBool oldIsRomOnly = aOldImpl->iImplInfo->RomOnly();
+
+ /* In addition to selecting the highest version of an
+ implementation this check takes care of the following special
+ cases:
+ 1. Ensure that a higher-versioned RAM-based implementation
+ cannot override a ROM-based version
+ 2. Allows for the case where there are two versions of the
+ same ROM-only implementation on ROM, thus ensuring the
+ higher of the two versions is used.
+ */
+ if(newIsRomOnly && !oldIsRomOnly)
+ {
+ return aNewImpl;
+ }
+ else if((newIsRomOnly && oldIsRomOnly))
+ {
+ if(aNewImpl->iImplInfo->Version() > aOldImpl->iImplInfo->Version())
+ {
+ return aNewImpl;
+ }
+ else if(aNewImpl->iImplInfo->Version() == aOldImpl->iImplInfo->Version())
+ {
+ //any drive from Y-A has higher priority than Z drive
+ //any drive with a letter alphabetically greater has higher priority
+ if((aNewImpl->iImplInfo->Drive() != EDriveZ) &&
+ (aOldImpl->iImplInfo->Drive() == EDriveZ || aNewImpl->iImplInfo->Drive() > aOldImpl->iImplInfo->Drive()))
+ {
+ return aNewImpl;
+ }
+ }
+ }
+ //all new implementations which are not flagged'RomOnly'
+ else if(!newIsRomOnly && !oldIsRomOnly)
+ {
+ TBool newIsReadOnly = iCachedDriveInfo->DriveIsReadOnlyInternalL(aNewImpl->iParent->iParent->iParent->iDrive);
+ TBool oldIsReadOnly = iCachedDriveInfo->DriveIsReadOnlyInternalL(aOldImpl->iParent->iParent->iParent->iDrive);
+
+ if(aNewImpl->iImplInfo->Version() > aOldImpl->iImplInfo->Version())
+ {
+ //filter for implementations on R/W drive trying to upgrade implementations on R/O drive
+ if((!newIsReadOnly && oldIsReadOnly) && aCheckIsNeeded)
+ {
+ //test if a later implementation version on R/W drive has the same filename as the current one before upgrading.
+ //If not,...
+ if(aOldImpl->iParent->iParent->iDllEntry->GetName().CompareF(aNewImpl->iParent->iParent->iDllEntry->GetName()) == 0)
+ {
+ return aNewImpl;
+ }
+ else
+ {
+ aLegitimateImpl = EFalse; //not secure
+ return aOldImpl;
+ }
+ }
+ else
+ {
+ return aNewImpl;
+ }
+ }
+ else if(aNewImpl->iImplInfo->Version() == aOldImpl->iImplInfo->Version())
+ {
+ //any drive from Y-A has higher priority than Z drive OR
+ //any drive with a letter alphabetically greater has higher priority
+ if((aNewImpl->iImplInfo->Drive() != EDriveZ) &&
+ (aOldImpl->iImplInfo->Drive() == EDriveZ || aNewImpl->iImplInfo->Drive() > aOldImpl->iImplInfo->Drive()))
+ {
+ //filename check needs to performed on implementation from R/W drives, trying to
+ //upgrade implementations on R/O drive
+ if((!newIsReadOnly && oldIsReadOnly) && aCheckIsNeeded)
+ {
+ //test if a later implementation version on R/W drive has the same filename as the current one before upgrading.
+ //If not,...
+ if(aOldImpl->iParent->iParent->iDllEntry->GetName().CompareF(aNewImpl->iParent->iParent->iDllEntry->GetName()) == 0)
+ {
+ return aNewImpl;
+ }
+ else
+ {
+ aLegitimateImpl = EFalse; //not secure
+ return aOldImpl;
+ }
+ }
+ else
+ {
+ return aNewImpl;
+ }
+ }
+ }
+ }
+ return aOldImpl;
+ }
+
+/**
+This functions checks if a given implementation already exists in
+the indexes. If it does exist, determine if the given implementation
+should replace the existing one or not.
+@param aIdxArray The container array of the interface to hold the implementation.
+@param aNewImpl The implementation to filter.
+@param aInsertMode whether aNewIMpl is a newcomer of the interface, or an
+ update of an existing implementation, or a older version of an
+ existing implementation.
+@param aPosOfImplInArray return the index of aNewImpl in aIdxArray,
+@param aLegitimateImpl Flag,indicating whether current implementation is secure
+@pre This object is fully constructed.
+@post none
+*/
+void
+CRegistryData::FilterForLatestLegitimateImplL(TImplContainerArray& aIdxArray,
+ CImplementationData* aNewImpl,
+ TInsertImplMode& aInsertMode,
+ TInt& aPosOfImplInArray,
+ TBool& aLegitimateImpl,
+ TBool aCheckIsNeeded)
+ {
+ aInsertMode = EInsertImplUndefinedMode;
+ aLegitimateImpl = ETrue;
+ TImplStruct newImplStruct;
+ newImplStruct.iCurrentImpl = aNewImpl;
+
+ TInt idxPos = aIdxArray.FindInOrder(newImplStruct, TLinearOrder<TImplStruct> (TImplStruct::CompareImplStructUid));
+
+ aPosOfImplInArray = idxPos;
+
+ if(idxPos != KErrNotFound)
+ {
+ if(aNewImpl != SelectPreferredImplL(aIdxArray[idxPos].iCurrentImpl,
+ aNewImpl,
+ aLegitimateImpl,
+ aCheckIsNeeded))
+ {
+ aInsertMode = EInsertImplAsUnusedImpl;
+ }
+ else
+ {
+ aInsertMode = EInsertImplAsUpgradeOfExistingImpl;
+ }
+ }
+ else
+ {
+ aInsertMode = EInsertImplAsNewcomerOfInterface;
+ }
+ }
+
+void CRegistryData::ResetTInterfaceIndex(TAny* aObject)
+ {
+ TInterfaceIndex* index=reinterpret_cast<TInterfaceIndex*>(aObject);
+ index->Reset();
+ }
+
+/**
+This method retrieves the data for security checks from the iInterfaceImplIndex
+@param aImplPtr The new item to be checked
+@param aCheckIsNeeded Boolean indicating, whether a filename check is needed
+@pre This object is fully constructed.
+@post aImplPtr has been checked and added to the index, or not, depending on the
+ outcome of the checks.
+*/
+TBool CRegistryData::InsertIntoIndexL(CImplementationData* aImplPtr, TBool aCheckIsNeeded)
+ {
+ TBool legitimateImpl = ETrue;
+
+ TInterfaceIndex newIndexEl;
+ TInterfaceIndex* newElPtr;
+ //initialise
+ newIndexEl.iInterfaceUid = aImplPtr->iParent->iInterfaceUid;
+ CleanupStack::PushL(TCleanupItem(ResetTInterfaceIndex,&newIndexEl));
+
+ TInt indexPos = iInterfaceImplIndex.FindInOrder(newIndexEl,TLinearOrder<TInterfaceIndex>(TInterfaceStruct::CompareInfUid));
+
+
+ if(indexPos!=KErrNotFound)
+ newElPtr = &(iInterfaceImplIndex[indexPos]);
+ else
+ newElPtr = &newIndexEl;
+
+ // For each implementation make sure we only have the latest version
+ TInt implIdxInContainerArray(KErrNotFound);
+ TInsertImplMode insertMode;
+ FilterForLatestLegitimateImplL(newElPtr->iImpData,
+ aImplPtr,
+ insertMode,
+ implIdxInContainerArray,
+ legitimateImpl,
+ aCheckIsNeeded);
+
+ InsertImplInIndexesL(insertMode,
+ indexPos,
+ *newElPtr,
+ implIdxInContainerArray,
+ aImplPtr,
+ legitimateImpl);
+
+ CleanupStack::Pop();
+
+ if (insertMode == EInsertImplAsUpgradeOfExistingImpl)
+ {
+ TUid ImplUid = aImplPtr->iImplInfo->ImplementationUid();
+ iImplUpgradeCallBack.CallBack(ECallBackId_ImplUpgrade, &ImplUid);
+ }
+
+ return legitimateImpl;
+ }
+
+/** Handle inserting a CImplementationData in iInterfaceImplIndex and
+iImplIndex.
+
+@param aNewImpl the implementation to add to the indexes.
+@param aInsertMode indicates whether the implementation is a newcover
+ of the interface, or is an update of existing implementation
+ or is an older version of an existing implementation.
+@param aIfPosInInterfaceImplIndex is the index of the interface in
+ iInterfaceImplIndex.
+@param aNewIfIndexEl the TInterfaceIndex object containing the implementation.
+@param aImplPosInContainerArray is the index of the implementation in
+ the iImpData member of aNewIfIndexEl.
+@param aLegitimateImpl indicate if the implementation passed security check or not.
+@leave KErrNoMemory operation fails because the system is out of memory.
+@leave KErrGeneral any non-specific programming error.
+@leave KErrAlreadyExists the indexes already have an entry with the same
+ Impl. UID and Interface UID.
+*/
+void CRegistryData::InsertImplInIndexesL(TInsertImplMode aInsertMode,
+ TInt aIfPosInInterfaceImplIndex,
+ TInterfaceIndex& aNewIfIndexEl,
+ TInt aImplPosInContainerArray,
+ CImplementationData* aNewImpl,
+ TBool aLegitimateImpl)
+ {
+ if(aInsertMode == EInsertImplUndefinedMode)
+ {
+ // Will not happen because if FilterForLatestLegitimateImplL
+ // does not leave then insertMode is set to one of the valid
+ // values. If FilterForLatestLegitimateImplL leaves ecomserver exits.
+ User::Leave(KErrGeneral);
+ }
+
+ // If not a legitimate implementation, aNewImpl will be deleted.
+ // Do not add it to the two indexes.
+
+ if (!aLegitimateImpl)
+ {
+ return;
+ }
+
+ TImplContainerArray& implContainerArray = aNewIfIndexEl.iImpData;
+
+ if(aInsertMode == EInsertImplAsNewcomerOfInterface)
+ {
+ TImplStruct newImplStruct;
+ newImplStruct.iCurrentImpl = aNewImpl;
+ implContainerArray.InsertInOrderL(newImplStruct, TLinearOrder<TImplStruct> (TImplStruct::CompareImplStructUid));
+
+#ifdef _DEBUG
+ // on debug build, check for duplicated implementation UID
+ // owned by different interfaces.
+
+ TInt ii = iImplIndex.SpecificFindInOrder(
+ aNewImpl,
+ CImplementationData::CompareImplUidIgnoreIfUid,
+ EArrayFindMode_Any);
+ if (ii != KErrNotFound)
+ {
+ CImplementationData* otherImpl = iImplIndex[ii];
+ TPtrC oldName = otherImpl->iImplInfo->DisplayName().Left(60);
+ TPtrC newName = aNewImpl->iImplInfo->DisplayName().Left(60);
+ __ECOM_TRACE5("** ECOM: error Impl UID %X, I/F UID %X DLL %S duplicating I/F %X DLL %S",\\
+ aNewImpl->iImplInfo->ImplementationUid().iUid, \\
+ aNewImpl->iParent->iInterfaceUid.iUid, &newName,\\
+ otherImpl->iParent->iInterfaceUid.iUid, &oldName);
+ }
+#endif
+ }
+ else if(aInsertMode == EInsertImplAsUpgradeOfExistingImpl)
+ {
+ TImplContainer& implContainer = implContainerArray[aImplPosInContainerArray];
+ CImplementationData* oldImpl = implContainer.iCurrentImpl;
+ implContainer.iUnusedImpls.AppendL(oldImpl);
+ RemoveImplFromImplIndex(oldImpl); // ignore return code
+ implContainer.iCurrentImpl = aNewImpl;
+
+ // We are replacing existing impl with aNewImpl. If existing
+ // corresponds to a ROM-based plug-in then aNewImpl is an
+ // update and qualifies as ROM-based under current policy.
+ if(oldImpl->iImplInfo->RomBased())
+ {
+ aNewImpl->iImplInfo->SetRomBased(ETrue);
+ }
+ __ECOM_TRACE5("ECOM: Removed old implementation: UID:0x%X interfaceUID:0x%X version:%d on drive:%d \"%S\"", oldImpl->iImplInfo->ImplementationUid().iUid, oldImpl->iParent->iInterfaceUid.iUid, oldImpl->iImplInfo->Version(), (TInt)(oldImpl->iImplInfo->Drive()), &(oldImpl->iImplInfo->DisplayName()));
+ __ECOM_TRACE5("ECOM: Loaded new implementation: UID:0x%X interfaceUID:0x%X version:%d on drive:%d \"%S\"", aNewImpl->iImplInfo->ImplementationUid().iUid, aNewImpl->iParent->iInterfaceUid.iUid, aNewImpl->iImplInfo->Version(), (TInt)(aNewImpl->iImplInfo->Drive()), &(aNewImpl->iImplInfo->DisplayName()));
+ }
+ else if (aInsertMode == EInsertImplAsUnusedImpl)
+ {
+ TImplContainer& implContainer = implContainerArray[aImplPosInContainerArray];
+ implContainer.iUnusedImpls.AppendL(aNewImpl);
+
+ CImplementationData* currImpl = implContainer.iCurrentImpl;
+ __ECOM_TRACE5("ECOM: Kept old implementation: UID:0x%X interfaceUID:0x%X version:%d on drive:%d \"%S\"", currImpl->iImplInfo->ImplementationUid().iUid, currImpl->iParent->iInterfaceUid.iUid, currImpl->iImplInfo->Version(), (TInt)(currImpl->iImplInfo->Drive()), &(currImpl->iImplInfo->DisplayName()));
+ __ECOM_TRACE5("ECOM: Not loaded new implementation: UID:0x%X interfaceUID:0x%X version:%d on drive:%d \"%S\"", aNewImpl->iImplInfo->ImplementationUid().iUid, aNewImpl->iParent->iInterfaceUid.iUid, aNewImpl->iImplInfo->Version(), (TInt)(aNewImpl->iImplInfo->Drive()), &(aNewImpl->iImplInfo->DisplayName()));
+ // We are not replacing existing with aNewImpl. However,
+ // if aNewImpl corresponds to a ROM-based plug-in then the
+ // existing impl is an update and qualifies as ROM-based
+ // under current policy.
+ if(aNewImpl->iImplInfo->RomBased())
+ {
+ currImpl->iImplInfo->SetRomBased(ETrue);
+ }
+
+ return; // the trailing steps not applicable to downgrade situation
+ }
+
+ User::LeaveIfError( InsertImplIntoImplIndex(aNewImpl) );
+
+ if(aIfPosInInterfaceImplIndex==KErrNotFound)
+ {
+ iInterfaceImplIndex.InsertInOrderL(aNewIfIndexEl, TLinearOrder<TInterfaceIndex>(TInterfaceStruct::CompareInfUid));
+ }
+ }
+
+/**
+This method takes removes all implementations of a plugin from the iInterfaceImplIndex
+@param aDllData Reference to a fully constructed CDllData object
+@pre This object is constructed
+@post All implementations of the CDllData object, have been removed from the index
+*/
+void CRegistryData::RemoveFromIndexL(CDllData* aDllData) const
+ {
+ //remove 'old' implementations from iInterfaceImplIndex
+ TInt counter=0;
+ TImplStruct implStruct;
+ TInt ifListCount=aDllData->iIfList->Count();
+ while(counter < ifListCount)
+ {
+ CInterfaceData* interface = (*aDllData->iIfList)[counter];
+ TInterfaceIndex index;
+ index.iInterfaceUid = interface->iInterfaceUid;
+
+ TInt indexPos = iInterfaceImplIndex.FindInOrder(index,TLinearOrder<TInterfaceIndex>(TInterfaceStruct::CompareInfUid));
+
+ if(indexPos!=KErrNotFound)
+ {
+ TImplContainerArray* impDataArray = &(iInterfaceImplIndex[indexPos].iImpData);
+ TInt implCount=interface->iImplementations->Count();
+ for(TInt i=0; i<implCount; i++)
+ {
+ implStruct.iCurrentImpl = (*interface->iImplementations)[i];
+ TInt impPos = impDataArray->FindInOrder(implStruct, TLinearOrder<CRegistryData::TImplStruct> (TImplStruct::CompareImplStructUid));
+ if(impPos!=KErrNotFound)
+ {
+ TImplContainer& implContainer = (*impDataArray)[impPos];
+ // remove from unused list if exists
+ TInt count = implContainer.iUnusedImpls.Count();
+ while(count > 0)
+ {
+ --count;
+ if(implContainer.iUnusedImpls[count]->iParent->iParent == aDllData)
+ {
+ implContainer.iUnusedImpls.Remove(count);
+ }
+ }
+
+ // update current entry
+ if(implContainer.iCurrentImpl->iParent->iParent == aDllData)
+ {
+ // do not care about the return code.
+ RemoveImplFromImplIndex(implContainer.iCurrentImpl);
+
+ TInt implContainerUnusedImplCount=implContainer.iUnusedImpls.Count();
+ // no unused impl's therefore no rollback and remove entry
+ if(implContainerUnusedImplCount == 0)
+ {
+ implContainer.Reset();
+ impDataArray->Remove(impPos);
+ }
+ else
+ {
+ // Rollback to implementation from unused array
+ // copy first from unused array
+ TInt selectedPos = 0;
+ implContainer.iCurrentImpl = implContainer.iUnusedImpls[selectedPos];
+
+ // now check if any others in list should be preferred
+ for(count = 1;count < implContainerUnusedImplCount; count++)
+ {
+ // determine which implementation should be used.
+ // no security check required as this will have already been done when impl was
+ // first added to unused list.
+ TBool dummLegitimateImpl;
+ implContainer.iCurrentImpl = SelectPreferredImplL(implContainer.iCurrentImpl,
+ implContainer.iUnusedImpls[count],
+ dummLegitimateImpl,
+ EFalse);
+ if(implContainer.iCurrentImpl == implContainer.iUnusedImpls[count])
+ {
+ selectedPos = count;
+ }
+ }
+ implContainer.iUnusedImpls.Remove(selectedPos);
+ User::LeaveIfError(InsertImplIntoImplIndex(implContainer.iCurrentImpl));
+#ifdef ECOM_TRACE
+ {
+ CImplementationData* p = implContainer.iCurrentImpl;
+ __ECOM_TRACE5("ECOM: unused implementation restored UID:0x%X interfaceUID:0x%X version:%d on drive:%d \"%S\"", p->iImplInfo->ImplementationUid().iUid, p->iParent->iInterfaceUid.iUid, p->iImplInfo->Version(), (TInt)(p->iImplInfo->Drive()), &(p->iImplInfo->DisplayName()));
+ }
+#endif
+ }
+ }
+ }
+ }
+ if(impDataArray->Count() == 0)
+ {
+ iInterfaceImplIndex[indexPos].Reset();
+ iInterfaceImplIndex.Remove(indexPos);
+ }
+ }
+ counter++;
+ }
+ }
+
+/**
+This method inserts implementations into the index
+@param aDriveData Drive data in which we are searching the implementations
+@pre This object is fully constructed.
+@post all implemementations found, have been inserted into the index.
+*/
+void CRegistryData::AddImplDataL(CDriveData* aDriveData)
+ {
+ TBool checkIsNeeded = EFalse;
+ TInt dllCount=aDriveData->iDllList->Count();
+ for(TInt dllCounter=0; dllCounter < dllCount;dllCounter++)
+ {
+ CDllData* aDllData = (*aDriveData->iDllList)[dllCounter];
+ TInt interfaceCount=aDllData->iIfList->Count();
+ for(TInt ifListCounter=0; ifListCounter < interfaceCount; ifListCounter++)
+ {
+ // For each interface structure
+ CInterfaceData* interface = (*aDllData->iIfList)[ifListCounter];
+ TInt implementationCount=interface->iImplementations->Count();
+ for(TInt impNum = 0; impNum < implementationCount; ++impNum)
+ {
+ CImplementationData* implData = (*interface->iImplementations)[impNum];
+ TInt retValue = InsertIntoIndexL(implData, checkIsNeeded);
+ //we know that during internalize, all implementations are legitimate,
+ //as the check was already performed during discovery. No check is
+ //performed at this stage, therefore ignore return value, as it will always
+ //KErrNone
+ }
+ }
+ }
+ }
+
+/** This method removes the specified entry from iImplIndex.
+
+@param aPtr is the entry to remove
+@return True if aPtr is removed from iImplIndex. False if aPtr is not
+ in iImplIndex, i.e. nothing is removed.
+*/
+TBool CRegistryData::RemoveImplFromImplIndex(CImplementationData* aPtr) const
+ {
+ TInt i = iImplIndex.FindInOrder(aPtr, TLinearOrder<CImplementationData>(CImplementationData::CompareImplUid));
+ if (i != KErrNotFound)
+ {
+ // The array does not own the pointer. Do not delete!
+ iImplIndex.Remove(i);
+ }
+ return (i != KErrNotFound);
+ }
+
+/** This method inserts the entry aNewImpl into iImplIndex.
+
+@param aNewImpl the item to add to iImplIndex.
+@return KErrNone aNewImpl is successfully added to the index.
+ KErrAlreadyExists iImplIndex has an entry with the same
+ implementation UID and same parent Interface UID.
+ KErrNoMemory fail to insert due to out of memory.
+ Other system wide errors.
+@pre aNewImpl is fully constructed.
+*/
+TInt CRegistryData::InsertImplIntoImplIndex(CImplementationData* aNewImpl) const
+ {
+ TLinearOrder<CImplementationData> ImplUidComparator(CImplementationData::CompareImplUid);
+
+ return iImplIndex.InsertInOrder(aNewImpl, ImplUidComparator);
+ }
+
+/** This method checks whether the language downgrade path has been changed.
+If it is, save language downgrade path information and set related flag true.
+
+@param aLanguageChanged the returned value to indicate language changed.
+*/
+void CRegistryData::LanguageChangedL(TBool& aLanguageChanged)
+ {
+ iLanguageChanged = RDowngradePath::HasChangedL(iFs);
+ aLanguageChanged = iLanguageChanged;
+ }
+
+/** setter
+If need to unset the callback, use a TCallBackWithArg constructed with no
+arguments.
+*/
+void CRegistryData::SetImplUpgradeCallBack(const TCallBackWithArg& aCallBack)
+ {
+ iImplUpgradeCallBack = aCallBack;
+ }
+
+#ifdef __ECOM_SERVER_PERFORMANCE__
+/**
+This method calculates the drive, plugins, interfaces, implementations counts for the drive
+type set
+@param aType The drive type for which the counts should be calculated
+@param aCounts Holds the calculated counts
+@pre This object is constructed
+*/
+void CRegistryData::GetRegistryCountsL(TInt aType, RegistryCounts::TRegistryCounts& aCounts) const
+ {
+ aCounts.iDrives = 0;
+ aCounts.iImplementations = 0;
+ aCounts.iInterfaces = 0;
+ aCounts.iDlls = 0;
+
+ for(TInt driveIndex = 0; driveIndex< iRegistrations->Count(); driveIndex++)
+ {
+ CDriveData* drive = (*iRegistrations)[driveIndex];
+ TBool isReadOnly = iCachedDriveInfo->DriveIsReadOnlyInternalL(drive->iDrive);
+
+ if((aType == RegistryCounts::TRegistryCounts::EAll) ||
+ (aType == RegistryCounts::TRegistryCounts::ERoInternal && isReadOnly) ||
+ (aType == RegistryCounts::TRegistryCounts::ENonRoInternal && !isReadOnly))
+ {
+ aCounts.iDrives++;
+ aCounts.iDlls += drive->iDllList->Count();
+ for(TInt dllIndex = 0; dllIndex < drive->iDllList->Count(); dllIndex++)
+ {
+ CDllData* dllList = (*drive->iDllList)[dllIndex];
+ aCounts.iInterfaces += dllList->iIfList->Count();
+ for(TInt ifIndex = 0; ifIndex < dllList->iIfList->Count(); ifIndex++)
+ {
+ CInterfaceData* ifList = (*dllList->iIfList)[ifIndex];
+ aCounts.iImplementations += ifList->iImplementations->Count();
+ }
+ }
+ }
+ }
+ }
+
+#endif // __ECOM_SERVER_PERFORMANCE__