persistentstorage/store/UFILE/UF_DICT.CPP
changeset 0 08ec8eefde2f
child 16 b6ab70c1385f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1998-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 "UF_STD.H"
       
    17 #include <e32math.h>
       
    18 
       
    19 const TUid KUidDictionaryFile={0x100000E4};
       
    20 
       
    21 _LIT(KSystemIniFileLocationSpec,"Z:\\System\\System.ini");
       
    22 
       
    23 const TUid KSystemIniFileUid = {0x1000010C};
       
    24 
       
    25 // Thread contention resolution constants
       
    26 
       
    27 const TInt KSpinCount=40;
       
    28 const TInt KLockoutLimit=0xc0000;	// to keep the lock-out time down to ~1sec (this is microseconds)
       
    29 const TInt KFailTime=0x1000;		// ~ time to fail to open file
       
    30 const TInt KSpinLimit=KLockoutLimit-KSpinCount*KFailTime;
       
    31 
       
    32 LOCAL_C TUint8 const WaitDistribution[8]={0,0,0,0,0x1f,0x3f,0x7f,0xff};	// wait-time distribution mask
       
    33 
       
    34 class RYieldThread : public RThread
       
    35 	{
       
    36 public:
       
    37 	inline void Yield() const {SetPriority(Priority());}
       
    38 	};
       
    39 
       
    40 /////////////////////////////////////////////
       
    41 // CDictionaryFileStore
       
    42 /////////////////////////////////////////////
       
    43 
       
    44 LOCAL_C void EnsurePathL(RFs& aFs,const TDesC& aName)
       
    45 	{
       
    46 	TInt r=aFs.MkDirAll(TParsePtrC(aName).DriveAndPath());
       
    47 	if (r!=KErrAlreadyExists)
       
    48 		User::LeaveIfError(r);
       
    49 	}
       
    50 
       
    51 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemL(RFs& aFs)
       
    52 /** Opens the system dictionary file store.
       
    53 
       
    54 @param aFs Handle to a file server session.
       
    55 @return A pointer to the system file based dictionary store object. */
       
    56 	{
       
    57 	CDictionaryFileStore* store=SystemLC(aFs);
       
    58 	CleanupStack::Pop();
       
    59 	return store;
       
    60 	}
       
    61 
       
    62 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemLC(RFs& aFs)
       
    63 /** Opens the system dictionary file store and puts the pointer to the file store 
       
    64 object onto the cleanup stack.
       
    65 
       
    66 @param aFs Handle to a file server session. 
       
    67 @return A pointer to the system file based dictionary store object. */
       
    68 	{
       
    69 	TDriveUnit drive(static_cast<TUint>(RFs::GetSystemDrive()));	
       
    70 	TParse parse;
       
    71 	User::LeaveIfError(parse.Set(drive.Name(), &KSystemIniFileLocationSpec, NULL));
       
    72 	
       
    73 	EnsurePathL(aFs, parse.FullName());
       
    74 	return OpenLC(aFs, parse.FullName(), KSystemIniFileUid);
       
    75 	}
       
    76 
       
    77 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenL(RFs& aFs,const TDesC& aName,TUid aFileId)
       
    78 	/** Creates a file based dictionary store object.
       
    79 	
       
    80 	If the file with the specified full path name exists, then an attempt is made 
       
    81 	to open an existing file store contained within this file. Any existing file 
       
    82 	store must satisfy the following conditions:
       
    83 	
       
    84 	it must be a valid dictionary store
       
    85 	
       
    86 	the third UID component of the file store type must match the specified UID; 
       
    87 	this UID serves to differentiate between dictionary stores
       
    88 	
       
    89 	otherwise the function leaves with KErrCorrupt.
       
    90 	
       
    91 	If the file with the specified full path name does not exist, then an attempt 
       
    92 	is made to create a new file and to create a file based dictionary within 
       
    93 	it. The third UID component of the file store type is set to the specified 
       
    94 	UID value.
       
    95 	
       
    96 	Note that the file is opened in exclusive access mode.
       
    97 	
       
    98 	@param aFs Handle to a file server session. 
       
    99 	@param aName The full path name of the file. 
       
   100 	@param aUid3 The UID used to differentiate between dictionary stores.
       
   101 	@return A pointer to the file based dictionary store object. 
       
   102 	@see TUid
       
   103 	@see TUidType */
       
   104 	{
       
   105 	CDictionaryFileStore* self = CDictionaryFileStore::OpenLC(aFs,aName,aFileId);
       
   106 	CleanupStack::Pop();
       
   107 	return self;
       
   108 	}
       
   109 
       
   110 EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenLC(RFs& aFs,const TDesC& aName,TUid aFileId)
       
   111 	/** Creates a file based dictionary store object and puts the pointer onto the 
       
   112 	cleanup stack.
       
   113 	
       
   114 	If the file with the specified full path name exists, then an attempt is made 
       
   115 	to open an existing file store contained within this file. Any existing file 
       
   116 	store must satisfy the following conditions:
       
   117 	
       
   118 	it must be a valid dictionary store
       
   119 	
       
   120 	the third UID component of the file store type must match the specified UID; 
       
   121 	this UID serves to differentiate between dictionary stores
       
   122 	
       
   123 	otherwise the function leaves with KErrCorrupt.
       
   124 	
       
   125 	If the file with the specified full path name does not exist, then an attempt 
       
   126 	is made to create a new file and to create a file based dictionary within 
       
   127 	it. The third UID component of the file store type is set to the specified 
       
   128 	UID value.
       
   129 	
       
   130 	Note that the file is opened in exclusive access mode.
       
   131 	
       
   132 	@param aFs Handle to a file server session. 
       
   133 	@param aName The full path name of the file. 
       
   134 	@param aUid3 The UID used to differentiate between dictionary stores.
       
   135 	@return A pointer to the file based dictionary store object. 
       
   136 	@see TUid
       
   137 	@see TUidType */
       
   138 	{
       
   139 	CDictionaryFileStore* self = new(ELeave) CDictionaryFileStore();
       
   140 	CleanupStack::PushL(self);
       
   141 	self->ConstructL(aFs,aName,aFileId);
       
   142 	return self;
       
   143 	}
       
   144 
       
   145 void CDictionaryFileStore::ConstructL(RFs& aFs,const TDesC& aName,TUid aFileId)
       
   146 //
       
   147 // try to open the file - if this fails KErrNotFound try to create it
       
   148 // if the file is in use retry after a pause
       
   149 //
       
   150 	{
       
   151 	RYieldThread thread;
       
   152 	TInt64 seed;
       
   153 	const TUidType type(KPermanentFileStoreLayoutUid,KUidDictionaryFile,aFileId);
       
   154 	for (TInt wait=KLockoutLimit;;)
       
   155 		{
       
   156 		RFile file;
       
   157 		TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite);
       
   158 		switch (r)
       
   159 			{
       
   160 		case KErrNone:
       
   161 			{
       
   162 			TInt size;
       
   163 			if (file.Size(size)==KErrNone && size!=0)
       
   164 				{
       
   165 				CFileStore* store=NULL;
       
   166 				TRAP(r,store=CPermanentFileStore::FromL(file));
       
   167 			    if (r==KErrNotSupported||r==KErrEof)
       
   168 					r=KErrCorrupt; // treat a bad store file as corrupt
       
   169 			    else if (r==KErrNone && store->Type()!=type)
       
   170 					{
       
   171 					// treat a wrong 3rd UID as corrupt
       
   172 					delete store;
       
   173 					store = NULL;
       
   174 					r=KErrCorrupt;
       
   175 					}
       
   176 				if (r==KErrCorrupt)
       
   177 					{
       
   178 					// silently replace the entire file if it is corrupt
       
   179 					r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite);
       
   180 					if (r==KErrInUse)
       
   181 						break;  // try again later...
       
   182 					if (r==KErrNone)
       
   183 						{
       
   184 						CreateStoreL(file,type);
       
   185 						return;
       
   186 						}
       
   187 					}
       
   188 				__LEAVE_IF_ERROR(r);
       
   189 				__ASSERT_DEBUG(store != NULL, User::Invariant());
       
   190 				//coverity[use_after_free]
       
   191     			iStore = store;
       
   192 				if (store->Root()==KNullStreamId)
       
   193 					CDictionaryStore::ConstructL();
       
   194 				}
       
   195 			else
       
   196 				CreateStoreL(file,type);
       
   197 			return;
       
   198 			}
       
   199 		case KErrNotFound:
       
   200 			r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite);
       
   201 			if (r==KErrNone)
       
   202 				{
       
   203 				CreateStoreL(file,type);
       
   204 				return;
       
   205 				}
       
   206 			else if (r==KErrAlreadyExists)
       
   207 				;	// try and open after delay
       
   208 			else
       
   209 				__LEAVE(r);
       
   210 			break;
       
   211 		case KErrInUse:
       
   212 			break;
       
   213 		default:
       
   214 			__LEAVE(r);
       
   215 			}
       
   216 		wait-=KFailTime;
       
   217 		if (wait<=0)
       
   218 			break;		// waited too long
       
   219 		if (wait>KSpinLimit)
       
   220 			{			// straight back to retry
       
   221 			thread.Yield();	// force another reschedule
       
   222 			continue;
       
   223 			}
       
   224 		// random wait time...
       
   225 		if (wait==KSpinLimit)
       
   226 			{	// initialise random number generator
       
   227 			TThreadId id=thread.Id();
       
   228 			TUint idVal=*(const TUint*)&id;
       
   229 			seed = MAKE_TINT64(idVal^TUint(this),idVal^TUint(&id));
       
   230 			Math::Rand(seed);
       
   231 			Math::Rand(seed);
       
   232 			}
       
   233 		TInt pause=Math::Rand(seed)>>11;
       
   234 		pause=(pause&WaitDistribution[(pause>>8)&0x7])<<10;
       
   235 		if (pause)
       
   236 			{
       
   237 			wait-=pause;
       
   238 			User::After(pause);
       
   239 			}
       
   240 		}
       
   241 	__LEAVE(KErrInUse);
       
   242 	}
       
   243 
       
   244 void CDictionaryFileStore::CreateStoreL(RFile& aFile,const TUidType& aType)
       
   245 	{
       
   246 	CFileStore* store = CPermanentFileStore::NewL(aFile);
       
   247 	iStore = store;
       
   248 	store->SetTypeL(aType);
       
   249 	CDictionaryStore::ConstructL();
       
   250 	}