--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/centralrepository/cenrepsrv/shrepos.cpp Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,980 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "srvdefs.h"
+#include "srvres.h"
+#include "shrepos.h"
+#include "srvrepos_noc.h"
+#include "obsrvr_noc.h"
+#include "srvparams.h"
+
+CSharedRepository* CSharedRepository::NewL(TUid aUid)
+ {
+ CSharedRepository* self = new(ELeave) CSharedRepository();
+ CleanupStack::PushL(self);
+ self->ConstructL(aUid);
+ CleanupStack::Pop(self);
+
+ // debug check that CRepository::TTransactionMode modes match those used internally
+ // from CRepositoryTransactor: internal state logic relies on this
+ // there should be a better location for these checks...
+ ASSERT(CRepository::EReadTransaction == static_cast<CRepository::TTransactionMode>(EReadTransaction));
+ ASSERT(CRepository::EConcurrentReadWriteTransaction == static_cast<CRepository::TTransactionMode>(EConcurrentReadWriteTransaction));
+ ASSERT(CRepository::EReadWriteTransaction == static_cast<CRepository::TTransactionMode>(EReadWriteTransaction));
+
+ return self;
+ }
+
+void CSharedRepository::ConstructL(TUid aUid)
+ {
+ iSimRep = CHeapRepository::NewL(aUid);
+ }
+
+CSharedRepository::CSharedRepository() : iNotificationState(ETrue)
+ {
+ }
+
+CSharedRepository::~CSharedRepository()
+ {
+ if (iSimRep)
+ {
+ delete iSimRep;
+ }
+ }
+
+TUid CSharedRepository::Uid() const
+ {
+ return iSimRep->Uid();
+ }
+
+/**
+Stores the repository in-memory content to the related repository file on drive C.
+If the operation fails, the in-memory content won't match the content of
+the repository file (which will be kept as it was before the CommitChangesL() call).
+In order to keep the consistency, the in-memory repository content is deleted now
+and restored later, on the next repository operation.
+*/
+TInt CSharedRepository::CommitChanges(TCentRepLocation aLocation)
+ {
+ iInconsistentData=ETrue;
+
+ HBufC* filePath(NULL);
+ TRAPD(err,TServerResources::CreateRepositoryFileNameL(filePath,iSimRep->Uid(),aLocation,ECre));
+ if (err!=KErrNone)
+ {
+ iSimRep->ResetContent();
+ return err;
+ }
+
+ // should not be committing while transactions are still active
+ ASSERT(!IsTransactionActive());
+ TInt ret=iSimRep->CommitChanges(TServerResources::iFs,TServerResources::iPersistsVersion,*filePath);
+ if (ret==KErrNone)
+ {
+ iInconsistentData=EFalse;
+ }
+ delete filePath;
+ return ret;
+ }
+
+// merge transaction settings (which may include entries flagged as deleted), persist and notify
+// private method relies on calling code to ensure it is permitted to make changes here.
+// if this method is committing any changes, it cancels all other sessions' transactions
+TInt CSharedRepository::DoCommitTransactionSettings(CRepositoryTransactor& aTransactor, TUint32& aKeyInfo)
+ {
+ aKeyInfo = KUnspecifiedKey;
+ if (0 == aTransactor.iTransactionSettings.Count())
+ {
+ aKeyInfo = 0; // == number of settings modified
+ return KErrNone; // nothing to do
+ }
+ TInt error = iSimRep->SettingsArray().MergeArray(aTransactor.iTransactionSettings, iSimRep->DeletedSettingsArray(), ETransactionMerge);
+ TInt numChanges = aTransactor.iTransactionSettings.Count();
+ if (numChanges == 0)
+ {
+ if (error == KErrNone)
+ {
+ aKeyInfo = 0; // no changes
+ }
+ // no changes were made, so the internal cache is still valid.
+ // This could be because there were no changes: empty list, only deletes on
+ // non-existent items (a setting created and deleted in the transaction),
+ // or because of error, such as failure of an initial realloc failure.
+ return error;
+ }
+ if (error != KErrNone)
+ {
+ // the repository is corrupted. Dump it for lazy loading later
+ ResetContent();
+
+ // mark cache as inconsistent so it is reloaded.
+ iInconsistentData = ETrue;
+ return error;
+ }
+ if (error == KErrNone)
+ {
+ // changes have been made: fail all other sessions' transactions so we can commit
+ FailAllTransactions(/*aExcludeTransactor=*/&aTransactor);
+ error = CommitChanges(); // this already calls ResetContent() in case of failure
+ }
+ if (error == KErrNone)
+ {
+ // settings are now persistent on disk: we can now notify about the changes
+ // following will notify about objects that are created and deleted in the transaction
+ // this could be made faster by having a multiple Notify method.
+ // That would also allow Notify messages to be more descriptive - ranges of Keys
+ for (TInt i = 0; i < numChanges; i++)
+ {
+ Notify(aTransactor.iTransactionSettings[i].Key());
+ }
+ aKeyInfo = /*reinterpret_cast<TUint32>*/numChanges;
+ }
+ return error;
+ }
+
+void CSharedRepository::SetMetaDataOnRead(TServerSetting& aSetting, TBool aSingleMetaFound)
+ {
+ iSimRep->SetMetaDataOnRead(aSetting, aSingleMetaFound);
+ }
+
+void CSharedRepository::SetMetaDataOnCreate(TServerSetting& aNewSetting, TUint32* aMeta)
+ {
+ if(aMeta)
+ {
+ aNewSetting.SetMeta(*aMeta);
+ }
+ else
+ {
+ // No metadata specified. First check for a matching "range" default
+ // metadata setting
+ TSettingsDefaultMeta* defaultMeta = iSimRep->RangeMetaArray().Find(aNewSetting.Key());
+ if (defaultMeta)
+ {
+ aNewSetting.SetMeta(defaultMeta->GetDefaultMetadata());
+ }
+ else
+ {
+ // Range value not found, try for a repository default
+ aNewSetting.SetMeta(iSimRep->DefaultMeta());
+ }
+ }
+ }
+
+void CSharedRepository::CreateL(TServerSetting& aSetting, TSettingsAccessPolicy*& aPolicy, TBool aFirstLoad, TBool aSingleMetaFound)
+ {
+ User::LeaveIfError(iSimRep->Create(aSetting, aPolicy, aSingleMetaFound));
+ if (!aFirstLoad)
+ {
+ Notify(aSetting.Key());
+ }
+ }
+
+// deletes an individual setting in the shared repository and makes it persistent
+// if changes are made, all sessions' transactions are failed
+TInt CSharedRepository::DeleteAndPersist(TUint32 aId)
+ {
+ TServerSetting* s = iSimRep->SettingsArray().Find(aId);
+ if(!s)
+ return KErrNotFound;
+ iSimRep->SettingsArray().Remove(aId);
+
+ // removed a setting, so must fail all sessions' transactions before commit possible
+ FailAllTransactions(/*aExcludeTransactor=*/NULL);
+ TInt error = CommitChanges();
+ if (error == KErrNone)
+ {
+ Notify(aId);
+ }
+ return error;
+ }
+
+// deletes an individual setting without making it persistent
+// must not be called while any sessions are in transactions
+TInt CSharedRepository::DeleteNoPersist(TUint32 aId)
+ {
+ // should only be calling this if no transactions are active
+ ASSERT(!IsTransactionActive());
+ TServerSetting* s = iSimRep->SettingsArray().Find(aId);
+ if(!s)
+ return KErrNotFound;
+
+ iSimRep->SettingsArray().Remove(aId);
+ return KErrNone;
+ }
+
+TInt CSharedRepository::ResetNoPersistL(TServerSetting& aSetting)
+ {
+ TServerSetting* s = iSimRep->SettingsArray().Find(aSetting.Key());
+ if ((!s) || (*s != aSetting))
+ {
+ if (s)
+ {
+ // save access policy of setting
+ TSettingsAccessPolicy* policy=s->AccessPolicy();
+ s->Transfer(aSetting);
+ // restore access policy of setting
+ s->SetAccessPolicy(policy);
+ }
+ else
+ {
+ TServerSetting setting;
+ setting.Transfer(aSetting);
+ setting.SetAccessPolicy(GetFallbackAccessPolicy(setting.Key()));
+ setting.PushL();
+ iSimRep->SettingsArray().OrderedInsertL(setting);
+
+ TInt index = iSimRep->DeletedSettingsArray().FindInUnsignedKeyOrder(aSetting.Key());
+ if (index != KErrNotFound)
+ iSimRep->DeletedSettingsArray().Remove(index);
+
+ setting.Pop();
+ }
+ }
+ else
+ {
+ return KErrGeneral;
+ }
+ return KErrNone;
+ }
+
+// if changes are made, all sessions' transactions are failed
+void CSharedRepository::ResetAndPersistL(TServerSetting& aSetting)
+ {
+ if (ResetNoPersistL(aSetting) == KErrNone)
+ {
+ // changed a setting, so must fail all sessions' transactions
+ // before commit possible
+ FailAllTransactions(/*aExcludeTransactor=*/NULL);
+ CommitChangesL();
+ Notify(aSetting.Key());
+ }
+ }
+
+TInt CSharedRepository::ResetAllNoPersistL(CSharedRepository& aNewContent)
+ {
+ // mark cache as inconsistent in case Reset fails, so it is reloaded.
+ iInconsistentData=ETrue;
+
+ // should not change repository while transactions in progress: should fail them first
+ ASSERT(!IsTransactionActive());
+ TInt newCount = (aNewContent.iSimRep)->SettingsArray().Count();
+ TInt count = iSimRep->SettingsArray().Count();
+
+ TInt newIndex = 0;
+ TInt index = 0;
+
+ while(newIndex<newCount && index<count)
+ {
+ const TServerSetting& newSetting = (aNewContent.iSimRep)->SettingsArray()[newIndex];
+ const TServerSetting& setting = iSimRep->SettingsArray()[index];
+
+ TUint32 newKey = newSetting.Key();
+ TUint32 key = setting.Key();
+
+ if(newKey<key)
+ {
+ Notify(newKey);
+ newIndex++;
+ }
+ else if(newKey==key)
+ {
+ if(newSetting!=setting)
+ {
+ Notify(key);
+ }
+ newIndex++;
+ index++;
+ }
+ else if(newKey>key)
+ {
+ Notify(key);
+ index++;
+ }
+ }
+
+ while(newIndex<newCount)
+ {
+ Notify((aNewContent.iSimRep)->SettingsArray()[newIndex++].Key());
+ }
+
+ while(index<count)
+ {
+ Notify(iSimRep->SettingsArray()[index++].Key());
+ }
+
+ // Replace current settings with settings read from ROM, this
+ // will leave settings pointing to new single policies
+ iSimRep->SettingsArray().AdoptL((aNewContent.iSimRep)->SettingsArray());
+
+ // Reset policy pointers to point at this repositories policies
+ newCount=iSimRep->SettingsArray().Count();
+ for(TInt i=0; i<newCount;i++)
+ {
+ (iSimRep->SettingsArray())[i].SetAccessPolicy(NULL);
+ TUint32 key = (iSimRep->SettingsArray())[i].Key();
+ (iSimRep->SettingsArray())[i].SetAccessPolicy(GetFallbackAccessPolicy(key));
+ }
+
+ iSimRep->DeletedSettingsArray().Reset();
+
+ iInconsistentData=EFalse;
+ return KErrNone;
+ }
+
+// returns the read security policy used if there is no per-setting policy at aId
+const TSecurityPolicy& CSharedRepository::GetFallbackReadAccessPolicy(TUint32 aId)
+ {
+ return iSimRep->GetFallbackReadAccessPolicy(aId);
+ }
+
+// returns the write security policy used if there is no per-setting policy at aId
+const TSecurityPolicy& CSharedRepository::GetFallbackWriteAccessPolicy(TUint32 aId)
+ {
+ return iSimRep->GetFallbackWriteAccessPolicy(aId);
+ }
+
+// Get pointer to security policy that applies to a given setting
+TSettingsAccessPolicy* CSharedRepository::GetFallbackAccessPolicy(TUint32 aId
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+ ,TBool aSkipSingle
+#endif
+ )
+ {
+ return iSimRep->GetFallbackAccessPolicy(aId
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+ ,aSkipSingle
+#endif
+ );
+ }
+
+
+TInt CSharedRepository::ReadSettingSavePolicyL(CIniFileIn& aFile,TServerSetting& aSetting, TSettingsAccessPolicy*& aPolicy, TBool& aSingleMetaFound)
+ {
+ return iSimRep->ReadSettingSavePolicyL(aFile, aSetting, aPolicy, aSingleMetaFound);
+ }
+
+// Merge settings in this->iSettings with the iSettings of aMergeRep
+// During an intsall/upgrade event aMergeRep will be created from the installed file
+// During an upinstall event aMergeRep will be created from the ROM file
+void CSharedRepository::MergeL(CSharedRepository& aMergeRep, TMergeType aMergeType)
+ {
+ // Process settings from main section - this updates values only
+ User::LeaveIfError(GetSettings().MergeArray(aMergeRep.GetSettings(), iSimRep->DeletedSettingsArray(), aMergeType));
+
+ //if the merging is due to a ROM Flash, we need to copy over both the NEW ROM keypsace global properties
+ //(default access policies/metadata and range policies/metadata), individual policies, we then need to ensure
+ //that the settings point at the correct individual policies and metadata.
+ if (aMergeType==ERomFlash)
+ {
+ //copy the default/range/individual policy
+ iSimRep->SetDefaultPolicy(aMergeRep.iSimRep->GetDefaultAccessPolicy());
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+ iSimRep->GetDefaultAccessPolicy().iHighKey=aMergeRep.iSimRep->GetDefaultAccessPolicy().iHighKey;
+ iSimRep->GetDefaultAccessPolicy().iKeyMask=aMergeRep.iSimRep->GetDefaultAccessPolicy().iKeyMask;
+#endif
+ iSimRep->RangePolicyArray().Reset();
+ TInt count=aMergeRep.iSimRep->RangePolicyArray().Count();
+ iSimRep->RangePolicyArray().ReserveL(count);
+ for (TInt i=0;i<count;i++)
+ {
+ iSimRep->RangePolicyArray().AppendL(aMergeRep.iSimRep->RangePolicyArray()[i]);
+ }
+ iSimRep->SinglePolicyArray().ResetAndDestroy();
+ count=aMergeRep.iSimRep->SinglePolicyArray().Count();
+ iSimRep->SinglePolicyArray().ReserveL(count);
+ for (TInt i=0;i<count;i++)
+ {
+ iSimRep->SinglePolicyArray().AppendL(aMergeRep.iSimRep->SinglePolicyArray()[i]);
+ }
+ //now need to reset the aMergeRep single policies so it is not going to destroy the
+ //individual policies as ownership has been transferred
+ aMergeRep.iSimRep->SinglePolicyArray().Reset();
+
+ //copy the default/range metadata
+ iSimRep->SetDefaultMeta(aMergeRep.iSimRep->DefaultMeta());
+ iSimRep->RangeMetaArray().Reset();
+ count=aMergeRep.iSimRep->RangeMetaArray().Count();
+ iSimRep->RangeMetaArray().ReserveL(count);
+ for (TInt i=0;i<count;i++)
+ {
+ iSimRep->RangeMetaArray().AppendL(aMergeRep.iSimRep->RangeMetaArray()[i]);
+ }
+
+ //set the timestamp,owner etc
+ iSimRep->SetTimeStamp(aMergeRep.iSimRep->TimeStamp());
+ iSimRep->SetOwner(aMergeRep.iSimRep->Owner());
+ }
+
+ // Update all access policies and meta
+ for(TInt i=0; i<iSimRep->SettingsArray().Count();i++)
+ {
+ TServerSetting& setting= iSimRep->SettingsArray()[i];
+ setting.SetAccessPolicy(GetFallbackAccessPolicy(setting.Key()));
+ }
+ }
+
+// Save timestamp of installed file
+void CSharedRepository::SetInstallTime(TTime aInstallTime)
+ {
+ iSimRep->SetTimeStamp(aInstallTime);
+ }
+
+// Handle creation or upgrade of file in install directory
+void CSharedRepository::HandleUpdateMergeL(TTime aInstallFileTimeStamp, CSharedRepository& aInstallRep)
+ {
+ MergeL(aInstallRep, ESWIUpgradeMerge);
+
+ SetInstallTime(aInstallFileTimeStamp); // Set merge timestamp
+ CommitChangesL(); // Commit changes to write system drive file
+
+ // settings are now persistent on disk: we can now notify about the changes
+ for (TInt i = 0; i < (aInstallRep.iSimRep)->SettingsArray().Count(); i++)
+ {
+ Notify((aInstallRep.iSimRep)->SettingsArray()[i].Key());
+ }
+ }
+
+// Handle merge activity due to an uninstall
+void CSharedRepository::HandleDeleteMergeL(CSharedRepository& aRomRep)
+ {
+ MergeL(aRomRep, ESWIDowngradeMerge);
+
+ SetInstallTime(0); // Reset timestamp
+ CommitChangesL(); // Commit changes to write system drive file
+
+ // settings are now persistent on disk: we can now notify about the changes
+ for (TInt i = 0; i < (aRomRep.iSimRep)->SettingsArray().Count(); i++)
+ {
+ Notify((aRomRep.iSimRep)->SettingsArray()[i].Key());
+ }
+ }
+
+
+#ifdef CENTREP_CONV_TOOL
+/**
+Statement "iInconsistentData = ETrue;" must be the first statement in the method,
+"iInconsistentData = EFalse;" must be the last. It is used for lasy-load implementation
+for the repository and solves the problem that if CommitChangesL() fails the in-memory
+repository data won't match the repository data, stored in the file.
+This routine is being retained for testing purposes
+*/
+void CSharedRepository::DoCommitChangesToIniFileL(const TDesC& aOutFileName
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+ ,TUint32 aCreVersion
+#endif
+ )
+ {
+ iInconsistentData=ETrue;
+
+ // should not be committing while transactions are still active
+ ASSERT(!IsTransactionActive());
+
+ iSimRep->DoCommitChangesToIniFileL(TServerResources::iFs,aOutFileName
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+ ,aCreVersion
+#endif
+ );
+
+ iInconsistentData = EFalse;
+ }
+#endif //CENTREP_CONV_TOOL
+
+/**
+The method reloads the repository content from a repository file.
+The current repository must be emptied (or must be empty already) before the call is made.
+@param aIniFile A reference to CIniFileIn object, which will be used to load
+ the repository content.
+@return KErrCorrupt Corrupted repository file.
+ KErrNone The repository content was seccessfully loaded into memory.
+ KErrNotFound Setting not found in the file.
+@leave System-wide error codes.
+@leave KErrGeneral It's probably a programmer's error - current CSharedRepository
+ object is partially initialised.
+*/
+TInt CSharedRepository::ReloadContentL(CIniFileIn& aIniFile, TBool aFirstLoad)
+ {
+ // Preconditions - CHeapRepository object should be an empty one.
+ if(!iSimRep->IsEmpty())
+ {
+ User::Leave(KErrGeneral);
+ }
+ TInt err = iSimRep->ReloadContentExceptSettingsL(aIniFile);
+ if(err == KErrCorrupt)
+ {
+ return err;
+ }
+ CleanupClosePushL(iSimRep->RangeMetaArray());
+ CleanupClosePushL(iSimRep->RangePolicyArray());
+
+ // Settings
+ TServerSetting setting;
+ TSettingsAccessPolicy* policy;
+ TBool singleMetaFound;
+ TCleanupItem tc(CHeapRepository::SinglePoliciesCleanup, &(iSimRep->SinglePolicyArray()));
+ CleanupStack::PushL(tc);
+ CleanupClosePushL(iSimRep->SettingsArray());
+ while((err = ReadSettingSavePolicyL(aIniFile, setting, policy, singleMetaFound)) == KErrNone)
+ {
+ setting.PushL();
+ if(iSimRep->SettingsArray().IsDefault())
+ {
+ setting.SetClean();
+ }
+ CreateL(setting, policy, aFirstLoad, singleMetaFound);
+ setting.Pop();
+ }
+ if(err == KErrNotFound)
+ {
+ err = KErrNone;
+ }
+ if (err == KErrNone)
+ {
+ CleanupStack::Pop(4,&(iSimRep->RangeMetaArray()));
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy(4,&(iSimRep->RangeMetaArray()));
+ }
+ return err;
+ }
+
+/**
+Resets current repository data - actually all of them, which may be loaded from
+the related ini file.
+The iUid data member value is kept as it was at the moment of creation of
+CSharedRepository object.
+*/
+void CSharedRepository::ResetContent()
+ {
+ iSimRep->ResetContent();
+ }
+
+/**
+This function is used to restore the notification, which was temporary disabled
+when making RestoreConsistencyL() call.
+@param aNotificationState It points to CObservable::iNotificationState data member, which
+ controls the notification state - active or disabled.
+@internalComponent
+*/
+static void RestoreNotification(void* aNotificationState)
+ {
+ TBool* notificationState = static_cast <TBool*> (aNotificationState);
+ *notificationState = ETrue;
+ }
+
+/**
+The method reloads the repository content from the related ini file if previous
+CommitChangesL() has not completed successfully.
+*/
+void CSharedRepository::RestoreConsistencyL()
+ {
+ //Do nothing if previous CommitChangesL() completed successfully.
+ if (!iInconsistentData)
+ {
+ return;
+ }
+ //Reset current repository data
+ ResetContent();
+ //Disable notifications
+ TCleanupItem restoreNotification(&RestoreNotification, &iNotificationState);
+ CleanupStack::PushL(restoreNotification);
+ iNotificationState = EFalse;
+ //Reload the repository content from the related ini file
+ DoRestoreConsistencyL();
+ //Activate notifications
+ CleanupStack::PopAndDestroy();//restoreNotification
+
+ TCentRepLocation location = EPersists;
+ HBufC* persistsTmpFilePath(NULL);
+ //allocates memory on the heap
+ TServerResources::CreateRepositoryFileNameLC(persistsTmpFilePath,iSimRep->Uid(),location,ETmp);
+ // Remove any .tmp file
+ // If a debug build - record error
+ TInt fileDeleteErr=TServerResources::iFs.Delete(*persistsTmpFilePath);
+ if ((fileDeleteErr != KErrNone) && (fileDeleteErr != KErrNotFound))
+ {
+ #ifdef _DEBUG
+ RDebug::Print(_L("CHeapRepository::RestoreConsistencyL - Failed to delete file. Error = %d"), fileDeleteErr);
+ #endif
+ }
+
+ CleanupStack::PopAndDestroy(persistsTmpFilePath);
+
+ iInconsistentData=EFalse;
+ }
+
+/**
+The method reloads the repository content from the related cre or ini file.
+@leave System-wide error codes
+*/
+void CSharedRepository::DoRestoreConsistencyL()
+ {
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+ //note that the function below already handles the deletion of any corrupt file
+ //in non-rom location
+ TInt ret=TServerResources::iObserver->CreateRepositoryL(this,EPersists);
+ if (ret==KErrNotFound)
+ {
+ ret=TServerResources::iObserver->CreateRepositoryL(this,EInstall);
+ if (ret==KErrNotFound)
+ {
+ ret=TServerResources::iObserver->CreateRepositoryL(this,ERom);
+ User::LeaveIfError(ret);
+ }
+ }
+#else
+ TCentRepLocation location;
+
+ TInt err = FindLocationForFileL(location,iSimRep->Uid(),ECre);
+ if (err != KErrNotFound)
+ {
+ User::LeaveIfError(CreateRepositoryFromCreFileL(location));
+ return;
+ }
+
+ User::LeaveIfError(FindLocationForFileL(location,iSimRep->Uid(),EIni));
+
+ HBufC* fileName(NULL);
+ TServerResources::CreateRepositoryFileNameLC(fileName,iSimRep->Uid(),location,EIni);
+
+ CIniFileIn* iniFile = NULL;
+ err = CIniFileIn::NewLC(TServerResources::iFs,iniFile,*fileName);
+ if (err==KErrCorrupt && location!=ERom)
+ {
+ User::LeaveIfError(TServerResources::iFs.Delete(*fileName));
+ }
+ User::LeaveIfError(err);
+
+
+ err = ReloadContentL(*iniFile);
+ User::LeaveIfError(err);
+
+ CleanupStack::PopAndDestroy(iniFile); //iniFile
+ CleanupStack::PopAndDestroy(fileName); //fileName
+#endif
+ }
+
+
+/**
+This method looks for and sets a location for a given repository.
+It is based on EAuto mode thus it goes through all locations in the
+same order (EPersists - EInstall - ERom)
+
+@param aLocation - returns a location for a repository
+@param aUid - id of a repository which location should be found
+@param aType - repository file type (.txt or .cre)
+@return KErrNone if aLocation succesfully set for a given repository,
+ KErrNotFound if a repository was not found in any locations.
+
+@internalTechnology
+*/
+#ifndef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+TInt CSharedRepository::FindLocationForFileL(TCentRepLocation& aLocation,TUid aUid,const TCentRepFileType aType) const
+ {
+ if(TServerResources::CentrepFileExistsL(aUid, EPersists, aType))
+ {
+ aLocation = EPersists;
+ return KErrNone;
+ }
+
+ if(TServerResources::CentrepFileExistsL(aUid, EInstall, aType))
+ {
+ aLocation = EInstall;
+ return KErrNone;
+ }
+
+ if(TServerResources::CentrepFileExistsL(aUid, ERom, aType))
+ {
+ aLocation = ERom;
+ return KErrNone;
+ }
+
+ return KErrNotFound;
+ }
+#endif
+
+TInt CSharedRepository::CreateRepositoryFromCreFileL( TCentRepLocation aLocation)
+ {
+ // Get file path name from location
+ HBufC* filePath(NULL);
+ TServerResources::CreateRepositoryFileNameLC(filePath,iSimRep->Uid(), aLocation,ECre);
+ // Trap errors from repository creation so we can delete corrupt repositories
+ TRAPD(error, iSimRep->CreateRepositoryFromCreFileL(TServerResources::iFs,*filePath));
+ if(error!=KErrNone && error!=KErrNotFound && error!=KErrNoMemory)
+ {
+ error=KErrCorrupt;
+ // store wasn't quite what we were expecting - can't return an error, can't leave
+ // so all we can do is close the file, tidy up as best we can, and return corrupt
+ if (aLocation != ERom)
+ {
+ // If a debug build - record error
+ TInt fileDeleteErr=TServerResources::iFs.Delete(*filePath);
+ if (fileDeleteErr != KErrNone)
+ {
+ #ifdef _DEBUG
+ RDebug::Print(_L("CSharedRepository::CreateRepositoryFromCreFileL - Failed to delete file. Error = %d"), fileDeleteErr);
+ #endif
+ }
+
+ }
+ }
+ else if( error==KErrNoMemory)
+ {
+ User::Leave(KErrNoMemory);
+ }
+ CleanupStack::PopAndDestroy(filePath);
+ return error;
+ }
+
+/** Attempts to start a transaction.
+Guaranteed to succeed (return KErrNone) for EConcurrentReadWriteTransaction mode only.
+@param aTransactor transactor attempting to start transaction
+@param aMode type of transaction to be started
+@pre transactor is not in a transaction
+@return KErrNone if the transaction is started, KErrLocked if read/write locks prevented that
+type of transaction from starting now, and KErrArgument for invalid aMode.
+@post On returning KErrNone, transaction is started and read/write locks are obtained for it
+in the shared repository. Any other return: transaction has not started.
+*/
+TInt CSharedRepository::StartTransaction(CRepositoryTransactor& aTransactor, TInt aMode)
+ {
+ // session can only be in one transaction
+ ASSERT(!aTransactor.IsInTransaction());
+
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ ASSERT(shrepinfo);
+ switch (aMode)
+ {
+ case EConcurrentReadWriteTransaction:
+ // can always start this type of transaction
+ shrepinfo->iNumActiveConcurrentReadWriteTransactions++;
+ break;
+ case EReadTransaction:
+ // negative lock means there is an active EReadWriteTransaction
+ if (shrepinfo->iPessimisticTransactionLockCount < 0)
+ {
+ ASSERT(shrepinfo->iPessimisticTransactionLockCount == -1); // sanity check
+ return KErrLocked;
+ }
+ // when non-negative lock equals number of active EReadTransactions.
+ shrepinfo->iPessimisticTransactionLockCount++;
+ break;
+ case EReadWriteTransaction:
+ // lock is zero if there are no active pessimistic transactions
+ if (shrepinfo->iPessimisticTransactionLockCount != 0)
+ {
+ return KErrLocked;
+ }
+ // lock value of -1 means the exclusive EReadWriteTransaction is active
+ shrepinfo->iPessimisticTransactionLockCount = -1;
+ break;
+ default:
+ // not a valid transaction mode
+ return KErrArgument;
+ }
+ aTransactor.AddToQueue(shrepinfo->iTransactors, aMode);
+ return KErrNone;
+ }
+
+/** Commit transaction
+@return KErrNone on success, or error code.
+@param aKeyInfo
+ on success (return KErrNone): aKeyInfo returns number of modified settings;
+ on failure (other error code): KUnspecifiedKey
+@pre transactor is in a transaction.
+@post transactor is not in a transaction
+*/
+TInt CSharedRepository::CommitTransaction(CRepositoryTransactor& aTransactor, TUint32& aKeyInfo)
+ {
+ // calling code should have panicked the client if not in a transaction
+ ASSERT(aTransactor.IsInTransaction());
+ TInt result = aTransactor.iTransactionResult;
+ if (aTransactor.IsInFailedTransaction())
+ {
+ ASSERT(result != KErrNone);
+ aKeyInfo = aTransactor.iTransactionErrorKey;
+ }
+ else
+ {
+ ASSERT(result == KErrNone);
+ ASSERT(aTransactor.iTransactionErrorKey == KUnspecifiedKey);
+ aKeyInfo = 0;
+ // must release locks otherwise shared repository will not commit changes
+ // failed transactions have already released their locks
+ ReleaseTransactionLock(aTransactor);
+ }
+
+ // transactions that haven't made any changes can be closed at any time
+ if (aTransactor.IsInActiveReadWriteTransaction() &&
+ (aTransactor.iTransactionSettings.Count() > 0))
+ {
+ result = DoCommitTransactionSettings(aTransactor, aKeyInfo);
+ }
+
+ // transaction is complete - remove from queue
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ ASSERT(shrepinfo);
+ shrepinfo->iTransactors.Remove(aTransactor);
+ //Remove the link to the next transaction
+ aTransactor.iLink.iNext = NULL;
+ aTransactor.Deque();
+
+ return result;
+ }
+
+/** Cancels the transaction, discarding changes.
+@post Not in a transaction
+*/
+void CSharedRepository::CancelTransaction(CRepositoryTransactor& aTransactor)
+ {
+ if (aTransactor.IsInTransaction())
+ {
+ ReleaseTransactionLock(aTransactor);
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ ASSERT(shrepinfo);
+ shrepinfo->iTransactors.Remove(aTransactor);
+ //Remove the link to the next transaction
+ aTransactor.iLink.iNext = NULL;
+ aTransactor.Deque();
+ }
+ }
+
+TInt CSharedRepository::FailTransaction(CRepositoryTransactor& aTransactor, TInt aError, TUint32 aErrorKey)
+ {
+ ASSERT(aError != KErrNone); // must fail for a reason
+ if (aTransactor.IsInActiveTransaction())
+ {
+ // locks cannot be removed from a failed transaction, so release before failing
+ ReleaseTransactionLock(aTransactor);
+ aTransactor.SetFailed(aError, aErrorKey);
+ }
+ return aError; // to allow "return FailTransaction(error, errorKey);" - error written once
+ }
+
+/** Fails all active transactions - except for the optional aExcludeTransactor, releasing locks.
+All transactions are failed with reason "KErrLocked" meaning they are "locked out".
+This should only be done to allow another agent to change values in the repository.
+Beware that all concurrent read/write transactions that are failed with KErrLocked are
+expected to retry the transactions straight afterwards - must be careful to allow their
+retry strategy to be successful.
+*/
+void CSharedRepository::FailAllTransactions(const CRepositoryTransactor* aExcludeTransactor)
+ {
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ ASSERT(shrepinfo);
+ TSglQueIter<CRepositoryTransactor> transIter(shrepinfo->iTransactors);
+ CRepositoryTransactor* transactor;
+ while ((transactor = transIter++) != NULL)
+ {
+ if (transactor != aExcludeTransactor)
+ {
+ FailTransaction(*transactor, KErrLocked, KUnspecifiedKey);
+ }
+ }
+ }
+
+/** must currently be in active Read transaction. Does not fail
+transaction here if promotion to read/write failed.
+@return KErrNone if promoted, KErrLocked if not
+*/
+TInt CSharedRepository::AttemptPromoteTransactionToReadWrite(CRepositoryTransactor& aTransactor)
+ {
+ // transactor should currently be in an active read transaction
+ ASSERT(aTransactor.IsInActiveReadTransaction());
+
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ ASSERT(shrepinfo);
+ // sanity check: must only be pessimistic reads active
+ ASSERT(shrepinfo->iPessimisticTransactionLockCount > 0);
+ // can promote only if there are no other active read transactions:
+ if (1 == shrepinfo->iPessimisticTransactionLockCount)
+ {
+ // may only promote to exclusive read/write as it has the same commit semantics
+ // as Read transaction: concurrent R/W must wait for reads to finish first.
+ aTransactor.PromoteToExclusiveReadWrite();
+ // lock value of -1 means the exclusive EReadWriteTransaction is active
+ shrepinfo->iPessimisticTransactionLockCount = -1;
+ return KErrNone;
+ }
+ return KErrLocked;
+ }
+
+/** Private helper method which releases any read/write locks held in the shared repository
+by this transactor. Caller must set transactor's state or remove from queue as appropriate.
+@param aTransactor transactor whose read/write locks are to be released.
+@post Any read/write locks held by transactor are released.
+*/
+void CSharedRepository::ReleaseTransactionLock(CRepositoryTransactor& aTransactor)
+ {
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ ASSERT(shrepinfo);
+ if (aTransactor.IsInActiveConcurrentReadWriteTransaction())
+ {
+ shrepinfo->iNumActiveConcurrentReadWriteTransactions--;
+ ASSERT(shrepinfo->iNumActiveConcurrentReadWriteTransactions >= 0); // sanity check
+ }
+ else if (aTransactor.IsInActiveReadTransaction())
+ {
+ shrepinfo->iPessimisticTransactionLockCount--;
+ ASSERT(shrepinfo->iPessimisticTransactionLockCount >= 0); // sanity check
+ }
+ else if (aTransactor.IsInActiveExclusiveReadWriteTransaction())
+ {
+ // can only be one exclusive read/write transaction active (lock value -1)
+ ASSERT(shrepinfo->iPessimisticTransactionLockCount == -1);
+ shrepinfo->iPessimisticTransactionLockCount = 0;
+ }
+ }
+
+void CSharedRepository::ExternalizeCre(RWriteStream& aStream) const
+ {
+ iSimRep->ExternalizeCre(TServerResources::iPersistsVersion,aStream);
+ }
+
+void CSharedRepository::InternalizeCreL(RReadStream& aStream)
+ {
+ iSimRep->InternalizeCreL(aStream);
+ }
+
+#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
+void CSharedRepository::InternalizeCreL(RReadStream& aStream,TUint8& aCreVersion)
+ {
+ iSimRep->InternalizeCreL(aStream,aCreVersion);
+ }
+#endif
+
+void CSharedRepository::Notify(TUint32 aVal) const
+ {
+ if(iNotificationState)
+ {
+ TServerResources::iObserver->Notify(iSimRep->Uid(), aVal);
+ }
+ }
+
+TBool CSharedRepository::IsTransactionActive()
+ {
+ CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
+ if (shrepinfo)
+ {
+ return (shrepinfo->iPessimisticTransactionLockCount != 0) ||
+ (shrepinfo->iNumActiveConcurrentReadWriteTransactions > 0);
+ }
+ return EFalse;
+ }
+
+RSettingsArray& CSharedRepository::GetSettings()
+ {
+ return iSimRep->SettingsArray();
+ }