// 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;
}
CImplementationInformation* implInfo = 0;
implInfo=CImplementationInformation::NewLC(EFalse,aStore);
//as we never store the drive name we need to get this from the parent
implInfo->SetDrive(iParent->iParent->iParent->iDrive);
CleanupStack::Pop(1);
iImplInfo = implInfo;
implInfo = 0;
}
/**
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);
loader.Close();
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();
}
void CRegistryData::RemoveImplFromImplIndexCleanUp(TAny* aPtr)
{
TCleanupImplIndexEntry *aCleanup = (TCleanupImplIndexEntry*)aPtr;
aCleanup->iRegistryData->RemoveImplByAddrFromImplIndex(aCleanup->iImplEntry);
}
/**
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);
RemoveImplByAddrFromImplIndex(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)
{
TCleanupImplIndexEntry aCleanup(this, aNewImpl);
CleanupStack::PushL(TCleanupItem(RemoveImplFromImplIndexCleanUp,&aCleanup));
iInterfaceImplIndex.InsertInOrderL(aNewIfIndexEl, TLinearOrder<TInterfaceIndex>(TInterfaceStruct::CompareInfUid));
CleanupStack::Pop();
}
}
/**
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));
TImplContainerArray* impDataArray = NULL;
TInt implCount=0;
if(indexPos!=KErrNotFound)
{
impDataArray = &(iInterfaceImplIndex[indexPos].iImpData);
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.
RemoveImplByAddrFromImplIndex(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
}
}
}
//To make sure it is removed from the implIndex no matter what and that the return code is ignored.
//The previous removal is still required so that a subsequent InsertImplIntoImplIndex is possible
//for an implementation. e.g. an implementaion is on different drives and only one of htem was removed.
// The other one should now make it to the iImplIndex through InsertImplIntoImplIndex. If it wasn't
// removed, before the insert operation, it will fail since both the implementations hav the same
// impl UID.
RemoveImplByAddrFromImplIndex((*interface->iImplementations)[i]);
}
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 does a search by address and 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::RemoveImplByAddrFromImplIndex(CImplementationData* aPtr) const
{
TInt aIdx = iImplIndex.Find(aPtr);
if (aIdx != KErrNotFound)
{
// This linear pointer search ensures a safe removal of the impl from iImplIndex so that it is free from a dead object.
// The array does not own the pointer. Do not delete!
iImplIndex.Remove(aIdx);
return ETrue;
}
return EFalse;
}
/** 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__