persistentstorage/store/UFILE/UF_DICT.CPP
changeset 0 08ec8eefde2f
child 16 b6ab70c1385f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/store/UFILE/UF_DICT.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,250 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "UF_STD.H"
+#include <e32math.h>
+
+const TUid KUidDictionaryFile={0x100000E4};
+
+_LIT(KSystemIniFileLocationSpec,"Z:\\System\\System.ini");
+
+const TUid KSystemIniFileUid = {0x1000010C};
+
+// Thread contention resolution constants
+
+const TInt KSpinCount=40;
+const TInt KLockoutLimit=0xc0000;	// to keep the lock-out time down to ~1sec (this is microseconds)
+const TInt KFailTime=0x1000;		// ~ time to fail to open file
+const TInt KSpinLimit=KLockoutLimit-KSpinCount*KFailTime;
+
+LOCAL_C TUint8 const WaitDistribution[8]={0,0,0,0,0x1f,0x3f,0x7f,0xff};	// wait-time distribution mask
+
+class RYieldThread : public RThread
+	{
+public:
+	inline void Yield() const {SetPriority(Priority());}
+	};
+
+/////////////////////////////////////////////
+// CDictionaryFileStore
+/////////////////////////////////////////////
+
+LOCAL_C void EnsurePathL(RFs& aFs,const TDesC& aName)
+	{
+	TInt r=aFs.MkDirAll(TParsePtrC(aName).DriveAndPath());
+	if (r!=KErrAlreadyExists)
+		User::LeaveIfError(r);
+	}
+
+EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemL(RFs& aFs)
+/** Opens the system dictionary file store.
+
+@param aFs Handle to a file server session.
+@return A pointer to the system file based dictionary store object. */
+	{
+	CDictionaryFileStore* store=SystemLC(aFs);
+	CleanupStack::Pop();
+	return store;
+	}
+
+EXPORT_C CDictionaryFileStore* CDictionaryFileStore::SystemLC(RFs& aFs)
+/** Opens the system dictionary file store and puts the pointer to the file store 
+object onto the cleanup stack.
+
+@param aFs Handle to a file server session. 
+@return A pointer to the system file based dictionary store object. */
+	{
+	TDriveUnit drive(static_cast<TUint>(RFs::GetSystemDrive()));	
+	TParse parse;
+	User::LeaveIfError(parse.Set(drive.Name(), &KSystemIniFileLocationSpec, NULL));
+	
+	EnsurePathL(aFs, parse.FullName());
+	return OpenLC(aFs, parse.FullName(), KSystemIniFileUid);
+	}
+
+EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenL(RFs& aFs,const TDesC& aName,TUid aFileId)
+	/** Creates a file based dictionary store object.
+	
+	If the file with the specified full path name exists, then an attempt is made 
+	to open an existing file store contained within this file. Any existing file 
+	store must satisfy the following conditions:
+	
+	it must be a valid dictionary store
+	
+	the third UID component of the file store type must match the specified UID; 
+	this UID serves to differentiate between dictionary stores
+	
+	otherwise the function leaves with KErrCorrupt.
+	
+	If the file with the specified full path name does not exist, then an attempt 
+	is made to create a new file and to create a file based dictionary within 
+	it. The third UID component of the file store type is set to the specified 
+	UID value.
+	
+	Note that the file is opened in exclusive access mode.
+	
+	@param aFs Handle to a file server session. 
+	@param aName The full path name of the file. 
+	@param aUid3 The UID used to differentiate between dictionary stores.
+	@return A pointer to the file based dictionary store object. 
+	@see TUid
+	@see TUidType */
+	{
+	CDictionaryFileStore* self = CDictionaryFileStore::OpenLC(aFs,aName,aFileId);
+	CleanupStack::Pop();
+	return self;
+	}
+
+EXPORT_C CDictionaryFileStore* CDictionaryFileStore::OpenLC(RFs& aFs,const TDesC& aName,TUid aFileId)
+	/** Creates a file based dictionary store object and puts the pointer onto the 
+	cleanup stack.
+	
+	If the file with the specified full path name exists, then an attempt is made 
+	to open an existing file store contained within this file. Any existing file 
+	store must satisfy the following conditions:
+	
+	it must be a valid dictionary store
+	
+	the third UID component of the file store type must match the specified UID; 
+	this UID serves to differentiate between dictionary stores
+	
+	otherwise the function leaves with KErrCorrupt.
+	
+	If the file with the specified full path name does not exist, then an attempt 
+	is made to create a new file and to create a file based dictionary within 
+	it. The third UID component of the file store type is set to the specified 
+	UID value.
+	
+	Note that the file is opened in exclusive access mode.
+	
+	@param aFs Handle to a file server session. 
+	@param aName The full path name of the file. 
+	@param aUid3 The UID used to differentiate between dictionary stores.
+	@return A pointer to the file based dictionary store object. 
+	@see TUid
+	@see TUidType */
+	{
+	CDictionaryFileStore* self = new(ELeave) CDictionaryFileStore();
+	CleanupStack::PushL(self);
+	self->ConstructL(aFs,aName,aFileId);
+	return self;
+	}
+
+void CDictionaryFileStore::ConstructL(RFs& aFs,const TDesC& aName,TUid aFileId)
+//
+// try to open the file - if this fails KErrNotFound try to create it
+// if the file is in use retry after a pause
+//
+	{
+	RYieldThread thread;
+	TInt64 seed;
+	const TUidType type(KPermanentFileStoreLayoutUid,KUidDictionaryFile,aFileId);
+	for (TInt wait=KLockoutLimit;;)
+		{
+		RFile file;
+		TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite);
+		switch (r)
+			{
+		case KErrNone:
+			{
+			TInt size;
+			if (file.Size(size)==KErrNone && size!=0)
+				{
+				CFileStore* store=NULL;
+				TRAP(r,store=CPermanentFileStore::FromL(file));
+			    if (r==KErrNotSupported||r==KErrEof)
+					r=KErrCorrupt; // treat a bad store file as corrupt
+			    else if (r==KErrNone && store->Type()!=type)
+					{
+					// treat a wrong 3rd UID as corrupt
+					delete store;
+					store = NULL;
+					r=KErrCorrupt;
+					}
+				if (r==KErrCorrupt)
+					{
+					// silently replace the entire file if it is corrupt
+					r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite);
+					if (r==KErrInUse)
+						break;  // try again later...
+					if (r==KErrNone)
+						{
+						CreateStoreL(file,type);
+						return;
+						}
+					}
+				__LEAVE_IF_ERROR(r);
+				__ASSERT_DEBUG(store != NULL, User::Invariant());
+				//coverity[use_after_free]
+    			iStore = store;
+				if (store->Root()==KNullStreamId)
+					CDictionaryStore::ConstructL();
+				}
+			else
+				CreateStoreL(file,type);
+			return;
+			}
+		case KErrNotFound:
+			r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite);
+			if (r==KErrNone)
+				{
+				CreateStoreL(file,type);
+				return;
+				}
+			else if (r==KErrAlreadyExists)
+				;	// try and open after delay
+			else
+				__LEAVE(r);
+			break;
+		case KErrInUse:
+			break;
+		default:
+			__LEAVE(r);
+			}
+		wait-=KFailTime;
+		if (wait<=0)
+			break;		// waited too long
+		if (wait>KSpinLimit)
+			{			// straight back to retry
+			thread.Yield();	// force another reschedule
+			continue;
+			}
+		// random wait time...
+		if (wait==KSpinLimit)
+			{	// initialise random number generator
+			TThreadId id=thread.Id();
+			TUint idVal=*(const TUint*)&id;
+			seed = MAKE_TINT64(idVal^TUint(this),idVal^TUint(&id));
+			Math::Rand(seed);
+			Math::Rand(seed);
+			}
+		TInt pause=Math::Rand(seed)>>11;
+		pause=(pause&WaitDistribution[(pause>>8)&0x7])<<10;
+		if (pause)
+			{
+			wait-=pause;
+			User::After(pause);
+			}
+		}
+	__LEAVE(KErrInUse);
+	}
+
+void CDictionaryFileStore::CreateStoreL(RFile& aFile,const TUidType& aType)
+	{
+	CFileStore* store = CPermanentFileStore::NewL(aFile);
+	iStore = store;
+	store->SetTypeL(aType);
+	CDictionaryStore::ConstructL();
+	}