persistentstorage/centralrepository/cenrepsrv/shrepos.cpp
changeset 0 08ec8eefde2f
child 1 c084286672be
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "srvdefs.h"
       
    17 #include "srvres.h"
       
    18 #include "shrepos.h"
       
    19 #include "srvrepos_noc.h"
       
    20 #include "obsrvr_noc.h"
       
    21 #include "srvparams.h"
       
    22 
       
    23 CSharedRepository* CSharedRepository::NewL(TUid aUid)
       
    24 	{
       
    25 	CSharedRepository* self = new(ELeave) CSharedRepository();
       
    26 	CleanupStack::PushL(self);
       
    27 	self->ConstructL(aUid);
       
    28 	CleanupStack::Pop(self);
       
    29 	
       
    30 	// debug check that CRepository::TTransactionMode modes match those used internally
       
    31 	// from CRepositoryTransactor: internal state logic relies on this
       
    32 	// there should be a better location for these checks...
       
    33 	ASSERT(CRepository::EReadTransaction == static_cast<CRepository::TTransactionMode>(EReadTransaction));
       
    34 	ASSERT(CRepository::EConcurrentReadWriteTransaction == static_cast<CRepository::TTransactionMode>(EConcurrentReadWriteTransaction));
       
    35 	ASSERT(CRepository::EReadWriteTransaction == static_cast<CRepository::TTransactionMode>(EReadWriteTransaction));
       
    36 	
       
    37 	return self;
       
    38 	}
       
    39 	
       
    40 void CSharedRepository::ConstructL(TUid aUid)
       
    41 	{
       
    42 	iSimRep = CHeapRepository::NewL(aUid);
       
    43 	}
       
    44 
       
    45 CSharedRepository::CSharedRepository() : iNotificationState(ETrue)
       
    46 	{
       
    47 	}
       
    48 	
       
    49 CSharedRepository::~CSharedRepository()
       
    50 	{
       
    51 	if (iSimRep)
       
    52 		{
       
    53 		delete iSimRep;
       
    54 		}
       
    55 	}
       
    56 
       
    57 TUid CSharedRepository::Uid() const
       
    58 	{
       
    59 	return iSimRep->Uid();
       
    60 	}
       
    61 
       
    62 /**
       
    63 Stores the repository in-memory content to the related repository file on drive C.
       
    64 If the operation fails, the in-memory content won't match the content of 
       
    65 the repository file (which will be kept as it was before the CommitChangesL() call).
       
    66 In order to keep the consistency, the in-memory repository content is deleted now
       
    67 and restored later, on the next repository operation.
       
    68 */
       
    69 TInt CSharedRepository::CommitChanges(TCentRepLocation aLocation)
       
    70 	{
       
    71 	iInconsistentData=ETrue;
       
    72 	
       
    73 	HBufC* filePath(NULL);	   
       
    74 	TRAPD(err,TServerResources::CreateRepositoryFileNameL(filePath,iSimRep->Uid(),aLocation,ECre));	
       
    75 	if (err!=KErrNone)
       
    76 		{
       
    77 		iSimRep->ResetContent();
       
    78 		return err;		
       
    79 		}
       
    80 	
       
    81 	// should not be committing while transactions are still active
       
    82 	ASSERT(!IsTransactionActive());
       
    83 	TInt ret=iSimRep->CommitChanges(TServerResources::iFs,TServerResources::iPersistsVersion,*filePath);
       
    84 	if (ret==KErrNone)
       
    85 		{
       
    86 		iInconsistentData=EFalse;	
       
    87 		}
       
    88 	delete filePath;
       
    89 	return ret;
       
    90 	}
       
    91 
       
    92 // merge transaction settings (which may include entries flagged as deleted), persist and notify
       
    93 // private method relies on calling code to ensure it is permitted to make changes here.
       
    94 // if this method is committing any changes, it cancels all other sessions' transactions
       
    95 TInt CSharedRepository::DoCommitTransactionSettings(CRepositoryTransactor& aTransactor, TUint32& aKeyInfo)
       
    96 	{
       
    97 	aKeyInfo = KUnspecifiedKey;
       
    98 	if (0 == aTransactor.iTransactionSettings.Count())
       
    99 		{
       
   100 		aKeyInfo = 0; // == number of settings modified
       
   101 		return KErrNone; // nothing to do
       
   102 		}
       
   103 	TInt error = iSimRep->SettingsArray().MergeArray(aTransactor.iTransactionSettings, iSimRep->DeletedSettingsArray(), ETransactionMerge);
       
   104 	TInt numChanges = aTransactor.iTransactionSettings.Count();
       
   105 	if (numChanges == 0)
       
   106 		{
       
   107 		if (error == KErrNone)
       
   108 			{
       
   109 			aKeyInfo = 0; // no changes
       
   110 			}
       
   111 		// no changes were made, so the internal cache is still valid.
       
   112 		// This could be because there were no changes: empty list, only deletes on
       
   113 		// non-existent items (a setting created and deleted in the transaction),
       
   114 		// or because of error, such as failure of an initial realloc failure.
       
   115 		return error;
       
   116 		}
       
   117 	if (error != KErrNone)
       
   118 		{
       
   119 		// the repository is corrupted. Dump it for lazy loading later
       
   120 		ResetContent();
       
   121 		
       
   122 		// mark cache as inconsistent so it is reloaded.
       
   123 		iInconsistentData = ETrue;	
       
   124 		return error;	
       
   125 		}
       
   126 	if (error == KErrNone)
       
   127 		{
       
   128 		// changes have been made: fail all other sessions' transactions so we can commit
       
   129 		FailAllTransactions(/*aExcludeTransactor=*/&aTransactor);
       
   130 		error = CommitChanges(); // this already calls ResetContent() in case of failure
       
   131 		}
       
   132 	if (error == KErrNone)
       
   133 		{
       
   134 		// settings are now persistent on disk: we can now notify about the changes
       
   135 		// following will notify about objects that are created and deleted in the transaction
       
   136 		// this could be made faster by having a multiple Notify method.
       
   137 		// That would also allow Notify messages to be more descriptive - ranges of Keys
       
   138 		for (TInt i = 0; i < numChanges; i++)
       
   139 			{
       
   140 			Notify(aTransactor.iTransactionSettings[i].Key());
       
   141 			}
       
   142 		aKeyInfo = /*reinterpret_cast<TUint32>*/numChanges;
       
   143 		}
       
   144 	return error;
       
   145 	}
       
   146 
       
   147 void CSharedRepository::SetMetaDataOnRead(TServerSetting& aSetting, TBool aSingleMetaFound)
       
   148 	{
       
   149 	iSimRep->SetMetaDataOnRead(aSetting, aSingleMetaFound);
       
   150 	}
       
   151 
       
   152 void CSharedRepository::SetMetaDataOnCreate(TServerSetting& aNewSetting, TUint32* aMeta)
       
   153 	{
       
   154 	if(aMeta)
       
   155 		{
       
   156 		aNewSetting.SetMeta(*aMeta);
       
   157 		}
       
   158 	else
       
   159 		{
       
   160 		// No metadata specified. First check for a matching "range" default
       
   161 		// metadata setting
       
   162 		TSettingsDefaultMeta* defaultMeta = iSimRep->RangeMetaArray().Find(aNewSetting.Key());
       
   163 		if (defaultMeta)
       
   164 			{
       
   165 			aNewSetting.SetMeta(defaultMeta->GetDefaultMetadata());
       
   166 			}
       
   167 		else
       
   168 			{
       
   169 			// Range value not found, try for a repository default
       
   170 			aNewSetting.SetMeta(iSimRep->DefaultMeta());
       
   171 			}
       
   172 		}	
       
   173 	}
       
   174 
       
   175 void CSharedRepository::CreateL(TServerSetting& aSetting, TSettingsAccessPolicy*& aPolicy, TBool aFirstLoad, TBool aSingleMetaFound)
       
   176 	{
       
   177 	User::LeaveIfError(iSimRep->Create(aSetting, aPolicy, aSingleMetaFound));
       
   178 	if (!aFirstLoad)
       
   179 		{
       
   180 		Notify(aSetting.Key());
       
   181 		}
       
   182 	}
       
   183 
       
   184 // deletes an individual setting in the shared repository and makes it persistent
       
   185 // if changes are made, all sessions' transactions are failed
       
   186 TInt CSharedRepository::DeleteAndPersist(TUint32 aId)
       
   187 	{
       
   188 	TServerSetting* s = iSimRep->SettingsArray().Find(aId);
       
   189 	if(!s)
       
   190 		return KErrNotFound;
       
   191 	iSimRep->SettingsArray().Remove(aId);
       
   192 	
       
   193 	// removed a setting, so must fail all sessions' transactions before commit possible
       
   194 	FailAllTransactions(/*aExcludeTransactor=*/NULL);
       
   195 	TInt error = CommitChanges();
       
   196 	if (error == KErrNone)
       
   197 		{
       
   198 		Notify(aId);
       
   199 		}
       
   200 	return error;
       
   201 	}
       
   202 
       
   203 // deletes an individual setting without making it persistent
       
   204 // must not be called while any sessions are in transactions
       
   205 TInt CSharedRepository::DeleteNoPersist(TUint32 aId)
       
   206 	{
       
   207 	// should only be calling this if no transactions are active
       
   208 	ASSERT(!IsTransactionActive());
       
   209 	TServerSetting* s = iSimRep->SettingsArray().Find(aId);
       
   210 	if(!s)
       
   211 		return KErrNotFound;
       
   212 
       
   213 	iSimRep->SettingsArray().Remove(aId);
       
   214 	return KErrNone;	
       
   215 	}
       
   216 
       
   217 TInt CSharedRepository::ResetNoPersistL(TServerSetting& aSetting)
       
   218 	{
       
   219 	TServerSetting* s = iSimRep->SettingsArray().Find(aSetting.Key());
       
   220 	if ((!s) || (*s != aSetting))
       
   221 		{
       
   222 		if (s)
       
   223 			{
       
   224 			// save access policy of setting
       
   225 			TSettingsAccessPolicy* policy=s->AccessPolicy();
       
   226 			s->Transfer(aSetting);
       
   227 			// restore access policy of setting
       
   228 			s->SetAccessPolicy(policy);
       
   229 			}
       
   230 		else
       
   231 			{
       
   232 			TServerSetting setting;
       
   233 			setting.Transfer(aSetting);
       
   234 			setting.SetAccessPolicy(GetFallbackAccessPolicy(setting.Key()));
       
   235 			setting.PushL();
       
   236 			iSimRep->SettingsArray().OrderedInsertL(setting);
       
   237 			
       
   238 			TInt index = iSimRep->DeletedSettingsArray().FindInUnsignedKeyOrder(aSetting.Key());
       
   239 			if (index != KErrNotFound)
       
   240 				iSimRep->DeletedSettingsArray().Remove(index);
       
   241 	
       
   242 			setting.Pop();
       
   243 			}
       
   244 		}
       
   245 	else
       
   246 		{
       
   247 		return KErrGeneral;
       
   248 		}
       
   249 	return KErrNone;
       
   250 	}
       
   251 
       
   252 // if changes are made, all sessions' transactions are failed
       
   253 void CSharedRepository::ResetAndPersistL(TServerSetting& aSetting)
       
   254 	{
       
   255 	if (ResetNoPersistL(aSetting) == KErrNone)
       
   256 		{
       
   257 		// changed a setting, so must fail all sessions' transactions
       
   258 		// before commit possible
       
   259 		FailAllTransactions(/*aExcludeTransactor=*/NULL);
       
   260 		CommitChangesL();
       
   261 		Notify(aSetting.Key());
       
   262 		}
       
   263 	}
       
   264 
       
   265 TInt CSharedRepository::ResetAllNoPersistL(CSharedRepository& aNewContent)
       
   266 	{
       
   267 	// mark cache as inconsistent in case Reset fails, so it is reloaded.
       
   268 	iInconsistentData=ETrue;
       
   269 
       
   270 	// should not change repository while transactions in progress: should fail them first
       
   271 	ASSERT(!IsTransactionActive());
       
   272 	TInt newCount = (aNewContent.iSimRep)->SettingsArray().Count();
       
   273 	TInt count = iSimRep->SettingsArray().Count();
       
   274 
       
   275 	TInt newIndex = 0;
       
   276 	TInt index = 0;
       
   277 
       
   278 	while(newIndex<newCount && index<count)
       
   279 		{
       
   280 		const TServerSetting& newSetting = (aNewContent.iSimRep)->SettingsArray()[newIndex];
       
   281 		const TServerSetting& setting = iSimRep->SettingsArray()[index];
       
   282 
       
   283 		TUint32 newKey = newSetting.Key();
       
   284 		TUint32 key = setting.Key();
       
   285 
       
   286 		if(newKey<key)
       
   287 			{
       
   288 			Notify(newKey);
       
   289 			newIndex++;
       
   290 			}
       
   291 		else if(newKey==key)
       
   292 			{
       
   293 			if(newSetting!=setting)
       
   294 				{
       
   295 				Notify(key);
       
   296 				}
       
   297 			newIndex++;
       
   298 			index++;
       
   299 			}
       
   300 		else if(newKey>key)
       
   301 			{
       
   302 			Notify(key);
       
   303 			index++;
       
   304 			}
       
   305 		}
       
   306 
       
   307 	while(newIndex<newCount)
       
   308 		{
       
   309 		Notify((aNewContent.iSimRep)->SettingsArray()[newIndex++].Key());
       
   310 		}
       
   311 		
       
   312 	while(index<count)
       
   313 		{
       
   314 		Notify(iSimRep->SettingsArray()[index++].Key());
       
   315 		}
       
   316 
       
   317 	// Replace current settings with settings read from ROM, this 
       
   318 	// will leave settings pointing to new single policies
       
   319 	iSimRep->SettingsArray().AdoptL((aNewContent.iSimRep)->SettingsArray());
       
   320 
       
   321 	// Reset policy pointers to point at this repositories policies
       
   322 	newCount=iSimRep->SettingsArray().Count();
       
   323 	for(TInt i=0; i<newCount;i++)
       
   324 		{
       
   325 		(iSimRep->SettingsArray())[i].SetAccessPolicy(NULL);
       
   326 		TUint32 key = (iSimRep->SettingsArray())[i].Key();
       
   327 		(iSimRep->SettingsArray())[i].SetAccessPolicy(GetFallbackAccessPolicy(key));
       
   328 		}	
       
   329 	
       
   330 	iSimRep->DeletedSettingsArray().Reset();
       
   331 
       
   332 	iInconsistentData=EFalse;
       
   333 	return KErrNone;
       
   334 	}
       
   335 	
       
   336 // returns the read security policy used if there is no per-setting policy at aId
       
   337 const TSecurityPolicy& CSharedRepository::GetFallbackReadAccessPolicy(TUint32 aId)
       
   338 	{
       
   339 	return iSimRep->GetFallbackReadAccessPolicy(aId);
       
   340 	}
       
   341 
       
   342 // returns the write security policy used if there is no per-setting policy at aId
       
   343 const TSecurityPolicy& CSharedRepository::GetFallbackWriteAccessPolicy(TUint32 aId)
       
   344 	{
       
   345 	return iSimRep->GetFallbackWriteAccessPolicy(aId);
       
   346 	}
       
   347 
       
   348 // Get pointer to security policy that applies to a given setting
       
   349 TSettingsAccessPolicy* CSharedRepository::GetFallbackAccessPolicy(TUint32 aId
       
   350 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   351 	,TBool aSkipSingle
       
   352 #endif	
       
   353 	)
       
   354 	{
       
   355 	return iSimRep->GetFallbackAccessPolicy(aId
       
   356 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   357 	,aSkipSingle
       
   358 #endif	
       
   359 	);
       
   360 	}
       
   361 
       
   362 
       
   363 TInt CSharedRepository::ReadSettingSavePolicyL(CIniFileIn& aFile,TServerSetting& aSetting, TSettingsAccessPolicy*& aPolicy, TBool& aSingleMetaFound)
       
   364 	{
       
   365 	return iSimRep->ReadSettingSavePolicyL(aFile, aSetting, aPolicy, aSingleMetaFound);
       
   366 	}	
       
   367 
       
   368 // Merge settings in this->iSettings with the iSettings of aMergeRep
       
   369 // During an intsall/upgrade event aMergeRep will be created from the installed file
       
   370 // During an upinstall event aMergeRep will be created from the ROM file
       
   371 void CSharedRepository::MergeL(CSharedRepository& aMergeRep, TMergeType aMergeType)
       
   372 	{
       
   373 	// Process settings from main section - this updates values only
       
   374 	User::LeaveIfError(GetSettings().MergeArray(aMergeRep.GetSettings(), iSimRep->DeletedSettingsArray(), aMergeType));
       
   375 
       
   376 	//if the merging is due to a ROM Flash, we need to copy over both the NEW ROM keypsace global properties
       
   377 	//(default access policies/metadata and range policies/metadata), individual policies, we then need to ensure
       
   378 	//that the settings point at the correct individual policies and metadata.
       
   379 	if (aMergeType==ERomFlash)
       
   380 		{
       
   381 		//copy the default/range/individual policy
       
   382 		iSimRep->SetDefaultPolicy(aMergeRep.iSimRep->GetDefaultAccessPolicy());
       
   383 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   384 		iSimRep->GetDefaultAccessPolicy().iHighKey=aMergeRep.iSimRep->GetDefaultAccessPolicy().iHighKey;
       
   385 		iSimRep->GetDefaultAccessPolicy().iKeyMask=aMergeRep.iSimRep->GetDefaultAccessPolicy().iKeyMask;		
       
   386 #endif		
       
   387 		iSimRep->RangePolicyArray().Reset();
       
   388 		TInt count=aMergeRep.iSimRep->RangePolicyArray().Count();
       
   389 		iSimRep->RangePolicyArray().ReserveL(count);
       
   390 		for (TInt i=0;i<count;i++)
       
   391 			{
       
   392 			iSimRep->RangePolicyArray().AppendL(aMergeRep.iSimRep->RangePolicyArray()[i]);
       
   393 			}
       
   394 		iSimRep->SinglePolicyArray().ResetAndDestroy();
       
   395 		count=aMergeRep.iSimRep->SinglePolicyArray().Count();
       
   396 		iSimRep->SinglePolicyArray().ReserveL(count);
       
   397 		for (TInt i=0;i<count;i++)
       
   398 			{
       
   399 			iSimRep->SinglePolicyArray().AppendL(aMergeRep.iSimRep->SinglePolicyArray()[i]);
       
   400 			}
       
   401 		//now need to reset the aMergeRep single policies so it is not going to destroy the
       
   402 		//individual policies as ownership has been transferred
       
   403 		aMergeRep.iSimRep->SinglePolicyArray().Reset();
       
   404 		
       
   405 		//copy the default/range metadata
       
   406 		iSimRep->SetDefaultMeta(aMergeRep.iSimRep->DefaultMeta());
       
   407 		iSimRep->RangeMetaArray().Reset();
       
   408 		count=aMergeRep.iSimRep->RangeMetaArray().Count();
       
   409 		iSimRep->RangeMetaArray().ReserveL(count);		
       
   410 		for (TInt i=0;i<count;i++)
       
   411 			{
       
   412 			iSimRep->RangeMetaArray().AppendL(aMergeRep.iSimRep->RangeMetaArray()[i]);
       
   413 			}
       
   414 		
       
   415 		//set the timestamp,owner etc
       
   416 		iSimRep->SetTimeStamp(aMergeRep.iSimRep->TimeStamp());
       
   417 		iSimRep->SetOwner(aMergeRep.iSimRep->Owner());
       
   418 		}
       
   419 
       
   420 	// Update all access policies and meta
       
   421 	for(TInt i=0; i<iSimRep->SettingsArray().Count();i++)
       
   422 		{
       
   423 		TServerSetting& setting= iSimRep->SettingsArray()[i];
       
   424 		setting.SetAccessPolicy(GetFallbackAccessPolicy(setting.Key()));
       
   425 		}	
       
   426 	}
       
   427 	
       
   428 // Save timestamp of installed file 
       
   429 void CSharedRepository::SetInstallTime(TTime aInstallTime)
       
   430 	{
       
   431 	iSimRep->SetTimeStamp(aInstallTime);
       
   432 	}
       
   433 	
       
   434 // Handle creation or upgrade of file in install directory
       
   435 void CSharedRepository::HandleUpdateMergeL(TTime aInstallFileTimeStamp, CSharedRepository& aInstallRep)
       
   436 	{			
       
   437 	MergeL(aInstallRep, ESWIUpgradeMerge);
       
   438 	
       
   439 	SetInstallTime(aInstallFileTimeStamp);	// Set merge timestamp		
       
   440 	CommitChangesL();						// Commit changes to write system drive file
       
   441 
       
   442 	// settings are now persistent on disk: we can now notify about the changes
       
   443 	for (TInt i = 0; i < (aInstallRep.iSimRep)->SettingsArray().Count(); i++)
       
   444 		{
       
   445 		Notify((aInstallRep.iSimRep)->SettingsArray()[i].Key());
       
   446 		}
       
   447 	}
       
   448 	
       
   449 // Handle merge activity due to an uninstall
       
   450 void CSharedRepository::HandleDeleteMergeL(CSharedRepository& aRomRep)
       
   451 	{
       
   452 	MergeL(aRomRep, ESWIDowngradeMerge);
       
   453 	
       
   454 	SetInstallTime(0);						// Reset timestamp			
       
   455 	CommitChangesL();						// Commit changes to write system drive file
       
   456 	
       
   457 	// settings are now persistent on disk: we can now notify about the changes
       
   458 	for (TInt i = 0; i < (aRomRep.iSimRep)->SettingsArray().Count(); i++)
       
   459 		{
       
   460 		Notify((aRomRep.iSimRep)->SettingsArray()[i].Key());
       
   461 		}
       
   462 	}
       
   463 	
       
   464 
       
   465 #ifdef CENTREP_CONV_TOOL
       
   466 /**
       
   467 Statement "iInconsistentData = ETrue;" must be the first statement in the method,
       
   468 "iInconsistentData = EFalse;" must be the last. It is used for lasy-load implementation
       
   469 for the repository and solves the problem that if CommitChangesL() fails the in-memory
       
   470 repository data won't match the repository data, stored in the file.
       
   471 This routine is being retained for testing purposes
       
   472 */
       
   473 void CSharedRepository::DoCommitChangesToIniFileL(const TDesC& aOutFileName
       
   474 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   475 	,TUint32 aCreVersion
       
   476 #endif
       
   477 	)
       
   478 	{
       
   479 	iInconsistentData=ETrue;
       
   480 
       
   481 	// should not be committing while transactions are still active
       
   482 	ASSERT(!IsTransactionActive());
       
   483 
       
   484 	iSimRep->DoCommitChangesToIniFileL(TServerResources::iFs,aOutFileName
       
   485 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   486 	,aCreVersion
       
   487 #endif	
       
   488 	);
       
   489 	
       
   490 	iInconsistentData = EFalse;
       
   491 	}
       
   492 #endif //CENTREP_CONV_TOOL
       
   493 	
       
   494 /**
       
   495 The method reloads the repository content from a repository file.
       
   496 The current repository must be emptied (or must be empty already) before the call is made.
       
   497 @param aIniFile A reference to CIniFileIn object, which will be used to load
       
   498 				the repository content.
       
   499 @return KErrCorrupt Corrupted repository file.
       
   500 		KErrNone	The repository content was seccessfully loaded into memory.
       
   501 		KErrNotFound Setting not found in the file.
       
   502 @leave System-wide error codes.
       
   503 @leave KErrGeneral It's probably a programmer's error - current CSharedRepository 
       
   504 				   object is partially initialised.
       
   505 */
       
   506 TInt CSharedRepository::ReloadContentL(CIniFileIn& aIniFile, TBool aFirstLoad)
       
   507 	{
       
   508 	// Preconditions - CHeapRepository object should be an empty one.
       
   509 	if(!iSimRep->IsEmpty())
       
   510 		{
       
   511 		User::Leave(KErrGeneral);
       
   512 		}
       
   513 	TInt err = iSimRep->ReloadContentExceptSettingsL(aIniFile);
       
   514 	if(err == KErrCorrupt)
       
   515 		{
       
   516 		return err;
       
   517 		}
       
   518 	CleanupClosePushL(iSimRep->RangeMetaArray());
       
   519 	CleanupClosePushL(iSimRep->RangePolicyArray());
       
   520 	
       
   521 	// Settings
       
   522 	TServerSetting setting;
       
   523 	TSettingsAccessPolicy* policy;
       
   524 	TBool singleMetaFound;
       
   525 	TCleanupItem tc(CHeapRepository::SinglePoliciesCleanup, &(iSimRep->SinglePolicyArray()));
       
   526 	CleanupStack::PushL(tc);	
       
   527 	CleanupClosePushL(iSimRep->SettingsArray());	
       
   528 	while((err = ReadSettingSavePolicyL(aIniFile, setting, policy, singleMetaFound)) == KErrNone)
       
   529 		{
       
   530 		setting.PushL();
       
   531 		if(iSimRep->SettingsArray().IsDefault())
       
   532 			{
       
   533 			setting.SetClean();			
       
   534 			}
       
   535 		CreateL(setting, policy, aFirstLoad, singleMetaFound);
       
   536 		setting.Pop();
       
   537 		}
       
   538 	if(err == KErrNotFound)			
       
   539 		{
       
   540 		err = KErrNone;
       
   541 		}
       
   542 	if (err == KErrNone)
       
   543 		{
       
   544 		CleanupStack::Pop(4,&(iSimRep->RangeMetaArray()));		
       
   545 		}
       
   546 	else
       
   547 		{
       
   548 		CleanupStack::PopAndDestroy(4,&(iSimRep->RangeMetaArray()));		
       
   549 		}
       
   550 	return err;
       
   551 	}
       
   552 
       
   553 /**
       
   554 Resets current repository data - actually all of them, which may be loaded from
       
   555 the related ini file.
       
   556 The iUid data member value is kept as it was at the moment of creation of 
       
   557 CSharedRepository object.
       
   558 */
       
   559 void CSharedRepository::ResetContent()
       
   560 	{
       
   561 	iSimRep->ResetContent();
       
   562 	}
       
   563 
       
   564 /**
       
   565 This function is used to restore the notification, which was temporary disabled
       
   566 when making RestoreConsistencyL() call.
       
   567 @param aNotificationState It points to CObservable::iNotificationState data member, which 
       
   568 						 controls the notification state - active or disabled.
       
   569 @internalComponent
       
   570 */
       
   571 static void RestoreNotification(void* aNotificationState)
       
   572 	{
       
   573 	TBool* notificationState = static_cast <TBool*> (aNotificationState);
       
   574 	*notificationState = ETrue;
       
   575 	}
       
   576 
       
   577 /**
       
   578 The method reloads the repository content from the related ini file if previous
       
   579 CommitChangesL() has not completed successfully.
       
   580 */
       
   581 void CSharedRepository::RestoreConsistencyL()
       
   582 	{
       
   583 	//Do nothing if previous CommitChangesL() completed successfully.
       
   584 	if (!iInconsistentData)
       
   585 		{
       
   586 		return;
       
   587 		}
       
   588 	//Reset current repository data	
       
   589 	ResetContent();
       
   590 	//Disable notifications
       
   591 	TCleanupItem restoreNotification(&RestoreNotification, &iNotificationState);
       
   592 	CleanupStack::PushL(restoreNotification);
       
   593 	iNotificationState = EFalse;
       
   594 	//Reload the repository content from the related ini file
       
   595 	DoRestoreConsistencyL();
       
   596 	//Activate notifications
       
   597 	CleanupStack::PopAndDestroy();//restoreNotification
       
   598 	
       
   599 	TCentRepLocation location = EPersists;
       
   600 	HBufC* persistsTmpFilePath(NULL);
       
   601     //allocates memory on the heap
       
   602     TServerResources::CreateRepositoryFileNameLC(persistsTmpFilePath,iSimRep->Uid(),location,ETmp);
       
   603 	// Remove any .tmp file
       
   604 	// If a debug build - record error
       
   605 	TInt fileDeleteErr=TServerResources::iFs.Delete(*persistsTmpFilePath);
       
   606 	if ((fileDeleteErr != KErrNone) && (fileDeleteErr != KErrNotFound))
       
   607 		{
       
   608 		#ifdef _DEBUG
       
   609 		RDebug::Print(_L("CHeapRepository::RestoreConsistencyL - Failed to delete file. Error = %d"), fileDeleteErr);
       
   610 		#endif
       
   611 		}
       
   612 
       
   613 	CleanupStack::PopAndDestroy(persistsTmpFilePath);
       
   614 	
       
   615 	iInconsistentData=EFalse;
       
   616 	}
       
   617 
       
   618 /**
       
   619 The method reloads the repository content from the related cre or ini file.
       
   620 @leave System-wide error codes
       
   621 */	
       
   622 void CSharedRepository::DoRestoreConsistencyL()
       
   623 	{
       
   624 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS	
       
   625 	//note that the function below already handles the deletion of any corrupt file
       
   626 	//in  non-rom location
       
   627 	TInt ret=TServerResources::iObserver->CreateRepositoryL(this,EPersists);
       
   628 	if (ret==KErrNotFound)
       
   629 		{
       
   630 		ret=TServerResources::iObserver->CreateRepositoryL(this,EInstall);
       
   631 		if (ret==KErrNotFound)
       
   632 			{	
       
   633 			ret=TServerResources::iObserver->CreateRepositoryL(this,ERom);
       
   634 			User::LeaveIfError(ret);
       
   635 			}
       
   636 		}
       
   637 #else
       
   638 	TCentRepLocation location;
       
   639 	
       
   640 	TInt err = FindLocationForFileL(location,iSimRep->Uid(),ECre);
       
   641 	if (err != KErrNotFound)
       
   642 		{
       
   643 		User::LeaveIfError(CreateRepositoryFromCreFileL(location));
       
   644 		return;
       
   645 		}
       
   646 		
       
   647 	User::LeaveIfError(FindLocationForFileL(location,iSimRep->Uid(),EIni));
       
   648 	
       
   649 	HBufC* fileName(NULL);
       
   650     TServerResources::CreateRepositoryFileNameLC(fileName,iSimRep->Uid(),location,EIni);	
       
   651  
       
   652 	CIniFileIn* iniFile = NULL;
       
   653 	err = CIniFileIn::NewLC(TServerResources::iFs,iniFile,*fileName);
       
   654 	if (err==KErrCorrupt && location!=ERom)
       
   655 		{
       
   656 		User::LeaveIfError(TServerResources::iFs.Delete(*fileName));
       
   657 		}
       
   658 	User::LeaveIfError(err);
       
   659 	
       
   660 
       
   661 	err = ReloadContentL(*iniFile);
       
   662 	User::LeaveIfError(err);
       
   663 	
       
   664 	CleanupStack::PopAndDestroy(iniFile); //iniFile 
       
   665 	CleanupStack::PopAndDestroy(fileName);	//fileName
       
   666 #endif
       
   667 	}
       
   668 
       
   669 
       
   670 /**
       
   671 This method looks for and sets a location for a given repository.
       
   672 It is based on EAuto mode thus it goes through all locations in the
       
   673 same order (EPersists - EInstall - ERom)  
       
   674 
       
   675 @param aLocation - returns a location for a repository
       
   676 @param aUid - id of a repository which location should be found
       
   677 @param aType - repository file type (.txt or .cre) 
       
   678 @return KErrNone if aLocation succesfully set for a given repository,
       
   679 		KErrNotFound if a repository was not found in any locations.
       
   680 
       
   681 @internalTechnology
       
   682 */
       
   683 #ifndef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   684 TInt CSharedRepository::FindLocationForFileL(TCentRepLocation& aLocation,TUid aUid,const TCentRepFileType aType) const
       
   685     { 		
       
   686 	if(TServerResources::CentrepFileExistsL(aUid, EPersists, aType))
       
   687 	    {
       
   688 	     aLocation = EPersists;
       
   689 		 return KErrNone;
       
   690 	    }
       
   691 	    
       
   692 	if(TServerResources::CentrepFileExistsL(aUid, EInstall, aType))
       
   693 		{
       
   694 	     aLocation = EInstall;
       
   695 		 return KErrNone;
       
   696 	    }
       
   697 	    
       
   698 	if(TServerResources::CentrepFileExistsL(aUid, ERom, aType))
       
   699 		{
       
   700 		aLocation = ERom;
       
   701 		return KErrNone;
       
   702 		}
       
   703 
       
   704 	return KErrNotFound;
       
   705     }
       
   706 #endif
       
   707 
       
   708 TInt CSharedRepository::CreateRepositoryFromCreFileL( TCentRepLocation aLocation)
       
   709 	{
       
   710 	// Get file path name from location
       
   711     HBufC* filePath(NULL);
       
   712     TServerResources::CreateRepositoryFileNameLC(filePath,iSimRep->Uid(), aLocation,ECre);
       
   713     // Trap errors from repository creation so we can delete corrupt repositories
       
   714 	TRAPD(error, iSimRep->CreateRepositoryFromCreFileL(TServerResources::iFs,*filePath));
       
   715 	if(error!=KErrNone && error!=KErrNotFound && error!=KErrNoMemory)
       
   716 		{
       
   717 		error=KErrCorrupt;
       
   718 		// store wasn't quite what we were expecting - can't return an error, can't leave
       
   719 		// so all we can do is close the file, tidy up as best we can, and return corrupt 
       
   720 		if (aLocation != ERom)
       
   721 			{
       
   722 			// If a debug build - record error
       
   723 			TInt fileDeleteErr=TServerResources::iFs.Delete(*filePath);
       
   724 			if (fileDeleteErr != KErrNone)
       
   725 				{
       
   726 				#ifdef _DEBUG
       
   727 				RDebug::Print(_L("CSharedRepository::CreateRepositoryFromCreFileL - Failed to delete file. Error = %d"), fileDeleteErr);
       
   728 				#endif
       
   729 				}
       
   730 
       
   731 			}
       
   732 		}
       
   733 	else if( error==KErrNoMemory)
       
   734 		{
       
   735 		User::Leave(KErrNoMemory);
       
   736 		}
       
   737 	CleanupStack::PopAndDestroy(filePath);
       
   738 	return error;
       
   739 	}
       
   740 
       
   741 /** Attempts to start a transaction.
       
   742 Guaranteed to succeed (return KErrNone) for EConcurrentReadWriteTransaction mode only.
       
   743 @param aTransactor transactor attempting to start transaction
       
   744 @param aMode type of transaction to be started
       
   745 @pre transactor is not in a transaction
       
   746 @return KErrNone if the transaction is started, KErrLocked if read/write locks prevented that
       
   747 type of transaction from starting now, and KErrArgument for invalid aMode.
       
   748 @post On returning KErrNone, transaction is started and read/write locks are obtained for it
       
   749 in the shared repository. Any other return: transaction has not started.
       
   750 */
       
   751 TInt CSharedRepository::StartTransaction(CRepositoryTransactor& aTransactor, TInt aMode)
       
   752 	{
       
   753 	// session can only be in one transaction
       
   754 	ASSERT(!aTransactor.IsInTransaction());
       
   755 	
       
   756   	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   757   	ASSERT(shrepinfo);
       
   758 	switch (aMode)
       
   759 		{
       
   760 		case EConcurrentReadWriteTransaction:
       
   761 			// can always start this type of transaction
       
   762 			shrepinfo->iNumActiveConcurrentReadWriteTransactions++;
       
   763 			break;
       
   764 		case EReadTransaction:
       
   765 			// negative lock means there is an active EReadWriteTransaction
       
   766 			if (shrepinfo->iPessimisticTransactionLockCount < 0)
       
   767 				{
       
   768 				ASSERT(shrepinfo->iPessimisticTransactionLockCount == -1); // sanity check
       
   769 				return KErrLocked;
       
   770 				}
       
   771 			// when non-negative lock equals number of active EReadTransactions.
       
   772 			shrepinfo->iPessimisticTransactionLockCount++;
       
   773 			break;
       
   774 		case EReadWriteTransaction:
       
   775 			// lock is zero if there are no active pessimistic transactions
       
   776 			if (shrepinfo->iPessimisticTransactionLockCount != 0)
       
   777 				{
       
   778 				return KErrLocked;
       
   779 				}
       
   780 			// lock value of -1 means the exclusive EReadWriteTransaction is active
       
   781 			shrepinfo->iPessimisticTransactionLockCount = -1;
       
   782 			break;
       
   783 		default:
       
   784 			// not a valid transaction mode
       
   785 			return KErrArgument;
       
   786 		}
       
   787 	aTransactor.AddToQueue(shrepinfo->iTransactors, aMode);
       
   788 	return KErrNone;
       
   789 	}
       
   790 
       
   791 /**	Commit transaction
       
   792 @return KErrNone on success, or error code.
       
   793 @param aKeyInfo 
       
   794 	on success (return KErrNone): aKeyInfo returns number of modified settings;
       
   795 	on failure (other error code): KUnspecifiedKey
       
   796 @pre transactor is in a transaction.
       
   797 @post transactor is not in a transaction
       
   798 */
       
   799 TInt CSharedRepository::CommitTransaction(CRepositoryTransactor& aTransactor, TUint32& aKeyInfo)
       
   800 	{
       
   801 	// calling code should have panicked the client if not in a transaction
       
   802 	ASSERT(aTransactor.IsInTransaction());
       
   803 	TInt result = aTransactor.iTransactionResult;
       
   804 	if (aTransactor.IsInFailedTransaction())
       
   805 		{
       
   806 		ASSERT(result != KErrNone);
       
   807 		aKeyInfo = aTransactor.iTransactionErrorKey;
       
   808 		}
       
   809 	else
       
   810 		{
       
   811 		ASSERT(result == KErrNone);
       
   812 		ASSERT(aTransactor.iTransactionErrorKey == KUnspecifiedKey);
       
   813 		aKeyInfo = 0;
       
   814 		// must release locks otherwise shared repository will not commit changes
       
   815 		// failed transactions have already released their locks
       
   816 		ReleaseTransactionLock(aTransactor);
       
   817 		}
       
   818 	
       
   819 	// transactions that haven't made any changes can be closed at any time
       
   820 	if (aTransactor.IsInActiveReadWriteTransaction() &&
       
   821 		(aTransactor.iTransactionSettings.Count() > 0))
       
   822 		{
       
   823 		result = DoCommitTransactionSettings(aTransactor, aKeyInfo);
       
   824 		}
       
   825 
       
   826 	// transaction is complete - remove from queue
       
   827   	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   828   	ASSERT(shrepinfo);
       
   829 	shrepinfo->iTransactors.Remove(aTransactor);
       
   830 	//Remove the link to the next transaction
       
   831 	aTransactor.iLink.iNext = NULL;
       
   832 	aTransactor.Deque();
       
   833 
       
   834 	return result;
       
   835 	}
       
   836 
       
   837 /**	Cancels the transaction, discarding changes.
       
   838 @post Not in a transaction
       
   839 */
       
   840 void CSharedRepository::CancelTransaction(CRepositoryTransactor& aTransactor)
       
   841 	{
       
   842 	if (aTransactor.IsInTransaction())
       
   843 		{
       
   844 		ReleaseTransactionLock(aTransactor);
       
   845 	  	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   846 	  	ASSERT(shrepinfo);
       
   847 		shrepinfo->iTransactors.Remove(aTransactor);
       
   848 		//Remove the link to the next transaction
       
   849 		aTransactor.iLink.iNext = NULL;
       
   850 		aTransactor.Deque();
       
   851 		}
       
   852 	}
       
   853 
       
   854 TInt CSharedRepository::FailTransaction(CRepositoryTransactor& aTransactor, TInt aError, TUint32 aErrorKey)
       
   855 	{
       
   856 	ASSERT(aError != KErrNone); // must fail for a reason
       
   857 	if (aTransactor.IsInActiveTransaction())
       
   858 		{
       
   859 		// locks cannot be removed from a failed transaction, so release before failing
       
   860 		ReleaseTransactionLock(aTransactor);
       
   861 		aTransactor.SetFailed(aError, aErrorKey);
       
   862 		}
       
   863 	return aError; // to allow "return FailTransaction(error, errorKey);" - error written once
       
   864 	}
       
   865 
       
   866 /** Fails all active transactions - except for the optional aExcludeTransactor, releasing locks.
       
   867 All transactions are failed with reason "KErrLocked" meaning they are "locked out".
       
   868 This should only be done to allow another agent to change values in the repository.
       
   869 Beware that all concurrent read/write transactions that are failed with KErrLocked are
       
   870 expected to retry the transactions straight afterwards - must be careful to allow their
       
   871 retry strategy to be successful.
       
   872 */
       
   873 void CSharedRepository::FailAllTransactions(const CRepositoryTransactor* aExcludeTransactor)
       
   874 	{
       
   875   	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   876   	ASSERT(shrepinfo);
       
   877 	TSglQueIter<CRepositoryTransactor> transIter(shrepinfo->iTransactors);  	
       
   878 	CRepositoryTransactor* transactor;
       
   879 	while ((transactor = transIter++) != NULL)
       
   880 		{
       
   881 		if (transactor != aExcludeTransactor)
       
   882 			{
       
   883 			FailTransaction(*transactor, KErrLocked, KUnspecifiedKey);
       
   884 			}
       
   885 		}
       
   886 	}
       
   887 
       
   888 /** must currently be in active Read transaction. Does not fail
       
   889 transaction here if promotion to read/write failed.
       
   890 @return KErrNone if promoted, KErrLocked if not
       
   891 */
       
   892 TInt CSharedRepository::AttemptPromoteTransactionToReadWrite(CRepositoryTransactor& aTransactor)
       
   893 	{
       
   894 	// transactor should currently be in an active read transaction
       
   895 	ASSERT(aTransactor.IsInActiveReadTransaction());
       
   896 
       
   897   	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   898   	ASSERT(shrepinfo);
       
   899 	// sanity check: must only be pessimistic reads active
       
   900 	ASSERT(shrepinfo->iPessimisticTransactionLockCount > 0);
       
   901 	// can promote only if there are no other active read transactions:
       
   902 	if (1 == shrepinfo->iPessimisticTransactionLockCount)
       
   903 		{
       
   904 		// may only promote to exclusive read/write as it has the same commit semantics
       
   905 		// as Read transaction: concurrent R/W must wait for reads to finish first.
       
   906 		aTransactor.PromoteToExclusiveReadWrite();
       
   907 		// lock value of -1 means the exclusive EReadWriteTransaction is active
       
   908 		shrepinfo->iPessimisticTransactionLockCount = -1;
       
   909 		return KErrNone;
       
   910 		}
       
   911 	return KErrLocked;
       
   912 	}
       
   913 
       
   914 /** Private helper method which releases any read/write locks held in the shared repository
       
   915 by this transactor. Caller must set transactor's state or remove from queue as appropriate.
       
   916 @param aTransactor transactor whose read/write locks are to be released.
       
   917 @post Any read/write locks held by transactor are released.
       
   918 */
       
   919 void CSharedRepository::ReleaseTransactionLock(CRepositoryTransactor& aTransactor)
       
   920 	{
       
   921   	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   922   	ASSERT(shrepinfo);
       
   923 	if (aTransactor.IsInActiveConcurrentReadWriteTransaction())
       
   924 		{
       
   925 		shrepinfo->iNumActiveConcurrentReadWriteTransactions--;
       
   926 		ASSERT(shrepinfo->iNumActiveConcurrentReadWriteTransactions >= 0); // sanity check
       
   927 		}
       
   928 	else if (aTransactor.IsInActiveReadTransaction())
       
   929 		{
       
   930 		shrepinfo->iPessimisticTransactionLockCount--;
       
   931 		ASSERT(shrepinfo->iPessimisticTransactionLockCount >= 0); // sanity check
       
   932 		}
       
   933 	else if (aTransactor.IsInActiveExclusiveReadWriteTransaction())
       
   934 		{
       
   935 		// can only be one exclusive read/write transaction active (lock value -1)
       
   936 		ASSERT(shrepinfo->iPessimisticTransactionLockCount == -1);
       
   937 		shrepinfo->iPessimisticTransactionLockCount = 0;
       
   938 		}
       
   939 	}
       
   940 	
       
   941 void CSharedRepository::ExternalizeCre(RWriteStream& aStream) const
       
   942 	{
       
   943 	iSimRep->ExternalizeCre(TServerResources::iPersistsVersion,aStream);
       
   944 	}
       
   945 
       
   946 void CSharedRepository::InternalizeCreL(RReadStream& aStream)
       
   947 	{
       
   948 	iSimRep->InternalizeCreL(aStream);
       
   949 	}
       
   950 	
       
   951 #ifdef	SYMBIAN_CENTREP_SUPPORT_MULTIROFS
       
   952 void CSharedRepository::InternalizeCreL(RReadStream& aStream,TUint8& aCreVersion)
       
   953 	{
       
   954 	iSimRep->InternalizeCreL(aStream,aCreVersion);
       
   955 	}
       
   956 #endif	
       
   957 
       
   958 void CSharedRepository::Notify(TUint32 aVal) const
       
   959 	{
       
   960 	if(iNotificationState)
       
   961 		{
       
   962 		TServerResources::iObserver->Notify(iSimRep->Uid(), aVal);
       
   963 		}
       
   964 	}
       
   965 
       
   966 TBool CSharedRepository::IsTransactionActive()
       
   967 	{
       
   968   	CObservable::TSharedRepositoryInfo* shrepinfo = TServerResources::iObserver->SharedRepositoryInfo(iSimRep->Uid());
       
   969   	if (shrepinfo)
       
   970   		{
       
   971 		return (shrepinfo->iPessimisticTransactionLockCount != 0) ||
       
   972 			(shrepinfo->iNumActiveConcurrentReadWriteTransactions > 0);
       
   973   		}
       
   974   	return EFalse;  		
       
   975 	}
       
   976 
       
   977 RSettingsArray& CSharedRepository::GetSettings()
       
   978 	{
       
   979 	return iSimRep->SettingsArray();
       
   980 	}