applayerpluginsandutils/bookmarksupport/test/cenrepsrv/shrepos.cpp
changeset 0 b16258d2340f
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     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 "panic.h"
       
    17 #include "srvdefs.h"
       
    18 #include "srvres.h"
       
    19 #include "shrepos.h"
       
    20 #include "srvrepos.h"
       
    21 #include "srvparams.h"
       
    22 
       
    23 #ifdef SYMBIAN_CENTRALREPOSITORY_PARANOID_CHECKING
       
    24 
       
    25 /** Validates that the required invariants hold: (1) ordered by ascending key value (2) key uniqueness.
       
    26 Panics upon violation.
       
    27 */
       
    28 void RSettingsArray::ValidateInvariantProperties() const
       
    29 	{
       
    30 	if (Count() > 0)
       
    31 		{
       
    32 		const TServerSetting* prev = &( operator[](0) );
       
    33 		const TServerSetting* curr = prev + 1;
       
    34 		const TServerSetting* upperBound = prev + Count() - 1;
       
    35 		while(curr <= upperBound)
       
    36 			{
       
    37 			// future: should replace with diagnostic panic code
       
    38 			ASSERT(curr->Key() > prev->Key());
       
    39 			prev = curr;
       
    40 			++curr;
       
    41 			}
       
    42 		}
       
    43 	}
       
    44 
       
    45 /** Validates that the required invariants hold for the given setting pointer array: 
       
    46 (1) ordered by ascending key value (2) key uniqueness. Panics upon violation.
       
    47 */
       
    48 void RSettingsArray::ValidateInvariantProperties(const RSettingPointerArray& aPtrArray)
       
    49 	{
       
    50 	if (aPtrArray.Count() > 0)
       
    51 		{
       
    52 		const TServerSetting** prev = const_cast<const TServerSetting**>( &(aPtrArray[0]) );
       
    53 		const TServerSetting** curr = prev + 1;
       
    54 		const TServerSetting** upperBound = prev + aPtrArray.Count() - 1;
       
    55 		while(curr <= upperBound)
       
    56 			{
       
    57 			// future: should replace with diagnostic panic code
       
    58 			ASSERT((*curr)->Key() > (*prev)->Key());
       
    59 			prev = curr;
       
    60 			++curr;
       
    61 			}
       
    62 		}
       
    63 	}
       
    64 
       
    65 #endif
       
    66 
       
    67 /** Returns pointers to all settings whose key matches all bits of the target id also included
       
    68 in the bitwise mask.
       
    69 
       
    70 @param	aTargetKey Bit pattern to match
       
    71 @param	aMask Bitwise mask. Where bits are set the corresponding bit in aTargetKey is significant, ie
       
    72 		AND behaviour conventional with masking
       
    73 @param	aMatches Returns pointers to all settings with keys matching the mask, in ascending key order. The
       
    74 		caller should ensure it is appropriately constructed for the likely growth pattern.
       
    75 @return	Error code. aMatches may be modified even upon error return but the contents must not be relied upon.
       
    76 */
       
    77 TInt RSettingsArray::Find(TUint32 aTargetKey, TUint32 aMask, RSettingPointerArray& aMatches) const
       
    78 	{
       
    79 #ifdef SYMBIAN_CENTRALREPOSITORY_PARANOID_CHECKING
       
    80 	ValidateInvariantProperties();
       
    81 #endif
       
    82 
       
    83 	aMatches.Reset();
       
    84 	// Find the first setting with key >= the lowest possible match
       
    85 	const TInt upperIdx = Count() - 1;
       
    86 	const TUint32 maskedTarget = aTargetKey & aMask;
       
    87 	TInt lowerIdx;
       
    88 	FindInUnsignedKeyOrder(TServerSetting(maskedTarget), lowerIdx);
       
    89 	if(lowerIdx > upperIdx)
       
    90 		{
       
    91 		return KErrNone;
       
    92 		}
       
    93 	
       
    94 	// this simply traverses the settings from the first possible match to the last. For masks with
       
    95 	// only with higher bits this would be wasteful - in principle could jump to next possible match start
       
    96 	// with another Find...() call. However logic more complex and counterproductive in some cases; would
       
    97 	// need some heuristic such as probing N settings ahead of current point and only invoking the refind
       
    98 	// if that still falls below the next range start, where N would allow for the cost of the binsearch
       
    99 	// and other book-keeping (for real smartness construct a new RArray from the current point onwards,
       
   100 	// so binsearch excludes the already known infertile preceding settings). Only worth pursuing after
       
   101 	// profiling.
       
   102 	const TUint32 upperMatchingKey = aTargetKey | ~aMask;
       
   103 	const TServerSetting* setting = &( operator[](lowerIdx) );
       
   104 	const TServerSetting* upperBound = setting + (upperIdx - lowerIdx);
       
   105 	while(setting <= upperBound && setting->Key() <= upperMatchingKey)
       
   106 		{
       
   107 		if((setting->Key() & aMask) == maskedTarget)
       
   108 			{
       
   109 			TInt err = aMatches.Append(setting);
       
   110 			// Small optimisation of not testing err in while() condition, presuming
       
   111 			// that Append() far less common than key tests, ie repeatedly testing err
       
   112 			// is wasteful. However (arguably) makes code more complex
       
   113 			if(err != KErrNone)
       
   114 				{
       
   115 				aMatches.Reset();
       
   116 				return err;
       
   117 				}
       
   118 			}
       
   119 		++setting;
       
   120 		}
       
   121 	return KErrNone;
       
   122 	}
       
   123 
       
   124 /** Given source and destination arrays of settings, replaces the destination with the union of the
       
   125 arrays. The properties of ascending key order and key uniqueness are preserved: where a key is common
       
   126 to both arrays the source setting is kept, excepting where the source setting is flagged as deleted, which
       
   127 simply deletes the destination
       
   128 
       
   129 @param	aDst destination settings array
       
   130 @param	aSrc source settings array
       
   131 @return Error code. If not KErrNone then the contents of aDst are may have been modified and must be
       
   132 		disregarded
       
   133 @post	aDst contains the union and matches the setting array invariant
       
   134 */
       
   135 TInt RSettingsArray::Merge(RSettingPointerArray& aDst, const RSettingPointerArray& aSrc)
       
   136 	{
       
   137 	const TServerSetting** srcBound;
       
   138 	const TServerSetting** srcPtr;
       
   139 	TInt count = aSrc.Count();
       
   140 	if(count > 0)
       
   141 		{
       
   142 		srcPtr = const_cast<const TServerSetting**>( &(aSrc[0]) );
       
   143 		srcBound = srcPtr + count;
       
   144 		}
       
   145 	else
       
   146 		{
       
   147 		srcPtr = NULL;
       
   148 		srcBound = NULL;
       
   149 		}
       
   150 
       
   151 	TInt dstIdx = 0;
       
   152 	const TServerSetting** dstPtr=NULL;
       
   153 	const TServerSetting** dstBound=NULL;
       
   154 
       
   155 	// The approach taken here of inserting entries one at a time is necessarily inefficient
       
   156 	// given the RPointerArray interface, but may be adequate for the projected (small) use. For 
       
   157 	// greater efficiency the ability to insert ranges is required, ie probably custom array code
       
   158 	while(srcPtr < srcBound)
       
   159 		{
       
   160 		if (aDst.Count() > 0)
       
   161 			{
       
   162 			dstBound = const_cast<const TServerSetting**>( &(aDst[0]) ) + aDst.Count();
       
   163 			dstPtr=const_cast<const TServerSetting**>( &(aDst[0]) )+ dstIdx;
       
   164 			}
       
   165 		const TUint32 srcKey = (*srcPtr)->Key();
       
   166 		while(dstPtr < dstBound && srcKey > (*dstPtr)->Key())
       
   167 			{
       
   168 			++dstPtr;
       
   169 			++dstIdx;
       
   170 			}
       
   171 		// Three possibilities: end of dst reached (append src), src and dst match (replace dst), 
       
   172 		// and dst now greater than src (insert src)
       
   173 		if((dstPtr == dstBound || (*dstPtr)->Key() > srcKey))
       
   174 			{
       
   175 			if(!(*srcPtr)->IsDeleted())	// drop deleted records
       
   176 				{
       
   177 				TInt ret = aDst.Insert(*srcPtr, dstIdx);	// presumes insert at end == append
       
   178 				if(ret != KErrNone)
       
   179 					{
       
   180 					return ret;
       
   181 					}
       
   182 				++dstIdx;
       
   183 				}
       
   184 			}
       
   185 		else
       
   186 			{
       
   187 			// Src key matches dst, replace or delete dst
       
   188 			if(!(*srcPtr)->IsDeleted())
       
   189 				{
       
   190 				*dstPtr= *srcPtr;
       
   191 				++dstIdx;
       
   192 				}
       
   193 			else
       
   194 				{
       
   195 				// may be more efficient ways of handling remove
       
   196 				aDst.Remove(dstIdx);
       
   197 				--dstBound;
       
   198 				}
       
   199 			}
       
   200 		++srcPtr;
       
   201 		}
       
   202 #ifdef SYMBIAN_CENTRALREPOSITORY_PARANOID_CHECKING
       
   203 	RSettingsArray::ValidateInvariantProperties(aDst);
       
   204 #endif
       
   205 	return KErrNone;
       
   206 	}
       
   207 
       
   208 CSharedRepository::CSharedRepository(TUid aUid) :
       
   209 	iSettings(), iUid(aUid),
       
   210 	iSinglePolicies(KGranularity),
       
   211 	iTransactors(_FOFF(CRepositoryTransactor, iLink))
       
   212 	{
       
   213 	iPersistsIniFileExists = ETrue;
       
   214 	
       
   215 	// debug check that CRepository::TTransactionMode modes match those used internally
       
   216 	// from CRepositoryTransactor: internal state logic relies on this
       
   217 	// there should be a better location for these checks...
       
   218 	ASSERT(CRepository::EReadTransaction == EReadTransaction);
       
   219 	ASSERT(CRepository::EConcurrentReadWriteTransaction == EConcurrentReadWriteTransaction);
       
   220 	ASSERT(CRepository::EReadWriteTransaction == EReadWriteTransaction);
       
   221 	}
       
   222 	
       
   223 CSharedRepository::~CSharedRepository()
       
   224 	{
       
   225 	// sanity check that no transactions are active
       
   226 	ASSERT(!IsTransactionActive());
       
   227 	// check transactor queue is empty - note this includes failed transactions
       
   228 	ASSERT(NULL == (CRepositoryTransactor*)TDblQueIter<CRepositoryTransactor>(iTransactors));
       
   229 
       
   230 	iSinglePolicies.ResetAndDestroy();
       
   231 	iDeletedSettings.Close();
       
   232 	}
       
   233 
       
   234 TUid CSharedRepository::Uid() const
       
   235 	{
       
   236 	return iUid;
       
   237 	}
       
   238 
       
   239 /**
       
   240 Stores the repository in-memory content to the related repository file on drive C.
       
   241 If the operation fails, the in-memory content won't match the content of 
       
   242 the repository file (which will be kept as it was before the CommitChangesL() call).
       
   243 In order to keep the consistency, the in-memory repository content is deleted now
       
   244 and restored later, on the next repository operation.
       
   245 */
       
   246 TInt CSharedRepository::CommitChanges()
       
   247 	{
       
   248 	TRAPD(error, DoCommitChangesL());
       
   249 	if (error != KErrNone)
       
   250 		{
       
   251 		ResetContent();
       
   252 		}
       
   253 	return error;
       
   254 	}
       
   255 
       
   256 /** Merges the aChanges settings into array. Is used for
       
   257 	Transaction merges
       
   258 	Restore merges
       
   259 	SWI merges
       
   260 
       
   261 	Works as follows:
       
   262 (a) EDeleted settings in aChanges destroy the corresponding setting in this array (if any)
       
   263 (b) Where matching settings exist in both arrays, data from aChanges replaces originals. 
       
   264     Matching depends on aKeyOnly parameter's value. If true, matching is only
       
   265     based on key. If false, settings values will be compared
       
   266     For SWI merges this replacement is also dependent on whether the setting has been modified
       
   267 (c)	aMergeType is the merge type
       
   268 Future: All descriptors are deeply copied; must change to use shallow copy for greater efficiency.
       
   269 @post Following a requirement that notifications are only made if values have changed:
       
   270 1. Settings flagged as deleted without a counterpart in the persistent array are removed from aChanges.
       
   271 2. Where the new value and the existing value are the same, the setting is removed from aChanges.
       
   272 */
       
   273 TInt RSettingsArray::MergeArray(RSettingsArray& aChanges, RArray<TUint32> & aDeletedSettings, TMergeType aMergeType, TBool aKeyOnly)
       
   274 	{
       
   275 	TInt error = KErrNone;
       
   276 	TInt numChanges;
       
   277 	TInt i;
       
   278 		
       
   279 	// For downgrade remove SWI only keys
       
   280 	if(aMergeType==ESWIDowngradeMerge)
       
   281 		{
       
   282 		numChanges = Count();
       
   283 		i = 0;
       
   284 		while ((i < numChanges) && (KErrNone == error))
       
   285 			{
       
   286 			TServerSetting source = operator[](i);
       
   287 			// find index of item in array matching the index of this change
       
   288 			TInt targetIndex = aChanges.FindIndex(source);
       
   289 			if (targetIndex == KErrNotFound)
       
   290 				{
       
   291 				// If key is default and wasn't in the ROM, it was an install key
       
   292 				// so remove it
       
   293 				if(source.IsClean())
       
   294 					{
       
   295 					DeleteElement(i);
       
   296 					--numChanges;
       
   297 					--i;
       
   298 					}
       
   299 				}
       
   300 			++i;
       
   301 			}
       
   302 		}
       
   303 
       
   304 	numChanges = aChanges.Count();
       
   305 	i=0;
       
   306 	
       
   307 	while ((i < numChanges) && (KErrNone == error))
       
   308 		{
       
   309 		const TServerSetting& source = aChanges[i];
       
   310 		// find index of item in array matching the index of this change
       
   311 		TInt targetIndex = FindIndex(source);
       
   312 		if (targetIndex == KErrNotFound)
       
   313 			{
       
   314 			if (source.IsDeleted())
       
   315 				{
       
   316 				// remove setting that is flagged as deleted to prevent notification
       
   317 				aChanges.DeleteElement(i);
       
   318 				i--;
       
   319 				numChanges--;
       
   320 				}
       
   321 			else
       
   322 				{
       
   323 				// add the new setting
       
   324 				TServerSetting newSetting(source.Key());
       
   325 				error = newSetting.Replace(source);
       
   326 				if (error == KErrNone)
       
   327 					{
       
   328 					error = OrderedInsert(newSetting);
       
   329 					TInt deletedSetting = aDeletedSettings.FindInUnsignedKeyOrder(source.Key());
       
   330 					if (KErrNotFound != deletedSetting)
       
   331 						{
       
   332 						aDeletedSettings.Remove(deletedSetting) ;
       
   333 						}
       
   334 					if (error != KErrNone)
       
   335 						{
       
   336 						newSetting.Reset();
       
   337 						}
       
   338 					}
       
   339 				}
       
   340 			}
       
   341 		else
       
   342 			{
       
   343 			if (source.IsDeleted())
       
   344 				{
       
   345 				// Retain "deleted element" state for settings marked for backup so that
       
   346 				// we can persist state correctly across a backup/restore cycle.
       
   347 				if (operator[](targetIndex).Meta() & KMetaBackup)
       
   348 					{
       
   349 						aDeletedSettings.InsertInUnsignedKeyOrder(source.Key()) ;
       
   350 					}
       
   351 				DeleteElement(targetIndex);
       
   352 				}
       
   353 			else
       
   354 				{
       
   355 				TServerSetting& target = operator[](targetIndex);
       
   356 				if ((target == source) && (aKeyOnly==EFalse))
       
   357 					{
       
   358 					// value not changing: remove setting to prevent notification
       
   359 					// Note that for SWI merges, settings are not deleted from 
       
   360 					// aChanges unless they are marked with EDeleted.
       
   361 					aChanges.DeleteElement(i);
       
   362 					i--;
       
   363 					numChanges--;
       
   364 					}
       
   365 				else
       
   366 					{						
       
   367 					if( (aMergeType==ESWIUpgradeMerge) || (aMergeType==ESWIDowngradeMerge))
       
   368 						{
       
   369 						if(target.IsClean())
       
   370 							{
       
   371 							error = target.Replace(source);
       
   372 							}
       
   373 						else
       
   374 							{
       
   375 							// value not changing: remove setting to prevent notification
       
   376 							aChanges.DeleteElement(i);
       
   377 							i--;
       
   378 							numChanges--;
       
   379 							}
       
   380 						}
       
   381 					else
       
   382 						{
       
   383 						error = target.Replace(source);
       
   384 						}
       
   385 					}
       
   386 				}
       
   387 			}
       
   388 		i++;
       
   389 		}
       
   390 	aDeletedSettings.Compress();
       
   391 	return error;
       
   392 	}
       
   393 
       
   394 // merge transaction settings (which may include entries flagged as deleted), persist and notify
       
   395 // private method relies on calling code to ensure it is permitted to make changes here.
       
   396 // if this method is committing any changes, it cancels all other sessions' transactions
       
   397 TInt CSharedRepository::DoCommitTransactionSettings(CRepositoryTransactor& aTransactor, TUint32& aKeyInfo)
       
   398 	{
       
   399 	aKeyInfo = KUnspecifiedKey;
       
   400 	if (0 == aTransactor.iTransactionSettings.Count())
       
   401 		{
       
   402 		aKeyInfo = 0; // == number of settings modified
       
   403 		return KErrNone; // nothing to do
       
   404 		}
       
   405  	TInt error = iSettings.MergeArray(aTransactor.iTransactionSettings, iDeletedSettings, ETransactionMerge, EFalse);
       
   406 	TInt numChanges = aTransactor.iTransactionSettings.Count();
       
   407 	if (numChanges == 0)
       
   408 		{
       
   409 		if (error == KErrNone)
       
   410 			{
       
   411 			aKeyInfo = 0; // no changes
       
   412 			}
       
   413 		// no changes were made, so the internal cache is still valid.
       
   414 		// This could be because there were no changes: empty list, only deletes on
       
   415 		// non-existent items (a setting created and deleted in the transaction),
       
   416 		// or because of error, such as failure of an initial realloc failure.
       
   417 		return error;
       
   418 		}
       
   419 	if (error != KErrNone)
       
   420 		{
       
   421 		// the repository is corrupted. Dump it for lazy loading later
       
   422 		ResetContent();
       
   423 		}
       
   424 	if (error == KErrNone)
       
   425 		{
       
   426 		// changes have been made: fail all other sessions' transactions so we can commit
       
   427 		FailAllTransactions(/*aExcludeTransactor=*/&aTransactor);
       
   428 		error = CommitChanges(); // this already calls ResetContent() in case of failure
       
   429 		}
       
   430 	if (error == KErrNone)
       
   431 		{
       
   432 		// settings are now persistent on disk: we can now notify about the changes
       
   433 		// following will notify about objects that are created and deleted in the transaction
       
   434 		// this could be made faster by having a multiple Notify method.
       
   435 		// That would also allow Notify messages to be more descriptive - ranges of Keys
       
   436 		for (TInt i = 0; i < numChanges; i++)
       
   437 			{
       
   438 			Notify(aTransactor.iTransactionSettings[i].Key());
       
   439 			}
       
   440 		aKeyInfo = /*reinterpret_cast<TUint32>*/numChanges;
       
   441 		}
       
   442 	return error;
       
   443 	}
       
   444 
       
   445 void CSharedRepository::SetMetaDataOnRead(TServerSetting& aSetting, TBool aSingleMetaFound)
       
   446 	{
       
   447 	TInt isMetaFlagSet = aSetting.Meta() & KMetaDefaultValue;
       
   448 	
       
   449 	if(!aSingleMetaFound)
       
   450 		// No single metadata set for this key
       
   451 		{
       
   452 		// First check for a matching "range" default metadata
       
   453 		// setting
       
   454 		TSettingsDefaultMeta *defaultMeta = iRangeMeta.Find(aSetting.Key());
       
   455 		if (defaultMeta)
       
   456 			{
       
   457 			if (isMetaFlagSet)
       
   458 				//sets a default meta data
       
   459 				//also sets the flag back to indicate that it is a default setting from ROM 
       
   460 				//or previous install so it can be replaced later with a new one. 
       
   461 				aSetting.SetMeta(defaultMeta->GetDefaultMetadata() | KMetaDefaultValue);
       
   462 			else
       
   463 				aSetting.SetMeta(defaultMeta->GetDefaultMetadata());
       
   464 			}
       
   465 		else
       
   466 			{
       
   467 			// Range value not found, try for a repository default
       
   468 			if (isMetaFlagSet)	
       
   469 				aSetting.SetMeta(iDefaultMeta | KMetaDefaultValue) ;
       
   470 			else
       
   471 				aSetting.SetMeta(iDefaultMeta) ;
       
   472 			}
       
   473 		}
       
   474 	}
       
   475 
       
   476 TInt CSharedRepository::CreateL(TServerSetting& aSetting, TSettingsAccessPolicy* &aPolicy, TBool aSingleMetaFound)
       
   477 	{
       
   478 	if(iSettings.Find(aSetting.Key()))
       
   479 		return KErrAlreadyExists;
       
   480 	
       
   481 	SetMetaDataOnRead( aSetting, aSingleMetaFound);
       
   482 		
       
   483 	TUint32 key = aSetting.Key();
       
   484 	aSetting.SetAccessPolicy(aPolicy);
       
   485 
       
   486 	iSettings.OrderedInsertL(aSetting);
       
   487 	Notify(aSetting.Key());
       
   488 	return KErrNone;
       
   489 	}
       
   490 
       
   491 // deletes an individual setting in the shared repository and makes it persistent
       
   492 // if changes are made, all sessions' transactions are failed
       
   493 TInt CSharedRepository::DeleteAndPersist(TUint32 aId)
       
   494 	{
       
   495 	TServerSetting* s = iSettings.Find(aId);
       
   496 	if(!s)
       
   497 		return KErrNotFound;
       
   498 
       
   499 	iSettings.Remove(aId);
       
   500 	// removed a setting, so must fail all sessions' transactions before commit possible
       
   501 	FailAllTransactions(/*aExcludeTransactor=*/NULL);
       
   502 	TInt error = CommitChanges();
       
   503 	if (error == KErrNone)
       
   504 		{
       
   505 		Notify(aId);
       
   506 		}
       
   507 	return error;
       
   508 	}
       
   509 
       
   510 // deletes an individual setting without making it persistent
       
   511 // must not be called while any sessions are in transactions
       
   512 TInt CSharedRepository::DeleteNoPersist(TUint32 aId)
       
   513 	{
       
   514 	// should only be calling this if no transactions are active
       
   515 	ASSERT(!IsTransactionActive());
       
   516 
       
   517 	TServerSetting* s = iSettings.Find(aId);
       
   518 	if(!s)
       
   519 		return KErrNotFound;
       
   520 
       
   521 	iSettings.Remove(aId);
       
   522 	Notify(aId);
       
   523 	return KErrNone;
       
   524 	}
       
   525 
       
   526 TInt CSharedRepository::ResetNoPersistL(TServerSetting& aSetting)
       
   527 	{
       
   528 	TServerSetting* s = iSettings.Find(aSetting.Key());
       
   529 	if ((!s) || (*s != aSetting))
       
   530 		{
       
   531 		if (s)
       
   532 			{
       
   533 			// save access policy of setting
       
   534 			TSettingsAccessPolicy* policy=s->AccessPolicy();
       
   535 			s->Transfer(aSetting);
       
   536 			// restore access policy of setting
       
   537 			s->SetAccessPolicy(policy);
       
   538 			}
       
   539 		else
       
   540 			{
       
   541 			TServerSetting setting;
       
   542 			setting.Transfer(aSetting);
       
   543 			setting.SetAccessPolicy(GetFallbackAccessPolicy(setting.Key()));
       
   544 			setting.PushL();
       
   545 			iSettings.OrderedInsertL(setting);
       
   546 			setting.Pop();
       
   547 			}
       
   548 		}
       
   549 	else
       
   550 		{
       
   551 		return KErrGeneral;
       
   552 		}
       
   553 	return KErrNone;
       
   554 	}
       
   555 
       
   556 // if changes are made, all sessions' transactions are failed
       
   557 void CSharedRepository::ResetAndPersistL(TServerSetting& aSetting)
       
   558 	{
       
   559 	if (ResetNoPersistL(aSetting) == KErrNone)
       
   560 		{
       
   561 		// changed a setting, so must fail all sessions' transactions
       
   562 		// before commit possible
       
   563 		FailAllTransactions(/*aExcludeTransactor=*/NULL);
       
   564 		CommitChangesL();
       
   565 		Notify(aSetting.Key());
       
   566 		}
       
   567 	}
       
   568 
       
   569 TInt CSharedRepository::ResetAllNoPersistL(CSharedRepository& aNewContent)
       
   570 	{
       
   571 	// mark cache as inconsistent in case Reset fails, so it is reloaded.
       
   572 	iInconsistentData = ETrue;
       
   573 
       
   574 	// should not change repository while transactions in progress: should fail them first
       
   575 	ASSERT(!IsTransactionActive());
       
   576 	TInt newCount = aNewContent.iSettings.Count();
       
   577 	TInt count = iSettings.Count();
       
   578 
       
   579 	TInt newIndex = 0;
       
   580 	TInt index = 0;
       
   581 
       
   582 	while(newIndex<newCount && index<count)
       
   583 		{
       
   584 		const TServerSetting& newSetting = aNewContent.iSettings[newIndex];
       
   585 		const TServerSetting& setting = iSettings[index];
       
   586 
       
   587 		TUint32 newKey = newSetting.Key();
       
   588 		TUint32 key = setting.Key();
       
   589 
       
   590 		if(newKey<key)
       
   591 			{
       
   592 			Notify(newKey);
       
   593 			newIndex++;
       
   594 			}
       
   595 		else if(newKey==key)
       
   596 			{
       
   597 			if(newSetting!=setting)
       
   598 				Notify(key);
       
   599 			newIndex++;
       
   600 			index++;
       
   601 			}
       
   602 		else if(newKey>key)
       
   603 			{
       
   604 			Notify(key);
       
   605 			index++;
       
   606 			}
       
   607 		}
       
   608 
       
   609 	while(newIndex<newCount)
       
   610 		Notify(aNewContent.iSettings[newIndex++].Key());
       
   611 
       
   612 	while(index<count)
       
   613 		Notify(iSettings[index++].Key());
       
   614 
       
   615 	// Replace current settings with settings read from ROM, this 
       
   616 	// will leave settings pointing to new single policies
       
   617 	iSettings.AdoptL(aNewContent.iSettings);
       
   618 
       
   619 	// Reset policy pointers to point at this repositories policies
       
   620 	newCount=iSettings.Count();
       
   621 	for(TInt i=0; i<newCount;i++)
       
   622 		{
       
   623 		iSettings[i].SetAccessPolicy(NULL);
       
   624 		TUint32 key = iSettings[i].Key();
       
   625 		iSettings[i].SetAccessPolicy(GetFallbackAccessPolicy(key));
       
   626 		}	
       
   627 
       
   628 	iInconsistentData = EFalse;
       
   629 	return KErrNone;
       
   630 	}
       
   631 	
       
   632 // Comparison relation to allow single policies to be inserted in order
       
   633 TBool CSharedRepository::CompareKeyIds(TSettingsAccessPolicy const &aSinglePolicy, TSettingsAccessPolicy const &aSinglePolicyIndexItem)
       
   634 	{
       
   635 	if(aSinglePolicy.iLowKey==aSinglePolicyIndexItem.iLowKey)
       
   636 		return 0;
       
   637 	return (aSinglePolicy.iLowKey < aSinglePolicyIndexItem.iLowKey)?-1:1;
       
   638 	}
       
   639 
       
   640 // Identity relation to allow single policy for a given key to be found
       
   641 TBool CSharedRepository::SinglePolicyMatchOnKey(TSettingsAccessPolicy const &aSinglePolicy, TSettingsAccessPolicy const &aSinglePolicyIndexItem)
       
   642 	{
       
   643 	return aSinglePolicy.iLowKey==aSinglePolicyIndexItem.iLowKey;
       
   644 	}
       
   645 
       
   646 // returns the read security policy used if there is no per-setting policy at aId
       
   647 const TSecurityPolicy& CSharedRepository::GetFallbackReadAccessPolicy(TUint32 aId)
       
   648 	{
       
   649 	return *(GetFallbackAccessPolicy(aId)->GetReadAccessPolicy());
       
   650 	}
       
   651 
       
   652 // returns the write security policy used if there is no per-setting policy at aId
       
   653 const TSecurityPolicy& CSharedRepository::GetFallbackWriteAccessPolicy(TUint32 aId)
       
   654 	{
       
   655 	return *(GetFallbackAccessPolicy(aId)->GetWriteAccessPolicy());
       
   656 	}
       
   657 
       
   658 // Get pointer to security policy that applies to a given setting
       
   659 TSettingsAccessPolicy* CSharedRepository::GetFallbackAccessPolicy(TUint32 aId)
       
   660 	{
       
   661 	// Check for single policy
       
   662 	TSettingsAccessPolicy policy(aId);
       
   663 	TIdentityRelation<TSettingsAccessPolicy> identity(SinglePolicyMatchOnKey);
       
   664 	TInt index = iSinglePolicies.Find(&policy, identity);
       
   665 	if(KErrNotFound != index)
       
   666 		return iSinglePolicies[index];
       
   667 	
       
   668 	// check if the aId falls into any range specified in the ini file
       
   669 	TSettingsAccessPolicy* rangePolicy = iRangePolicies.Find(aId);
       
   670 	if(rangePolicy)
       
   671 		return rangePolicy;
       
   672 	
       
   673 	// If no single policy or range policy, return default policy
       
   674 	return &iDefaultPolicy;
       
   675 	}
       
   676 
       
   677 
       
   678 TInt CSharedRepository::ReadSettingSavePolicyL(CIniFileIn& aFile,TServerSetting& aSetting, TSettingsAccessPolicy* &aPolicy, TBool& aSingleMetaFound)
       
   679 	{
       
   680 	TBool singleReadPolicyFound;
       
   681 	TBool singleWritePolicyFound;
       
   682 	TSecurityPolicy singleReadPolicy;
       
   683 	TSecurityPolicy singleWritePolicy;
       
   684 
       
   685 	TInt err=aFile.ReadSettingL(aSetting,singleReadPolicy, singleWritePolicy, singleReadPolicyFound, singleWritePolicyFound, aSingleMetaFound);
       
   686 	if(err!=KErrNone)
       
   687 		return err;
       
   688 	
       
   689 	// Set up single policies
       
   690 	if(!singleReadPolicyFound)
       
   691 		singleReadPolicy=GetDefaultReadAccessPolicy();
       
   692 	if(!singleWritePolicyFound)
       
   693 		singleWritePolicy=GetDefaultWriteAccessPolicy();
       
   694 
       
   695 	aSetting.PushL();
       
   696 	if(singleReadPolicyFound || singleWritePolicyFound)
       
   697 		{
       
   698 		aPolicy=new (ELeave) TSettingsAccessPolicy(singleReadPolicy,singleWritePolicy,aSetting.Key());
       
   699 		CleanupStack::PushL(aPolicy);
       
   700 		TLinearOrder<TSettingsAccessPolicy> order(&CSharedRepository::CompareKeyIds);
       
   701 		SinglePolicyArray().InsertInOrderL(aPolicy, order);
       
   702 		CleanupStack::Pop(aPolicy);
       
   703 		}
       
   704 	else
       
   705 		{
       
   706 		// check if the aId falls into any range specified in the ini file
       
   707 		// otherwise set policy to default policy
       
   708 		TSettingsAccessPolicy* rangePolicy = iRangePolicies.Find(aSetting.Key());
       
   709 		if(rangePolicy)
       
   710 			aPolicy=rangePolicy;
       
   711 		else
       
   712 			aPolicy=&iDefaultPolicy;
       
   713 		}
       
   714 		
       
   715 	aSetting.Pop();
       
   716 	return err;
       
   717 	}	
       
   718 
       
   719 // Merge settings in this->iSettings with the iSettings of aMergeRep
       
   720 // During an intsall/upgrade event aMergeRep will be created from the installed file
       
   721 // During an upinstall event aMergeRep will be created from the ROM file
       
   722 void CSharedRepository::MergeL(CSharedRepository& aMergeRep, TMergeType aMergeType)
       
   723 	{								
       
   724 	// Process settings from main section - this updates values only
       
   725 	User::LeaveIfError(iSettings.MergeArray(aMergeRep.iSettings, iDeletedSettings, aMergeType));
       
   726 		
       
   727 	// Update all access policies and meta
       
   728 	for(TInt i=0; i<iSettings.Count();i++)
       
   729 		{
       
   730 		TServerSetting& setting= iSettings[i];
       
   731 		setting.SetAccessPolicy(GetFallbackAccessPolicy(setting.Key()));
       
   732 		}
       
   733 	}
       
   734 
       
   735 // Get timestamp of installed file
       
   736 TTime CSharedRepository::InstallTime()
       
   737 	{
       
   738 	return iTimeStamp;
       
   739 	}
       
   740 	
       
   741 // Save timestamp of installed file 
       
   742 void CSharedRepository::SetInstallTime(TTime aInstallTime)
       
   743 	{
       
   744 	iTimeStamp = aInstallTime;
       
   745 	}
       
   746     
       
   747 // Return if this repository's installed file exists and if it does
       
   748 // return the file time stamp as well
       
   749 TInt CSharedRepository::InstallFileTimeStampL(TTime& aModified)
       
   750 	{
       
   751 	// Ensure that there is an install directory
       
   752 	if( !TServerResources::iInstallDirectory)
       
   753 		{
       
   754 		return KErrNotFound;
       
   755 		}
       
   756 	
       
   757 	// Get name for open repository
       
   758 	// Look for .cre file first
       
   759 	HBufC* fullPath(NULL);
       
   760 	TCentRepLocation location=EInstall;
       
   761     TServerResources::CreateRepositoryFileNameLC(fullPath, iUid, location, ECre);
       
   762 		
       
   763 	// Look in install directory to see if this repository has been hit
       
   764 	TEntry entry;
       
   765 	TInt r=TServerResources::iFs.Entry(fullPath->Des(),entry);
       
   766 	if( r == KErrNone)
       
   767 		{
       
   768 		aModified=entry.iModified;
       
   769 		}
       
   770 	else if( r== KErrNotFound)
       
   771 		{
       
   772 		// Look for txt file
       
   773     	TServerResources::CreateRepositoryFileNameLC(fullPath, iUid, location, EIni);
       
   774 		r=TServerResources::iFs.Entry(fullPath->Des(),entry);
       
   775 		if( r == KErrNone)
       
   776 			{
       
   777 			aModified=entry.iModified;
       
   778 			}	
       
   779 		}
       
   780 	return r;
       
   781 	}
       
   782 	
       
   783 // Handle creation or upgrade of file in install directory
       
   784 void CSharedRepository::HandleUpdateMergeL(TTime aInstallFileTimeStamp, CSharedRepository& aInstallRep)
       
   785 	{			
       
   786 	MergeL(aInstallRep, ESWIUpgradeMerge);
       
   787 	
       
   788 	SetInstallTime(aInstallFileTimeStamp);	// Set merge timestamp		
       
   789 	CommitChangesL();						// Commit changes to write C: file
       
   790 
       
   791 	// settings are now persistent on disk: we can now notify about the changes
       
   792 	for (TInt i = 0; i < aInstallRep.iSettings.Count(); i++)
       
   793 		{
       
   794 		Notify(aInstallRep.iSettings[i].Key());
       
   795 		}
       
   796 	}
       
   797 	
       
   798 // Handle merge activity due to an uninstall
       
   799 void CSharedRepository::HandleDeleteMergeL(CSharedRepository& aRomRep)
       
   800 	{
       
   801 	MergeL(aRomRep, ESWIDowngradeMerge);
       
   802 	
       
   803 	SetInstallTime(0);						// Reset timestamp			
       
   804 	CommitChangesL();						// Commit changes to write C: file
       
   805 	
       
   806 	// settings are now persistent on disk: we can now notify about the changes
       
   807 	for (TInt i = 0; i < aRomRep.iSettings.Count(); i++)
       
   808 		{
       
   809 		Notify(aRomRep.iSettings[i].Key());
       
   810 		}
       
   811 	}
       
   812 	
       
   813 
       
   814 /**
       
   815 Statement "iInconsistentData = ETrue;" must be the first statement in the method,
       
   816 "iInconsistentData = EFalse;" must be the last. It is used for lasy-load implementation
       
   817 for the repository and solves the problem that if CommitChangesL() fails the in-memory
       
   818 repository data won't match the repository data, stored in the file.
       
   819 This routine is being retained for testing purposes
       
   820 */
       
   821 void CSharedRepository::DoCommitChangesToIniFileL(const TDesC& aOutFileName)
       
   822 	{
       
   823 	iInconsistentData = ETrue;
       
   824 
       
   825 	// should not be committing while transactions are still active
       
   826 	ASSERT(!IsTransactionActive());
       
   827 
       
   828 	CIniFileOut* out = CIniFileOut::NewLC();
       
   829 
       
   830 	out->WriteHeaderL();
       
   831 	out->WriteOwnerSectionL(iOwner);
       
   832 	out->WriteTimeStampL(iTimeStamp);
       
   833 	out->WriteMetaDataL(iDefaultMeta, iRangeMeta);
       
   834 	out->WritePlatSecL(iDefaultReadPolicy, iDefaultWritePolicy, iRangePolicies);
       
   835 
       
   836 	out->WriteMainSectionHeaderL();
       
   837 	for(TInt i=0; i<iSettings.Count(); i++)
       
   838 		{
       
   839 		const TServerSetting& setting = iSettings[i];
       
   840 		if (setting.HasAccessPolicy() && (iSinglePolicies.Find(setting.AccessPolicy()) != KErrNotFound))
       
   841 			{
       
   842 			out->WriteSettingL(setting, *setting.AccessPolicy());
       
   843 			}
       
   844 		else
       
   845 			{
       
   846 			out->WriteSettingL(setting);
       
   847 			}
       
   848 		}
       
   849 
       
   850 	out->CommitL(aOutFileName);
       
   851 	CleanupStack::PopAndDestroy(out);//out
       
   852 	iInconsistentData = EFalse;
       
   853 	}
       
   854 
       
   855 
       
   856 /**
       
   857 Statement "iInconsistentData = ETrue;" must be the first statement in the method,
       
   858 "iInconsistentData = EFalse;" must be the last. It is used for lasy-load implementation
       
   859 for the repository and solves the problem that if CommitChangesL() fails the in-memory
       
   860 repository data won't match the repository data, stored in the file.
       
   861 */
       
   862 void CSharedRepository::DoCommitChangesL() 
       
   863 	{
       
   864 	iInconsistentData = ETrue;
       
   865 	
       
   866 	// should not be committing while transactions are still active
       
   867 	ASSERT(!IsTransactionActive());
       
   868 	
       
   869 	TCentRepLocation location = EPersists;
       
   870 	HBufC* persistsTrnsFilePath(NULL);
       
   871     //allocates memory on the heap
       
   872     TServerResources::CreateRepositoryFileNameLC(persistsTrnsFilePath,iUid,location,ETmp);
       
   873 	// Create file store
       
   874 	CDirectFileStore* store = CDirectFileStore::ReplaceLC(TServerResources::iFs, *persistsTrnsFilePath,
       
   875 															  (EFileWrite | EFileShareExclusive));
       
   876 	const TUid uid2	 = KNullUid ;														 
       
   877 	store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; 
       
   878 
       
   879 	// Write the stream index/dictionary as root stream within the store
       
   880 	// so we can access it when we do a restore later on
       
   881 	RStoreWriteStream rootStream ;
       
   882 	TStreamId rootStreamId = rootStream.CreateLC(*store) ;
       
   883 	ExternalizeCre(rootStream) ;
       
   884 	rootStream.CommitL() ;
       
   885 		
       
   886 	CleanupStack::PopAndDestroy(&rootStream) ;
       
   887 	store->SetRootL(rootStreamId);
       
   888 	store->CommitL();
       
   889 	CleanupStack::PopAndDestroy(store) ;	
       
   890 	
       
   891 	HBufC* persistsFilePath(NULL);	   
       
   892 	TServerResources::CreateRepositoryFileNameLC(persistsFilePath,iUid,location,ECre);
       
   893 	TEntry entry;
       
   894 	if(TServerResources::iFs.Entry(*persistsFilePath,entry)==KErrNone)
       
   895 		{
       
   896 		User::LeaveIfError(TServerResources::iFs.Replace(*persistsTrnsFilePath, *persistsFilePath));
       
   897 		}
       
   898 	else
       
   899 		{
       
   900 		User::LeaveIfError(TServerResources::iFs.Rename(*persistsTrnsFilePath, *persistsFilePath));
       
   901 		}
       
   902 	
       
   903 	CleanupStack::PopAndDestroy(persistsFilePath);
       
   904 	CleanupStack::PopAndDestroy(persistsTrnsFilePath);		
       
   905 	iInconsistentData = EFalse;		
       
   906 	
       
   907 	// Delete any exitsing ini file on 1st sucessful externalizing of repository
       
   908 	if(iPersistsIniFileExists)
       
   909 		{
       
   910 		HBufC* iniFileName(NULL);	   
       
   911 	    TServerResources::CreateRepositoryFileNameLC(iniFileName,iUid,location,EIni);	
       
   912 		TServerResources::iFs.Delete(*iniFileName);
       
   913 		CleanupStack::PopAndDestroy(iniFileName);
       
   914 		iPersistsIniFileExists=EFalse;
       
   915 		}
       
   916 	}
       
   917 
       
   918 /**
       
   919 The method reloads the repository content from a repository file.
       
   920 The current repository must be emptied (or must be empty already) before the call is made.
       
   921 @param aIniFile A reference to CIniFileIn object, which will be used to load
       
   922 				the repository content.
       
   923 @return KErrCorrupt Corrupted repository file.
       
   924 		KErrNone	The repository content was seccessfully loaded into memory.
       
   925 		KErrNotFound Setting not found in the file.
       
   926 @leave System-wide error codes.
       
   927 @leave KErrGeneral It's probably a programmer's mistake - current CSharedRepository 
       
   928 				   object is partially initialised.
       
   929 */
       
   930 TInt CSharedRepository::ReloadContentL(CIniFileIn& aIniFile)
       
   931 	{
       
   932 	// Preconditions - CSharedRepository object should be an empty one.
       
   933 	if(iSettings.Count() != 0 || iRangeMeta.Count() != 0 ||
       
   934 	   iSinglePolicies.Count() != 0 || iRangePolicies.Count() != 0)
       
   935 		{
       
   936 		User::Leave(KErrGeneral);
       
   937 		}
       
   938 	// Look for an "owner" section
       
   939 	TUint32 uidValue(KNullUid.iUid);
       
   940 	TInt err = aIniFile.ReadOwnerSectionL(uidValue);
       
   941 	if(err == KErrCorrupt)
       
   942 		{
       
   943 		return err;
       
   944 		}
       
   945 	iOwner.iUid = uidValue;
       
   946 	// Timestamp
       
   947 	TTime timeStamp (0);
       
   948 	err = aIniFile.ReadTimeStampSectionL(timeStamp);
       
   949 	if(err == KErrCorrupt)
       
   950 		{
       
   951 		return err;
       
   952 		}
       
   953 	if(timeStamp.Int64() != 0)
       
   954 		{
       
   955 		iTimeStamp = timeStamp;
       
   956 		}
       
   957 
       
   958 	// Metadata
       
   959 	err = aIniFile.ReadDefaultMetaSecSectionL(iDefaultMeta, iRangeMeta);
       
   960 	if(err == KErrCorrupt)
       
   961 		{
       
   962 		return err;
       
   963 		}
       
   964 	// Default read/write policies
       
   965 	TBool gotDefaultReadPolicy;
       
   966 	TBool gotDefaultWritePolicy;
       
   967 	err = aIniFile.ReadPlatSecSectionL(iDefaultReadPolicy, gotDefaultReadPolicy,
       
   968 									   iDefaultWritePolicy, gotDefaultWritePolicy,
       
   969 									   iRangePolicies);
       
   970 	if(err == KErrCorrupt)
       
   971 		{
       
   972 		return err;
       
   973 		}
       
   974 		
       
   975 	iDefaultPolicy=TSettingsAccessPolicy(iDefaultReadPolicy,iDefaultWritePolicy, KUnspecifiedKey);
       
   976 
       
   977 	// Settings
       
   978 	TServerSetting setting;
       
   979 	TSettingsAccessPolicy* policy;
       
   980 	TBool singleMetaFound;
       
   981 	while((err = ReadSettingSavePolicyL(aIniFile, setting, policy, singleMetaFound)) == KErrNone)
       
   982 		{
       
   983 		setting.PushL();
       
   984 		if(iSettings.IsDefault())
       
   985 			{
       
   986 			setting.SetClean();			
       
   987 			}
       
   988 		User::LeaveIfError(CreateL(setting, policy, singleMetaFound));
       
   989 		setting.Pop();
       
   990 		}
       
   991 	if(err == KErrNotFound)			
       
   992 		{
       
   993 		return KErrNone;
       
   994 		}
       
   995 	return err;
       
   996 	}
       
   997 
       
   998 /**
       
   999 Resets current repository data - actually all of them, which may be loaded from
       
  1000 the related ini file.
       
  1001 The iUid data member value is kept as it was at the moment of creation of 
       
  1002 CSharedRepository object.
       
  1003 */
       
  1004 void CSharedRepository::ResetContent()
       
  1005 	{
       
  1006 	iSettings.Reset();
       
  1007 	iOwner = KNullUid;
       
  1008 	iTimeStamp = TTime(0);
       
  1009 
       
  1010 	for (TInt i=0;i<iSinglePolicies.Count();i++)
       
  1011 		{
       
  1012 		delete iSinglePolicies[i];
       
  1013 		}
       
  1014 	iSinglePolicies.Reset();
       
  1015 	iRangePolicies.Reset();
       
  1016 	iDefaultReadPolicy = TSecurityPolicy();
       
  1017 	iDefaultWritePolicy = TSecurityPolicy();
       
  1018 	iDefaultPolicy=TSettingsAccessPolicy(iDefaultReadPolicy,iDefaultWritePolicy, KUnspecifiedKey);
       
  1019 	iDefaultMeta = 0;
       
  1020 	iRangeMeta.Reset();
       
  1021 	}
       
  1022 
       
  1023 /**
       
  1024 This function is used to restore the notification, which was temporary disabled
       
  1025 when making RestoreConsistencyL() call.
       
  1026 @param aNotificationState It points to CObservable::iNotificationState data member, which 
       
  1027 						 controls the notification state - active or disabled.
       
  1028 @internalComponent
       
  1029 */
       
  1030 static void RestoreNotification(void* aNotificationState)
       
  1031 	{
       
  1032 	TBool* notificationState = static_cast <TBool*> (aNotificationState);
       
  1033 	*notificationState = ETrue;
       
  1034 	}
       
  1035 
       
  1036 /**
       
  1037 The method reloads the repository content from the related ini file if previous
       
  1038 CommitChangesL() has not completed successfully.
       
  1039 */
       
  1040 void CSharedRepository::RestoreConsistencyL()
       
  1041 	{
       
  1042 	//Do nothing if previous CommitChangesL() completed successfully.
       
  1043 	if(!iInconsistentData)
       
  1044 		{
       
  1045 		return;
       
  1046 		}
       
  1047 	//Reset current repository data	
       
  1048 	ResetContent();
       
  1049 	//Disable notifications
       
  1050 	TCleanupItem restoreNotification(&RestoreNotification, &iNotificationState);
       
  1051 	CleanupStack::PushL(restoreNotification);
       
  1052 	iNotificationState = EFalse;
       
  1053 	//Reload the repository content from the related ini file
       
  1054 	DoRestoreConsistencyL();
       
  1055 	//Activate notifications
       
  1056 	CleanupStack::PopAndDestroy();//restoreNotification
       
  1057 	
       
  1058 	 TCentRepLocation location = EPersists;
       
  1059 	HBufC* persistsTmpFilePath(NULL);
       
  1060     //allocates memory on the heap
       
  1061     TServerResources::CreateRepositoryFileNameLC(persistsTmpFilePath,iUid,location,ETmp);
       
  1062 	// Remove any .tmp file
       
  1063 	TServerResources::iFs.Delete(*persistsTmpFilePath);
       
  1064 	CleanupStack::PopAndDestroy(persistsTmpFilePath);
       
  1065 	
       
  1066 	iInconsistentData = EFalse;	
       
  1067 	}
       
  1068 
       
  1069 /**
       
  1070 This method looks for and sets a location for a given repository.
       
  1071 It is based on EAuto mode thus it goes through all locations in the
       
  1072 same order (EPersists - EInstall - ERom)  
       
  1073 
       
  1074 @param aLocation - returns a location for a repository
       
  1075 @param aUid - id of a repository which location should be found
       
  1076 @param aType - repository file type (.txt or .cre) 
       
  1077 @return KErrNone if aLocation succesfully set for a given repository,
       
  1078 		KErrNotFound if a repository was not found in any locations.
       
  1079 
       
  1080 @internalTechnology
       
  1081 */
       
  1082 TInt CSharedRepository::FindLocationForFileL(TCentRepLocation& aLocation,TUid aUid,const TCentRepFileType aType) const
       
  1083     { 		
       
  1084 	if(TServerResources::CentrepFileExistsL(aUid, EPersists, aType))
       
  1085 	    {
       
  1086 	     aLocation = EPersists;
       
  1087 		 return KErrNone;
       
  1088 	    }
       
  1089 	    
       
  1090 	if(TServerResources::CentrepFileExistsL(aUid, EInstall, aType))
       
  1091 		{
       
  1092 	     aLocation = EInstall;
       
  1093 		 return KErrNone;
       
  1094 	    }
       
  1095 	    
       
  1096 	if(TServerResources::CentrepFileExistsL(aUid, ERom, aType))
       
  1097 		{
       
  1098 		aLocation = ERom;
       
  1099 		return KErrNone;
       
  1100 		}
       
  1101 
       
  1102 	return KErrNotFound;
       
  1103     }
       
  1104     
       
  1105 /**
       
  1106 The method reloads the repository content from the related cre or ini file.
       
  1107 @leave System-wide error codes
       
  1108 */	
       
  1109 void CSharedRepository::DoRestoreConsistencyL()
       
  1110 	{
       
  1111 	 TCentRepLocation location;
       
  1112 	
       
  1113 	TInt err = FindLocationForFileL(location,iUid,ECre);
       
  1114 	if (err != KErrNotFound)
       
  1115 		{
       
  1116 		User::LeaveIfError(CreateRepositoryFromCreFileL(location));
       
  1117 		return;
       
  1118 		}
       
  1119 		
       
  1120 	User::LeaveIfError(FindLocationForFileL(location,iUid,EIni));
       
  1121 	
       
  1122 	HBufC* fileName(NULL);
       
  1123     TServerResources::CreateRepositoryFileNameLC(fileName,iUid,location,EIni);	
       
  1124  
       
  1125 	CIniFileIn* iniFile = NULL;
       
  1126 	err = CIniFileIn::NewLC(iniFile,fileName,location);
       
  1127 	User::LeaveIfError(err);
       
  1128 	
       
  1129 
       
  1130 	err = ReloadContentL(*iniFile);
       
  1131 	User::LeaveIfError(err);
       
  1132 	
       
  1133 	CleanupStack::PopAndDestroy(iniFile); //iniFile 
       
  1134 	CleanupStack::PopAndDestroy(fileName);	//fileName
       
  1135 	fileName=0;
       
  1136 	}
       
  1137     
       
  1138 TInt CSharedRepository::CreateRepositoryFromCreFileL( TCentRepLocation aLocation)
       
  1139 	{
       
  1140 	// Get file path name from location
       
  1141     HBufC* filePath(NULL);
       
  1142     TServerResources::CreateRepositoryFileNameLC(filePath,iUid, aLocation,ECre);
       
  1143     // Trap errors from repository creation so we can delete corrupt repositories
       
  1144 	TRAPD(error, CreateRepositoryFromCreFileL(*filePath));
       
  1145 	if(error!=KErrNone && error!=KErrNotFound && error!=KErrNoMemory)
       
  1146 		{
       
  1147 		error=KErrCorrupt;
       
  1148 		// store wasn't quite what we were expecting - can't return an error, can't leave
       
  1149 		// so all we can do is close the file, tidy up as best we can, and return corrupt 
       
  1150 		if (aLocation != ERom)
       
  1151 			{
       
  1152 			TServerResources::iFs.Delete(*filePath) ;
       
  1153 			}
       
  1154 		}
       
  1155 	else if( error==KErrNoMemory)
       
  1156 		{
       
  1157 		User::Leave(KErrNoMemory);
       
  1158 		}
       
  1159 	CleanupStack::PopAndDestroy(filePath);
       
  1160 	return error;
       
  1161 	}
       
  1162     
       
  1163 void CSharedRepository::CreateRepositoryFromCreFileL(TDesC& aFilePath )
       
  1164 	{	
       
  1165 
       
  1166 	TEntry entry;
       
  1167 	TInt e = TServerResources::iFs.Entry(aFilePath, entry);	
       
  1168 	if(e==KErrNotFound || e==KErrPathNotFound)
       
  1169 		{
       
  1170 		User::Leave( KErrNotFound);
       
  1171 		}
       
  1172 
       
  1173 	CDirectFileStore* store = 
       
  1174 	    CDirectFileStore::OpenLC (TServerResources::iFs,aFilePath, EFileRead|EFileShareReadersOnly);
       
  1175 	if(store->Type()[0] != KDirectFileStoreLayoutUid)
       
  1176 		{
       
  1177 		User::Leave(KErrCorrupt);
       
  1178 		}
       
  1179 
       
  1180 	// Get the root stream and attempt to read the index from it
       
  1181 	TStreamId rootStreamId = store->Root() ;
       
  1182 	RStoreReadStream rootStream ;
       
  1183 	rootStream.OpenLC(*store, rootStreamId);
       
  1184 	// Internalize the repository
       
  1185 	InternalizeCreL(rootStream);
       
  1186 	CleanupStack::PopAndDestroy(&rootStream);
       
  1187 	CleanupStack::PopAndDestroy(store);
       
  1188 	}
       
  1189 
       
  1190 /** Attempts to start a transaction.
       
  1191 Guaranteed to succeed (return KErrNone) for EConcurrentReadWriteTransaction mode only.
       
  1192 @param aTransactor transactor attempting to start transaction
       
  1193 @param aMode type of transaction to be started
       
  1194 @pre transactor is not in a transaction
       
  1195 @return KErrNone if the transaction is started, KErrLocked if read/write locks prevented that
       
  1196 type of transaction from starting now, and KErrArgument for invalid aMode.
       
  1197 @post On returning KErrNone, transaction is started and read/write locks are obtained for it
       
  1198 in the shared repository. Any other return: transaction has not started.
       
  1199 */
       
  1200 TInt CSharedRepository::StartTransaction(CRepositoryTransactor& aTransactor, TInt aMode)
       
  1201 	{
       
  1202 	// session can only be in one transaction
       
  1203 	ASSERT(!aTransactor.IsInTransaction());
       
  1204 	switch (aMode)
       
  1205 		{
       
  1206 		case EConcurrentReadWriteTransaction:
       
  1207 			// can always start this type of transaction
       
  1208 			iNumActiveConcurrentReadWriteTransactions++;
       
  1209 			break;
       
  1210 		case EReadTransaction:
       
  1211 			// negative lock means there is an active EReadWriteTransaction
       
  1212 			if (iPessimisticTransactionLockCount < 0)
       
  1213 				{
       
  1214 				ASSERT(iPessimisticTransactionLockCount == -1); // sanity check
       
  1215 				return KErrLocked;
       
  1216 				}
       
  1217 			// when non-negative lock equals number of active EReadTransactions.
       
  1218 			iPessimisticTransactionLockCount++;
       
  1219 			break;
       
  1220 		case EReadWriteTransaction:
       
  1221 			// lock is zero if there are no active pessimistic transactions
       
  1222 			if (iPessimisticTransactionLockCount != 0)
       
  1223 				{
       
  1224 				return KErrLocked;
       
  1225 				}
       
  1226 			// lock value of -1 means the exclusive EReadWriteTransaction is active
       
  1227 			iPessimisticTransactionLockCount = -1;
       
  1228 			break;
       
  1229 		default:
       
  1230 			// not a valid transaction mode
       
  1231 			return KErrArgument;
       
  1232 		}
       
  1233 	aTransactor.AddToQueue(iTransactors, aMode);
       
  1234 	return KErrNone;
       
  1235 	}
       
  1236 
       
  1237 /**	Commit transaction
       
  1238 @return KErrNone on success, or error code.
       
  1239 @param aKeyInfo 
       
  1240 	on success (return KErrNone): aKeyInfo returns number of modified settings;
       
  1241 	on failure (other error code): KUnspecifiedKey
       
  1242 @pre transactor is in a transaction.
       
  1243 @post transactor is not in a transaction
       
  1244 */
       
  1245 TInt CSharedRepository::CommitTransaction(CRepositoryTransactor& aTransactor, TUint32& aKeyInfo)
       
  1246 	{
       
  1247 	// calling code should have panicked the client if not in a transaction
       
  1248 	ASSERT(aTransactor.IsInTransaction());
       
  1249 	TInt result = aTransactor.iTransactionResult;
       
  1250 	if (aTransactor.IsInFailedTransaction())
       
  1251 		{
       
  1252 		ASSERT(result != KErrNone);
       
  1253 		aKeyInfo = aTransactor.iTransactionErrorKey;
       
  1254 		}
       
  1255 	else
       
  1256 		{
       
  1257 		ASSERT(result == KErrNone);
       
  1258 		ASSERT(aTransactor.iTransactionErrorKey == KUnspecifiedKey);
       
  1259 		aKeyInfo = 0;
       
  1260 		// must release locks otherwise shared repository will not commit changes
       
  1261 		// failed transactions have already released their locks
       
  1262 		ReleaseTransactionLock(aTransactor);
       
  1263 		}
       
  1264 	
       
  1265 	// transactions that haven't made any changes can be closed at any time
       
  1266 	if (aTransactor.IsInActiveReadWriteTransaction() &&
       
  1267 		(aTransactor.iTransactionSettings.Count() > 0))
       
  1268 		{
       
  1269 		result = DoCommitTransactionSettings(aTransactor, aKeyInfo);
       
  1270 		}
       
  1271 
       
  1272 	// transaction is complete - remove from queue
       
  1273 	aTransactor.Deque();
       
  1274 
       
  1275 	return result;
       
  1276 	}
       
  1277 
       
  1278 /**	Cancels the transaction, discarding changes.
       
  1279 @post Not in a transaction
       
  1280 */
       
  1281 void CSharedRepository::CancelTransaction(CRepositoryTransactor& aTransactor)
       
  1282 	{
       
  1283 	if (aTransactor.IsInTransaction())
       
  1284 		{
       
  1285 		ReleaseTransactionLock(aTransactor);
       
  1286 		aTransactor.Deque();
       
  1287 		}
       
  1288 	}
       
  1289 
       
  1290 TInt CSharedRepository::FailTransaction(CRepositoryTransactor& aTransactor, TInt aError, TUint32 aErrorKey)
       
  1291 	{
       
  1292 	ASSERT(aError != KErrNone); // must fail for a reason
       
  1293 	if (aTransactor.IsInActiveTransaction())
       
  1294 		{
       
  1295 		// locks cannot be removed from a failed transaction, so release before failing
       
  1296 		ReleaseTransactionLock(aTransactor);
       
  1297 		aTransactor.SetFailed(aError, aErrorKey);
       
  1298 		}
       
  1299 	return aError; // to allow "return FailTransaction(error, errorKey);" - error written once
       
  1300 	}
       
  1301 
       
  1302 /** Fails all active transactions - except for the optional aExcludeTransactor, releasing locks.
       
  1303 All transactions are failed with reason "KErrLocked" meaning they are "locked out".
       
  1304 This should only be done to allow another agent to change values in the repository.
       
  1305 Beware that all concurrent read/write transactions that are failed with KErrLocked are
       
  1306 expected to retry the transactions straight afterwards - must be careful to allow their
       
  1307 retry strategy to be successful.
       
  1308 */
       
  1309 void CSharedRepository::FailAllTransactions(const CRepositoryTransactor* aExcludeTransactor)
       
  1310 	{
       
  1311 		TDblQueIter<CRepositoryTransactor> transIter(iTransactors);
       
  1312 		CRepositoryTransactor* transactor;
       
  1313 		while ((transactor = transIter++) != NULL)
       
  1314 			{
       
  1315 			if (transactor != aExcludeTransactor)
       
  1316 				{
       
  1317 				FailTransaction(*transactor, KErrLocked, KUnspecifiedKey);
       
  1318 				}
       
  1319 			}
       
  1320 	}
       
  1321 
       
  1322 /** must currently be in active Read transaction. Does not fail
       
  1323 transaction here if promotion to read/write failed.
       
  1324 @return KErrNone if promoted, KErrLocked if not
       
  1325 */
       
  1326 TInt CSharedRepository::AttemptPromoteTransactionToReadWrite(CRepositoryTransactor& aTransactor)
       
  1327 	{
       
  1328 	// transactor should currently be in an active read transaction
       
  1329 	ASSERT(aTransactor.IsInActiveReadTransaction());
       
  1330 	// sanity check: must only be pessimistic reads active
       
  1331 	ASSERT(iPessimisticTransactionLockCount > 0);
       
  1332 	// can promote only if there are no other active read transactions:
       
  1333 	if (1 == iPessimisticTransactionLockCount)
       
  1334 		{
       
  1335 		// may only promote to exclusive read/write as it has the same commit semantics
       
  1336 		// as Read transaction: concurrent R/W must wait for reads to finish first.
       
  1337 		aTransactor.PromoteToExclusiveReadWrite();
       
  1338 		// lock value of -1 means the exclusive EReadWriteTransaction is active
       
  1339 		iPessimisticTransactionLockCount = -1;
       
  1340 		return KErrNone;
       
  1341 		}
       
  1342 	return KErrLocked;
       
  1343 	}
       
  1344 
       
  1345 /** Private helper method which releases any read/write locks held in the shared repository
       
  1346 by this transactor. Caller must set transactor's state or remove from queue as appropriate.
       
  1347 @param aTransactor transactor whose read/write locks are to be released.
       
  1348 @post Any read/write locks held by transactor are released.
       
  1349 */
       
  1350 void CSharedRepository::ReleaseTransactionLock(CRepositoryTransactor& aTransactor)
       
  1351 	{
       
  1352 	if (aTransactor.IsInActiveConcurrentReadWriteTransaction())
       
  1353 		{
       
  1354 		iNumActiveConcurrentReadWriteTransactions--;
       
  1355 		ASSERT(iNumActiveConcurrentReadWriteTransactions >= 0); // sanity check
       
  1356 		}
       
  1357 	else if (aTransactor.IsInActiveReadTransaction())
       
  1358 		{
       
  1359 		iPessimisticTransactionLockCount--;
       
  1360 		ASSERT(iPessimisticTransactionLockCount >= 0); // sanity check
       
  1361 		}
       
  1362 	else if (aTransactor.IsInActiveExclusiveReadWriteTransaction())
       
  1363 		{
       
  1364 		// can only be one exclusive read/write transaction active (lock value -1)
       
  1365 		ASSERT(iPessimisticTransactionLockCount == -1);
       
  1366 		iPessimisticTransactionLockCount = 0;
       
  1367 		}
       
  1368 	}
       
  1369 	
       
  1370 void CSharedRepository::ExternalizeCre(RWriteStream& aStream) const
       
  1371 	{
       
  1372 	aStream << TServerResources::iPersistsVersion;
       
  1373 	aStream << iUid ;
       
  1374 	aStream << iOwner ;
       
  1375 	
       
  1376 	TUint32 count=iSinglePolicies.Count();
       
  1377 	aStream << count;
       
  1378 	for(TInt i=0; i<count;i++)
       
  1379 		{
       
  1380 		aStream << *iSinglePolicies[i];
       
  1381 		}
       
  1382 	
       
  1383 	aStream << iRangePolicies ;
       
  1384 	aStream << iDefaultReadPolicy.Package() ;
       
  1385 	aStream << iDefaultWritePolicy.Package() ;
       
  1386 	
       
  1387 	aStream << iDefaultMeta ;
       
  1388 	aStream << iRangeMeta ;
       
  1389 	aStream << iTimeStamp.Int64() ;
       
  1390 
       
  1391 	aStream << iSettings ;
       
  1392 	
       
  1393 	// Deleted settings
       
  1394 	count = iDeletedSettings.Count() ;
       
  1395 	aStream << count ;
       
  1396 	for (TInt i=0; i<count; i++)
       
  1397 		{
       
  1398 		aStream << iDeletedSettings[i];
       
  1399 		}
       
  1400 	}
       
  1401 
       
  1402 void CSharedRepository::InternalizeCreL(RReadStream& aStream)
       
  1403 	{
       
  1404 	TUint8 version;
       
  1405 	aStream >> version;
       
  1406 	aStream >> iUid ;
       
  1407 	aStream >> iOwner ;
       
  1408 	
       
  1409 	TUint32 count;
       
  1410 	aStream >> count;
       
  1411 	for(TInt i=0; i<count;i++)
       
  1412 		{
       
  1413 		TSettingsAccessPolicy* singlePolicy = new(ELeave) TSettingsAccessPolicy;
       
  1414 		CleanupStack::PushL(singlePolicy);
       
  1415 		aStream >> *singlePolicy;
       
  1416 		iSinglePolicies.AppendL(singlePolicy);
       
  1417 		CleanupStack::Pop(singlePolicy);
       
  1418 		}
       
  1419 	
       
  1420 	iRangePolicies.Reset();		
       
  1421 	aStream >> iRangePolicies ;
       
  1422 	
       
  1423 	HBufC8* securityPolicyPackage ;
       
  1424 	securityPolicyPackage = HBufC8::NewLC(aStream, 10000) ;
       
  1425 	iDefaultReadPolicy.Set(securityPolicyPackage->Des()) ;
       
  1426 	CleanupStack::PopAndDestroy(securityPolicyPackage) ;
       
  1427 	securityPolicyPackage = HBufC8::NewLC(aStream, 10000) ;
       
  1428 	iDefaultWritePolicy.Set(securityPolicyPackage->Des()) ;
       
  1429 	CleanupStack::PopAndDestroy(securityPolicyPackage) ;
       
  1430 	
       
  1431 	iDefaultPolicy=TSettingsAccessPolicy(iDefaultReadPolicy,iDefaultWritePolicy, KUnspecifiedKey);
       
  1432 	
       
  1433 	aStream >> iDefaultMeta ;
       
  1434 	
       
  1435 	iRangeMeta.Reset();
       
  1436 	aStream >> iRangeMeta ;
       
  1437 	
       
  1438 	TInt64 timeStampInt ;
       
  1439 	aStream >> timeStampInt ;
       
  1440 	iTimeStamp = timeStampInt ;
       
  1441 
       
  1442 	iSettings.Reset() ;
       
  1443 	aStream >> iSettings ;
       
  1444 	
       
  1445 	if (version >= KPersistFormatSupportsDeletedSettings)
       
  1446 		{
       
  1447 		// Deleted Settings 
       
  1448 		// Deleted settings
       
  1449 		aStream >> count  ;
       
  1450 		for (TInt i=0; i<count; i++)
       
  1451 			{
       
  1452 			TUint32 keyValue ;
       
  1453 			aStream >> keyValue ;
       
  1454 			iDeletedSettings.InsertInUnsignedKeyOrder(keyValue);
       
  1455 			}
       
  1456 		}
       
  1457 	// Set up access policies
       
  1458 	TInt32 numElements = iSettings.Count();
       
  1459 	for (TInt32 count = 0; count < numElements; count++)
       
  1460 		{
       
  1461 		TServerSetting* setting= &iSettings[count];
       
  1462 		TUint32 key=setting->Key();
       
  1463 		setting->SetAccessPolicy(GetFallbackAccessPolicy(key));
       
  1464 		}
       
  1465 	}
       
  1466 	
       
  1467 void CSharedRepository::SetAllDefaultMetaFlags()	
       
  1468     {
       
  1469     TInt y = iSettings.Count();
       
  1470     for (TInt i=0; i < iSettings.Count(); i++)
       
  1471         {
       
  1472         TUint32 meta = iSettings.operator[](i).Meta();
       
  1473         meta |= KMetaDefaultValue;
       
  1474         iSettings.operator[](i).SetMeta(meta);
       
  1475         }
       
  1476     }