persistentstorage/sqlite3api/OsLayer/os_symbian_mt.cpp
changeset 0 08ec8eefde2f
child 8 fa9941cf3867
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sqlite3api/OsLayer/os_symbian_mt.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1703 @@
+// Copyright (c) 2005-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:
+// os_symbian.cpp
+// The Symbian OS porting layer - multi-threaded implementation.
+// SQLite never accesses the file system and the OS services directly.
+// SQLite uses for that sqlite3_vfs and sqlite3_file objects.
+// sqlite3_vfs and sqlite3_file functionality is implemented in this file - 
+// TVfs and TFileIo classes.
+// 
+//
+
+/**
+ @file
+ @see TVfs
+ @see TFileIo
+*/
+
+#ifdef  SQLITE_OS_SYMBIAN
+
+extern "C" 
+	{
+	#include "sqliteInt.h"
+	#include "os.h"
+	#include "os_common.h"
+	}
+#include <e32math.h>
+#include "os_symbian.h"
+#include "UTraceSqlite.h"
+
+#ifdef SQLITE_TEST
+
+//Count the number of fullsyncs and normal syncs.  This is used to test
+//that syncs and fullsyncs are occuring at the right times.
+extern "C" int sqlite3_sync_count = 0;
+extern "C" int sqlite3_fullsync_count = 0;
+
+//The following variable, if set to a non-zero value, becomes the result
+//returned from sqlite3OsCurrentTime().  This is used for testing.
+extern "C" int sqlite3_current_time = 0;
+
+#endif//SQLITE_TEST
+
+_LIT(KCwd, ".\\");
+
+//Used for the random numbers generation
+static inline TInt64& Seed()
+	{
+	static TInt64 seed = 0;
+	if(seed == 0)
+		{
+		TTime now;
+		now.UniversalTime();
+		seed = now.Int64();
+		}
+	return seed;
+	}
+
+/**
+Os2SqliteErr() is called at the end of many of the interface functions of the OS porting layer (wherever it is appropriate - 
+TFileIo and TVfs interfaces). The purpose of this function is to identify the "out of memory" and "disk is full" errors
+reported by the used Symbian OS APIs (aOsErr parameter) and report them to SQLite as SQLITE_FULL and SQLITE_NOMEM errors.
+The KErrEof error (TFileIo::Read() can return KErrEof) is reported to SQLite as SQLITE_IOERR_SHORT_READ. The rest of failures
+are reported as the error specified in aDefaultErr parameter.
+ 
+@param aOsErr      Symbian OS error
+@param aDefaultErr The default SQLite error that should be used if the aOsErr parameter is not one of:
+                     KErrNone, KErrEof, KErrNoMemory, KErrDiskFull
+@return SQLITE_OK,               The OS porting layer function call has completed successfully, 
+          SQLITE_IOERR_SHORT_READ, The amount of the data read is less than the requested amount,
+          SQLITE_IOERR_NOMEM,      Out of memory,
+          SQLITE_FULL,             The disk is full,
+          aDefaultErr,             The rest of failures will be reported as aDefaultErr.
+*/
+static TInt Os2SqliteErr(TInt aOsErr, TInt aDefaultErr)
+	{
+	switch(aOsErr)
+		{
+		case KErrNone:
+			return SQLITE_OK;	
+		case KErrEof:
+			return SQLITE_IOERR_SHORT_READ;
+		case KErrNoMemory:
+			return SQLITE_IOERR_NOMEM;
+		case KErrDiskFull:
+			return SQLITE_FULL;
+		default:
+#ifdef _DEBUG		
+			RDebug::Print(_L("SQLite3 C API, Os2SqliteErr(), err=%d\n"), aOsErr);
+#endif			
+			break;
+		}
+	return aDefaultErr;
+	}
+	
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////  TStaticFs  /////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Connects the file session used by the SQLite OS porting layer.
+Single RFs instance per process is used.
+
+@return KErrNone The operation was completed successfully,
+                 System-wide error code if the operation has failed.
+*/
+TInt TStaticFs::Connect()
+	{
+	TInt err = iFs.Connect();
+	if(err == KErrNone)	
+		{
+		err = iFs.ShareAuto();	
+		}
+	if(err != KErrNone)
+		{
+		iFs.Close();	
+		}
+	return err;
+	}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////  sqlite3_mutex  /////////////////////////////////////////////////////////////////////////////////////            
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Initializes sqlite3_mutex data members with their default values.
+*/
+sqlite3_mutex::sqlite3_mutex() :
+	iRefCount(0),
+	iOwnerThreadId(KMaxTUint64)
+	{
+	}
+
+/**
+Closes the mutex handle.
+*/
+sqlite3_mutex::~sqlite3_mutex()
+	{
+	iMutex.Close();
+	}
+
+/**
+Gives the calling thread an exclusive access to the SQLite resources (global variables, file handles, buffers, cache, etc.).
+The calling thread becomes a mutex owner.
+If the mutex is already locked by another thread, the calling thread will block until the other thread releases the mutex.
+The method can be called by the mutex owning thread more than once, even if the mutex is already entered.
+*/
+void sqlite3_mutex::Enter()
+	{
+	iMutex.Wait();
+	RThread currThread;
+	iOwnerThreadId = currThread.Id();
+	++iRefCount;
+	}
+	
+/**
+Unlocks the mutex. If sqlite3_mutex::Enter() was called more than once by the owning thread, then the number of 
+sqlite3_mutex::Leave() calls must eventually match the number of sqlite3_mutex::Enter() calls.
+If there are thread(s) blocked on sqlite3_mutex::Enter(), after the mutex gets unlocked one of the waiting threads
+will be able to lock the mutex and get an exclusive access to the guarded resources.
+
+@panic SqliteMt 23 Negative mutex lock counter (in debug builds only)
+@panic SqliteMt 24 The mutex has been entered (locked) by a different thread than the current one (in debug builds only)
+*/
+void sqlite3_mutex::Leave()
+	{
+	__ASSERT_DEBUG(iRefCount > 0, User::Panic(KPanicCategory, EPanicMutexLockCounter));
+#ifdef _DEBUG
+	RThread currThread;	
+	__ASSERT_DEBUG(iOwnerThreadId == currThread.Id(), User::Panic(KPanicCategory, EPanicMutexOwner));
+#endif
+	--iRefCount;
+	iMutex.Signal();
+	}
+
+/**
+Returns true if the mutex is already locked (entered).
+
+@return True if the mutex is locked, false otherwise
+*/
+TBool sqlite3_mutex::IsHeld() const
+	{
+	RThread currThread;
+	return iRefCount != 0 && iOwnerThreadId == currThread.Id();
+	}
+
+/**
+Creates the mutex.
+
+@return KErrNone The operation was completed successfully,
+                 System-wide error code if the operation has failed.
+*/
+TInt sqlite3_mutex::Create()
+	{
+	return iMutex.CreateLocal();
+	}
+
+/**
+Creates new CRecursiveMutex object.
+
+@return A pointer to the created CRecursiveMutex object or NULL if the operation has failed.
+*/
+CRecursiveMutex* CRecursiveMutex::New()
+	{
+	CRecursiveMutex* self = new CRecursiveMutex;
+	if(self)
+		{
+		if(self->Create() != KErrNone)
+			{
+			delete self;	
+			self = NULL;
+			}
+		}
+	return self;
+	}
+
+CRecursiveMutex::~CRecursiveMutex()
+	{
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////  TMutexApi  ////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Initializes the mutex system.
+No-op function.
+
+@return SQLITE_OK
+*/
+int TMutexApi::Init()
+	{
+	SQLUTRACE_PROFILER(0);
+	return SQLITE_OK;
+	}
+	
+/**
+Finalizes the mutex system.
+No-op function.
+
+@return SQLITE_OK
+*/
+int TMutexApi::End()
+	{
+	SQLUTRACE_PROFILER(0);
+	return SQLITE_OK;
+	}
+	
+/**
+Creates a new mutex.
+If the request is for a static mutex, a pointer to already created static mutex will be returned.
+
+@param aType  The mutex type: static, fast, recursive
+@return A pointer to the created mutex or NULL if the operation has failed
+*/
+sqlite3_mutex* TMutexApi::Alloc(int aType)
+	{
+	SQLUTRACE_PROFILER(0);
+	sqlite3_mutex* mutex = NULL;
+	switch(aType)
+		{
+		case SQLITE_MUTEX_FAST:
+		case SQLITE_MUTEX_RECURSIVE:
+			mutex = CRecursiveMutex::New();
+			break;
+		default:
+			mutex = ::StaticMutex(aType - 2);
+			break;	
+		}
+	return mutex;
+	}
+	
+/**
+Destroys a mutex, created previously by a call to TMutexApi::Alloc().
+@param aMutex Pointer to the mutex object that has to be destroyed
+*/
+void TMutexApi::Free(sqlite3_mutex* aMutex)
+	{
+	SQLUTRACE_PROFILER(0);
+	delete aMutex;
+	}
+	
+/**
+Locks the mutex.
+See sqlite3_mutex::Enter() for more details.
+
+@param aMutex Pointer to the mutex object
+
+@see sqlite3_mutex::Enter()
+*/
+void TMutexApi::Enter(sqlite3_mutex* aMutex)
+	{
+	SQLUTRACE_PROFILER(0);
+	aMutex->Enter();
+	}
+	
+/**
+No-op. Always returns SQLITE_BUSY.
+
+@return SQLITE_BUSY
+*/
+int TMutexApi::Try(sqlite3_mutex*)
+	{
+	SQLUTRACE_PROFILER(0);
+	return SQLITE_BUSY;
+	}
+	
+/**
+Unlocks the mutex.
+See sqlite3_mutex::Leave() for more details.
+
+@param aMutex Pointer to the mutex object
+
+@see sqlite3_mutex::Leave()
+*/
+void TMutexApi::Leave(sqlite3_mutex* aMutex)
+	{
+	SQLUTRACE_PROFILER(0);
+	aMutex->Leave();
+	}
+	
+/**
+Checks whether the mutex is locked or not.
+See sqlite3_mutex::IsHeld() for more details.
+
+@param aMutex Pointer to the mutex object
+
+@return True if the mutex is locked, false otherwise
+
+@see sqlite3_mutex::IsHeld()
+*/
+int TMutexApi::Held(sqlite3_mutex* aMutex)
+	{
+	SQLUTRACE_PROFILER(0);
+	return aMutex->IsHeld();
+	}
+	
+/**
+Checks whether the mutex is locked or not.
+See sqlite3_mutex::IsHeld() for more details.
+
+@param aMutex Pointer to the mutex object
+
+@return False if the mutex is locked, true otherwise
+
+@see sqlite3_mutex::IsHeld()
+*/
+int TMutexApi::Notheld(sqlite3_mutex* aMutex)
+	{
+	SQLUTRACE_PROFILER(0);
+	return !aMutex->IsHeld();
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////       SQLite init/release functions     ///////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Initializes the OS porting layer global data.
+*/
+extern "C" SQLITE_EXPORT int sqlite3_os_init(void)
+	{
+	return sqlite3_vfs_register(VfsApi(), 1);
+	}
+
+/**
+Destroys the OS porting layer global data.
+*/
+extern "C" SQLITE_EXPORT int sqlite3_os_end(void)
+	{
+	return sqlite3_vfs_unregister(VfsApi());
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////  TheFileIoApi  /////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Single sqlite3_io_methods instance, which data members (function pointers) are initialized with the addresses of
+TFileIo members. 
+TheFileIoApi is used by SQLite for performing OS independent file I/O.
+
+@see TFileIo
+@see TVfs
+
+@internalComponent
+*/
+const static sqlite3_io_methods TheFileIoApi = 
+	{
+	1,						//Version
+	&TFileIo::Close,
+	&TFileIo::Read,
+	&TFileIo::Write,
+	&TFileIo::Truncate,
+	&TFileIo::Sync,
+	&TFileIo::FileSize,
+	&TFileIo::Lock,
+	&TFileIo::Unlock,
+	&TFileIo::CheckReservedLock,
+	&TFileIo::FileControl,
+	&TFileIo::SectorSize,
+	&TFileIo::DeviceCharacteristics
+	};
+	
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////  TheMutexMethods  //////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+*/
+static sqlite3_mutex_methods TheMutexMethods =
+	{
+	&TMutexApi::Init,
+	&TMutexApi::End,
+	&TMutexApi::Alloc,
+	&TMutexApi::Free,
+	&TMutexApi::Enter,
+	&TMutexApi::Try,
+	&TMutexApi::Leave,
+	&TMutexApi::Held,
+	&TMutexApi::Notheld
+	};
+
+extern "C" sqlite3_mutex_methods* sqlite3DefaultMutex(void)
+	{
+	return &TheMutexMethods;
+	};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////          UTF16<-->UTF8, conversion functions    ////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+The function converts aFileName to UTF16 encoded file name, and stores the UTF16 encoded file name
+to the place pointed by aFileNameDestBuf argument.
+If the UTF16 conversion of the file name failed because the file name is too long or NULL, 
+the function returns EFalse. 
+
+@param aFileName Expected to point to UTF8 encoded, zero terminated string.
+				 Max allowed aFileName length is KMaxFileName (excluding terminating 0 character).
+@param aFileNameDestBuf Output parameter. Will hold UTF16, non-zero-terminated string.
+						The max length must be at least KMaxFileName characters.
+                         
+@return True if the conversion has been completed successfully						 
+*/
+static TBool ConvertToUnicode(const char *aFileName, TDes& aFileNameDestBuf)
+	{
+	if(aFileName)
+		{
+		wchar_t* dest = reinterpret_cast <wchar_t*> (const_cast <TUint16*> (aFileNameDestBuf.Ptr()));
+		TInt len = mbstowcs(dest, aFileName, KMaxFileName);
+		//Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid.
+		if(len > 0 && len <= KMaxFileName)
+			{
+			aFileNameDestBuf.SetLength(len);
+			return ETrue;
+			}
+		}
+	return EFalse;
+	}
+
+/**
+The function converts aFileName to UTF8 encoded file name, and stores the UTF8 encoded file name
+to the place pointed by aFileNameDestBuf argument.
+If the UTF8 conversion of the file name failed because the file name is too long or NULL, 
+the function returns EFalse. 
+
+@param aFileName Expected to point to UTF16 encoded, zero terminated string.
+				 Max allowed aFileName length is KMaxFileName (excluding terminating 0 character).
+@param aFileNameDestBuf Output parameter. Will hold UTF8, non-zero-terminated string.
+						The max length must be at least KMaxFileName characters.
+                         
+@return True if the conversion has been completed successfully						 
+*/
+static TBool ConvertFromUnicode(const TDesC& aFileName, TDes8& aFileNameDestBuf)
+	{
+	char* dest = reinterpret_cast <char*> (const_cast <TUint8*> (aFileNameDestBuf.Ptr()));
+	const wchar_t* src = reinterpret_cast <const wchar_t*> (aFileName.Ptr());
+	TInt len = wcstombs(dest, src, KMaxFileName);
+	//Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid.
+	if(len > 0 && len <= KMaxFileName)
+		{
+		aFileNameDestBuf.SetLength(len);
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////       TDbFile class definition    ///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const TInt KFileBufSize = 8 * 1024;	
+
+/**
+Initializes TDbFile data members with their default values.
+*/
+inline TDbFile::TDbFile() :
+	iFileBuf(KFileBufSize),
+	iFullName(NULL),
+	iSharedLockByte(0),
+	iLockType(SQLITE_LOCK_NONE),
+	iReadOnly(EFalse),
+	iSectorSize(0),
+	iDeviceCharacteristics(-1)
+	{
+	pMethods = 0;
+	}
+
+/**
+Casts the passed sqlite3_file pointer to a reference to the derived class - TDbFile&.
+All sqlite3_file pointers passed to TFileIo methods are actually pointers to TDbFile instances. 
+So the cast is safe.
+
+@param aDbFile A pointer to a sqlite3_file instance
+
+@return A TDbFile reference. 
+@see TFileIo
+@see TVfs
+@see TDbFile
+
+@panic Sqlite 20 In _DEBUG mode if aDbFile is NULL.
+
+@internalComponent
+*/
+static inline TDbFile& DbFile(sqlite3_file* aDbFile)
+	{
+	__ASSERT_DEBUG(aDbFile != 0, User::Panic(KPanicCategory, EPanicNullDbFilePtr));
+	return *(static_cast <TDbFile*> (aDbFile));
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////       TFileIo class definition    ///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+SQLite OS porting layer API.
+
+Closes the file referred by aDbFile parameter.
+If aDbFile, which is actually a pointer to a TDbFile instance, the iFullName data member is not NULL, 
+then the file will be deleted.
+
+@param aDbFile A pointer to a TDbFile instance, than contains the file handle to be closed.
+
+@return SQLITE_OK
+
+@see TDbFile
+*/
+/* static */ int TFileIo::Close(sqlite3_file* aDbFile)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	dbFile.iFileBuf.Close();	
+	if(dbFile.iFullName)
+		{
+		(void)TStaticFs::Fs().Delete(*dbFile.iFullName);
+		delete dbFile.iFullName;
+		dbFile.iFullName = NULL;
+		}
+    OpenCounter(-1);
+	return SQLITE_OK;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Reads from the file referred by the aDbFile parameter.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle to be read from.
+@param aBuf Output parameter. The data read from the file will be copied there.
+			The buffer size must be at least aAmt bytes.
+@param aAmt The amount of data to be read form the file.
+@param aOffset The offset in the file where the read operation should start.
+
+@return SQLITE_FULL,       			The disk is full,
+	    SQLITE_IOERR_SHORT_READ, 	The amount of the data read is less than aAmt,
+	    SQLITE_IOERR_READ, 			File read error,
+	    SQLITE_IOERR_NOMEM,			An out of memory condition has occured,
+	    SQLITE_OK,					The operation has completed successfully.
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::Read(sqlite3_file* aDbFile, void* aBuf, int aAmt, sqlite3_int64 aOffset)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileRead, aAmt, aOffset));
+	SimulateIOError(return SQLITE_IOERR_READ);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	TPtr8 ptr((TUint8*)aBuf, 0, aAmt);
+	TInt err = dbFile.iFileBuf.Read(aOffset, ptr);
+	TInt cnt = ptr.Length();
+	TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_READ);
+	if(cnt != aAmt && (sqliteErr == SQLITE_OK || sqliteErr == SQLITE_IOERR_SHORT_READ))
+		{
+		Mem::FillZ(static_cast <TUint8*> (aBuf) + cnt, aAmt - cnt);
+		sqliteErr = SQLITE_IOERR_SHORT_READ;
+		}
+	return sqliteErr;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Writes to the file referred by the aDbFile parameter.
+"Write beyond the end of the file" operations are allowed.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle to be written to.
+@param aData The data to be written to the file. The buffer size must be at least aAmt bytes.
+@param aAmt The amount of data to be written to the file.
+@param aOffset The offset in the file where the write operation should start.
+
+@return SQLITE_IOERR_WRITE, the file write operation has failed or the file is read-only,
+		SQLITE_FULL,       	The disk is full,
+	    SQLITE_IOERR_NOMEM,	An out of memory condition has occured,
+	    SQLITE_OK,			The operation has completed successfully.
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::Write(sqlite3_file* aDbFile, const void* aData, int aAmt, sqlite3_int64 aOffset)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileWrite, aAmt, aOffset));
+	SimulateIOError(return SQLITE_IOERR_WRITE);
+	SimulateDiskfullError(return SQLITE_FULL);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	TInt err = KErrAccessDenied;
+	if(!dbFile.iReadOnly)
+		{
+		TPtrC8 ptr((const TUint8*)aData, aAmt);
+		err = dbFile.iFileBuf.Write(aOffset, ptr);
+		}
+	return ::Os2SqliteErr(err, SQLITE_IOERR_WRITE);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Truncates the file referred by the aDbFile parameter.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aLength The new file size in bytes.
+
+@return SQLITE_IOERR_TRUNCATE, the file truncate operation has failed or the file is read-only,
+		SQLITE_FULL,       	The disk is full,
+	    					The file truncate operation has failed,
+	    SQLITE_IOERR_NOMEM,	An out of memory condition has occured,
+	    SQLITE_OK,			The operation has completed successfully.
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::Truncate(sqlite3_file* aDbFile, sqlite3_int64 aLength)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileTruncate, aLength));
+	SimulateIOError(return SQLITE_IOERR_TRUNCATE);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	TInt err = KErrAccessDenied;
+	if(!dbFile.iReadOnly)
+		{
+		err = dbFile.iFileBuf.SetSize(aLength);
+		}
+	return ::Os2SqliteErr(err, SQLITE_IOERR_TRUNCATE);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Flushes the file referred by the aDbFile parameter.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aFlags  This parameter is not used in the production builds. It may be one of 
+			   SQLITE_SYNC_NORMAL or SQLITE_SYNC_FULL and is used only by the TCL test suite.
+
+@return SQLITE_IOERR_FSYNC,	This is a read-only file, or  the file flush operation has failed,
+	    SQLITE_IOERR_NOMEM,	An out of memory condition has occured,
+	    SQLITE_FULL,       		The disk is full,
+   	    SQLITE_OK,			The operation has completed successfully.
+
+@see TDbFile
+*/
+/* static */int TFileIo::Sync(sqlite3_file* aDbFile, int aFlags)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	SimulateIOError(return SQLITE_IOERR_FSYNC);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+#ifdef SQLITE_TEST
+	if(aFlags & SQLITE_SYNC_FULL)
+		{
+		sqlite3_fullsync_count++;
+		}
+	sqlite3_sync_count++;
+#else
+	aFlags = aFlags;	
+#endif
+	TInt err = KErrAccessDenied;
+	if(!dbFile.iReadOnly)
+		{
+		err = dbFile.iFileBuf.Flush();
+		}
+	return ::Os2SqliteErr(err, SQLITE_IOERR_FSYNC);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Returns the size of the file referred by the aDbFile parameter.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aSize Output parameter. If the function completes successfully, the file size will be stored there.
+
+@return SQLITE_IOERR_FSTAT,		The file size operation has failed;
+	    SQLITE_IOERR_NOMEM,		An out of memory condition has occured;
+	    SQLITE_OK,				The operation has completed successfully.
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::FileSize(sqlite3_file* aDbFile, sqlite3_int64* aSize)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	SimulateIOError(return SQLITE_IOERR_FSTAT);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	TInt err =  dbFile.iFileBuf.Size(*aSize);
+	return ::Os2SqliteErr(err, SQLITE_IOERR_FSTAT);
+	}
+
+/**
+This function is called when SQLite needs to obtain a read lock. This is done by generating a
+random file position within the first page beyond the first Gb of the file and locking a single byte there.
+There is a possible problem with that random file position, because the database file may be shared between multiple
+connections. That increases the possibility of generating the same "random" file position by different connections to the
+same file. In order to minimise that, TFileIo::GetReadLock() will generate up to 3 different file positions in a case of
+a "lock byte" failure. 
+The generated file position will be stored in TDbFile::iSharedLockByte data member and will be used later for the 
+unlock operation.
+
+@param aDbFile The Os porting layer file handle
+@return KErrNone 	The locking operation has completed successfully,
+		KErrLocked	The 1 byte file area that begins from the generated file position is already locked,
+				    Some other system-wide error codes in a case of  failure.
+
+@see TFileIo::UnlockReadLock()
+*/
+/* static */TInt TFileIo::GetReadLock(TDbFile& aDbFile)
+	{
+	const TInt KLockTryCount = 3;
+	TInt rc = KErrLocked;
+	for(TInt i=0;i<KLockTryCount;++i)
+		{
+	    TInt lock = Math::Rand(Seed());
+	    //Explanation regarding how the file locking works can be found in os.h file, lines 279-335.
+	    //Shortly, in order to read pages from the database the calling thread must obtain a shared lock.
+	    //This is done locking a randomly chosen byte - iSharedLockByte.
+	    //The calculation of iSharedLockByte is done in a way that:
+	    // - All calculated iSharedLockByte fit on a single page, even if the page size is chosen to be the smallest one possible.
+	    //       That's why the "% (SHARED_SIZE - 1)" is used in the calculation;
+	    // - The locked byte cannot be used for storing data. That is the reason SHARED_FIRST to be set to be a position beyond the
+	    //       1Gb boundary;
+	    TInt sharedLockByte = (lock & 0x7fffffff) % (SHARED_SIZE - 1);
+	    rc = aDbFile.iFileBuf.Lock(SHARED_FIRST + sharedLockByte, 1);
+	    if(rc == KErrNone)
+	    	{
+	    	aDbFile.iSharedLockByte = sharedLockByte;
+	    	break;
+	    	}
+		}
+	return rc;
+	}
+
+/**
+Unlocks the file area previously locked by the GetReadLock() call.
+The beginning of the locked area with length 1 byte is stored in TDbFile::iSharedLockByte data member.
+
+@param aDbFile The Os porting layer file handle
+
+@return KErrNone 	The locking operation has completed successfully,
+				    Some other system-wide error codes in a case of  failure.
+
+@see TFileIo::GetReadLock()
+*/
+/* static */TInt TFileIo::UnlockReadLock(TDbFile& aDbFile)
+	{
+	return aDbFile.iFileBuf.UnLock(SHARED_FIRST + aDbFile.iSharedLockByte, 1);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Locks the file, referred by the aDbFile parameter, with the specified lock type.
+The file lock type is stored for later use by the CheckReservedLock() call.
+
+Sometimes when requesting one lock state, additional lock states
+are inserted in between.  The locking might fail on one of the later
+transitions leaving the lock state different from what it started but
+still short of its goal.  The following chart shows the allowed
+transitions and the inserted intermediate states:
+
+SQLITE_LOCK_NONE		-> SQLITE_LOCK_SHARED
+SQLITE_LOCK_SHARED 		-> SQLITE_LOCK_RESERVED
+SQLITE_LOCK_SHARED 		-> (SQLITE_LOCK_PENDING) 	-> 	SQLITE_LOCK_EXCLUSIVE
+SQLITE_LOCK_RESERVED 	-> (SQLITE_LOCK_PENDING) 	-> 	SQLITE_LOCK_EXCLUSIVE
+SQLITE_LOCK_PENDING 	-> SQLITE_LOCK_EXCLUSIVE
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aLockType Lock type: SQLITE_LOCK_NONE, SQLITE_LOCK_SHARED, SQLITE_LOCK_RESERVED, SQLITE_LOCK_PENDING or
+				 SQLITE_LOCK_EXCLUSIVE.
+
+@return SQLITE_IOERR_NOMEM,	An out of memory condition has occured;
+	    SQLITE_BUSY,	    The requested lock cannot be obtained;
+	    SQLITE_LOCK,		File locking error,
+	    SQLITE_OK,			The operation has completed successfully.
+
+@see TFileIo::CheckReservedLock()
+@see TFileIo::Unlock()
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::Lock(sqlite3_file* aDbFile, int aLockType)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	//If there is already a lock of this type or more restrictive on the aDbFile, then - do nothing.
+	if(dbFile.iLockType >= aLockType)
+		{
+		return SQLITE_OK;
+		}
+
+	//The file flushing here must be done in order to get the file buffer object content (iFileBuf data member))
+	//synchronised with the database file content (the database file content may get modified by a different connection
+	//at the same time).
+	if(aLockType == SQLITE_LOCK_SHARED && !dbFile.iReadOnly)
+		{
+		TInt err = dbFile.iFileBuf.Flush(ETrue);
+		if(err != KErrNone)
+			{
+			return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK);
+			}
+		}
+
+	//Make sure the locking sequence is correct
+	__ASSERT_DEBUG(dbFile.iLockType != SQLITE_LOCK_NONE || aLockType == SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock));
+	__ASSERT_DEBUG(aLockType != SQLITE_LOCK_PENDING, User::Panic(KPanicCategory, EPanicInvalidLock));
+	__ASSERT_DEBUG(aLockType != SQLITE_LOCK_RESERVED || dbFile.iLockType == SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock));
+		
+	TInt rc = SQLITE_OK;    //Return code from subroutines
+	TBool locked = ETrue;   //Result of a file lock call (the default value means: "lock accuired")
+  	TInt newLockType = -1;	//Set dbFile.iLockType to this value before exiting
+	TBool gotPendingLock = EFalse;//True if we acquired a SQLITE_LOCK_PENDING lock this time
+
+	//Lock the SQLITE_LOCK_PENDING byte if we need to acquire a SQLITE_LOCK_PENDING lock or
+	//SQLITE_LOCK_SHARED lock. If we are acquiring a SQLITE_LOCK_SHARED lock, the acquisition of
+	//the SQLITE_LOCK_PENDING byte is temporary.
+	newLockType = dbFile.iLockType;
+	if(dbFile.iLockType == SQLITE_LOCK_NONE || (aLockType == SQLITE_LOCK_EXCLUSIVE && dbFile.iLockType == SQLITE_LOCK_RESERVED))
+		{
+		//Try 3 times to get the pending lock.  The pending lock might be
+		//held by another reader process who will release it momentarily.
+		const TInt KLockTryCnt = 3;
+		locked = EFalse;
+		for(TInt i=0;i<KLockTryCnt && !locked;++i)
+			{
+			TInt err = dbFile.iFileBuf.Lock(PENDING_BYTE, 1);
+			if(err != KErrNone && err != KErrLocked) 
+				{
+				return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK);
+				}
+			locked = (err == KErrNone);
+   			if(!locked)
+   				{
+				const TInt KMs = 10;
+				TVfs::Sleep(NULL, KMs * 1000);
+   				}
+			}
+		gotPendingLock = locked;
+		}
+
+	//Acquire a shared lock
+	if(aLockType == SQLITE_LOCK_SHARED && locked)
+		{
+		__ASSERT_DEBUG(dbFile.iLockType == SQLITE_LOCK_NONE, User::Panic(KPanicCategory, EPanicInvalidLock));
+		TInt err = TFileIo::GetReadLock(dbFile);
+		if(err != KErrNone && err != KErrLocked) 
+			{
+			return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK);
+			}
+		locked = (err == KErrNone);
+		if(locked)
+			{
+			newLockType = SQLITE_LOCK_SHARED;
+			}
+  		}
+
+	//Acquire a RESERVED lock
+	if(aLockType == SQLITE_LOCK_RESERVED && locked)
+		{
+		__ASSERT_DEBUG(dbFile.iLockType == SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock));
+		TInt err = dbFile.iFileBuf.Lock(RESERVED_BYTE, 1); 
+		if(err != KErrNone && err != KErrLocked) 
+			{
+			return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK);
+			}
+		locked = (err == KErrNone);
+		if(locked)
+			{
+			newLockType = SQLITE_LOCK_RESERVED;
+			}
+		}
+
+	// Acquire a PENDING lock
+	if(aLockType == SQLITE_LOCK_EXCLUSIVE && locked)
+		{
+		newLockType = SQLITE_LOCK_PENDING;
+		gotPendingLock = EFalse;
+		}
+
+	//Acquire an EXCLUSIVE lock
+	if(aLockType == SQLITE_LOCK_EXCLUSIVE && locked)
+		{
+		__ASSERT_DEBUG(dbFile.iLockType >= SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock));
+		(void)TFileIo::UnlockReadLock(dbFile);
+		TInt err = dbFile.iFileBuf.Lock(SHARED_FIRST, SHARED_SIZE);
+		if(err != KErrNone && err != KErrLocked)
+			{
+			return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK);
+			}
+		locked = (err == KErrNone);
+		if(locked)
+			{
+			newLockType = SQLITE_LOCK_EXCLUSIVE;
+			}
+		}
+
+	// If we are holding a PENDING lock that ought to be released, then
+	// release it now.
+	if(gotPendingLock && aLockType == SQLITE_LOCK_SHARED)
+		{
+		(void)dbFile.iFileBuf.UnLock(PENDING_BYTE, 1);
+  		}
+
+	// Update the state of the lock has held in the file descriptor then
+	// return the appropriate result code.
+	rc = locked ? SQLITE_OK : SQLITE_BUSY;
+	dbFile.iLockType = newLockType;
+	return rc;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Lower the locking level on file descriptor id to locktype.  locktype
+must be either SQLITE_LOCK_NONE or SQLITE_LOCK_SHARED.
+
+If the locking level of the file descriptor is already at or below
+the requested locking level, this routine is a no-op.
+
+It is not possible for this routine to fail if the second argument
+is SQLITE_LOCK_NONE. If the second argument is SQLITE_LOCK_SHARED then this routine
+might return SQLITE_IOERR;
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aLockType Lock type: SQLITE_LOCK_NONE, SQLITE_LOCK_SHARED, SQLITE_LOCK_RESERVED, SQLITE_LOCK_PENDING or
+				 SQLITE_LOCK_EXCLUSIVE.
+
+@return SQLITE_OK,	 		 The operation has completed successfully,
+	     SQLITE_IOERR_UNLOCK, The unlock operation has failed. 
+
+@see TFileIo::CheckReservedLock()
+@see TFileIo::Lock()
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::Unlock(sqlite3_file* aDbFile, int aLockType)
+	{
+	__ASSERT_DEBUG(aLockType <= SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock));
+	
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	TInt rc = SQLITE_OK;
+	TInt currLockType = dbFile.iLockType;
+	
+	if(currLockType >= SQLITE_LOCK_EXCLUSIVE)
+		{
+		(void)dbFile.iFileBuf.UnLock(SHARED_FIRST, SHARED_SIZE);
+		if(aLockType == SQLITE_LOCK_SHARED)
+    		{
+			TInt err = TFileIo::GetReadLock(dbFile); 
+			if(err != KErrNone && err != KErrLocked)
+				{
+				return ::Os2SqliteErr(err, SQLITE_IOERR_UNLOCK);
+				}
+			if(err == KErrLocked)
+				{
+				//This should never happen. We should always be able to reacquire the read lock
+				rc = SQLITE_IOERR_UNLOCK;
+				}
+			}
+		}
+	if(currLockType >= SQLITE_LOCK_RESERVED)
+		{
+    	(void)dbFile.iFileBuf.UnLock(RESERVED_BYTE, 1);
+		}
+	if(aLockType == SQLITE_LOCK_NONE && currLockType >= SQLITE_LOCK_SHARED)
+		{
+		(void)TFileIo::UnlockReadLock(dbFile);
+		}
+	if(currLockType>= SQLITE_LOCK_PENDING)
+		{
+		(void)dbFile.iFileBuf.UnLock(PENDING_BYTE, 1);
+		}
+		
+	dbFile.iLockType = aLockType;
+	return rc;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Checks if the file lock type is SQLITE_LOCK_RESERVED or bigger.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aResOut Output parameter. It should be set to 1 if the stored lock type is bigger or equal 
+							     than SQLITE_LOCK_RESERVED.
+
+@return SQLITE_IOERR_CHECKRESERVEDLOCK, The operation has failed,
+	    SQLITE_OK 					    The operation has completed successfully.
+
+@see TFileIo::Lock()
+@see TFileIo::Unlock()
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::CheckReservedLock(sqlite3_file* aDbFile, int *aResOut)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	TInt rc;
+	if(dbFile.iLockType >= SQLITE_LOCK_RESERVED)
+		{
+		rc = 1;
+  		}
+	else
+		{
+		TInt err = dbFile.iFileBuf.Lock(RESERVED_BYTE, 1);
+		if(err != KErrNone && err != KErrLocked)
+			{
+			return ::Os2SqliteErr(err, SQLITE_IOERR_CHECKRESERVEDLOCK);
+			}
+		rc = (err == KErrNone);
+		if(rc) //non-zero rc means: the lock has been successful (there wasn't a reserved lock on this file)
+			{
+			(void)dbFile.iFileBuf.UnLock(RESERVED_BYTE, 1);
+			}
+    	rc = !rc;
+		}
+	*aResOut = rc;
+	return SQLITE_OK;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Performs an aOp operation on the file referred by the aDbFile parameter.
+Since the only supported operation at the moment is SQLITE_FCNTL_LOCKSTATE, and the current lock type is stored as
+a data memebr of TDbFile, the function implementation has been optimised - no file I/O calls. The stored file lock type
+is retured if the operation is SQLITE_FCNTL_LOCKSTATE.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aOp File operation type. Currently only SQLITE_FCNTL_LOCKSTATE is supported.
+@param aArg An additional input/output parameter which purpose depends on the type of the current file operation.
+			If the file operation is SQLITE_FCNTL_LOCKSTATE, then aArg is used as an output parameter, where
+			the file lock type is stored.
+
+@return SQLITE_ERROR,	Non-supported operation,
+		SQLITE_OK,	The operation has completed successfully.
+	    
+@see TDbFile
+*/
+/* static */ int TFileIo::FileControl(sqlite3_file* aDbFile, int aOp, void* aArg)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileFileCtr, aOp, dbFile.iFullName));
+	TInt err = KErrNone;
+	switch(aOp)
+		{
+		case SQLITE_FCNTL_LOCKSTATE:
+			*(int*)aArg = dbFile.iLockType;
+			break;
+		default:
+			err = KErrArgument;
+			break;
+		}
+	return err == KErrNone ? SQLITE_OK : SQLITE_ERROR;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Retrieves the sector size of the media of the file referred by the aDbFile parameter.
+Since the sector size never changes till the file is open, the function has been optimised - no file I/O calls.
+The sector size is retrieved during the TVfs::Open() call and stored in TDbFile::iSectorSize. The SectorSize()
+call returns the value of TDbFile::iSectorSize.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+
+@return The sector size.
+
+@panic Sqlite 19 In _DEBUG mode - TDbFile::iSectorSize is negative or 0 .
+	    
+@see TDbFile
+@see TVfs::Open()
+*/
+/* static */ int TFileIo::SectorSize(sqlite3_file* aDbFile)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	__ASSERT_DEBUG(dbFile.iSectorSize > 0, User::Panic(KPanicCategory, EPanicInternalError));
+	if(dbFile.iSectorSize > 0)
+		{
+		return dbFile.iSectorSize;	
+		}
+	return SQLITE_DEFAULT_SECTOR_SIZE;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Retrieves the device characteristics of the device of the file referred by the aDbFile parameter.
+Since the device characteristics never change till the file is open, the function has been optimised - no file I/O calls.
+The device characteristics are retrieved during the TVfs::Open() call and stored in TDbFile::iDeviceCharacteristics. 
+The DeviceCharacteristics() call returns the value of TDbFile::iDeviceCharacteristics.
+
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+
+@return A bit set containing the device characteristics.
+	    
+@panic Sqlite 19 In _DEBUG mode - TDbFile::iDeviceCharacteristics is negative or 0 .
+
+@see TDbFile
+@see TVfs::Open()
+*/
+/* static */ int TFileIo::DeviceCharacteristics(sqlite3_file* aDbFile)
+	{
+	SQLUTRACE_PROFILER(aDbFile);
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	__ASSERT_DEBUG(dbFile.iDeviceCharacteristics >= 0, User::Panic(KPanicCategory, EPanicInternalError));
+	if(dbFile.iDeviceCharacteristics >= 0)
+		{
+		return dbFile.iDeviceCharacteristics;	
+		}
+	return 0;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////       TVfs class definition     ///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+Collects information about the drive referred by the aDriveNo parameter.
+
+@param aFs			RFs instance.
+@param aDriveNo     The drive about which an information will be collected.
+@param aVolumeInfo	Output parameter. A reference to a TVolumeIOParamInfo object where the collected information will be stored.
+
+@return KErrNone,          The operation has completed succesfully;
+	    KErrNoMemory,      Out of memory condition has occured;
+                           Note that other system-wide error codes may also be returned.
+	    
+@see TVfs::Open()
+*/
+/* static */ inline TInt TVfs::DoGetVolumeIoParamInfo(RFs& aFs, TInt aDriveNo, TVolumeIOParamInfo& aVolumeInfo)
+	{
+	return aFs.VolumeIOParam(aDriveNo, aVolumeInfo);
+	}
+
+/**
+Retrieves and returns in a bit set the device characteristics.
+
+@param aDriveInfo	A TDriveInfo reference from which the device characteristics will be extracted.
+@param aVolumeInfo	A TVolumeIOParamInfo reference from which the device characteristics will be extracted.
+
+@return A bit set containing the device characteristics: 
+			SQLITE_IOCAP_SAFE_APPEND, SQLITE_IOCAP_ATOMIC, the atomic block size.
+	    
+@see TVfs::DoGetDriveInfo();
+@see TVfs::DoGetVolumeIoParamInfo();
+@see TVfs::Open()
+*/
+/* static */ TInt TVfs::DoGetDeviceCharacteristics(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo)
+	{
+	TInt deviceCharacteristics = 0;	
+	if(aDriveInfo.iDriveAtt & (KDriveAttLocal | KDriveAttInternal))
+		{
+		deviceCharacteristics |= SQLITE_IOCAP_SAFE_APPEND;//Data written first, file size updated second
+		}
+	if(aDriveInfo.iDriveAtt & KDriveAttTransaction)
+		{
+		deviceCharacteristics |= SQLITE_IOCAP_ATOMIC;	
+		}
+	if(aVolumeInfo.iBlockSize >= SQLITE_DEFAULT_SECTOR_SIZE && (aVolumeInfo.iBlockSize & (aVolumeInfo.iBlockSize - 1)) == 0)	
+		{
+		switch(aVolumeInfo.iBlockSize)
+			{
+			case 512:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC512;
+				break;
+			case 1024:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC1K;
+				break;
+			case 2048:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC2K;
+				break;
+			case 4096:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC4K;
+				break;
+			case 8192:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC8K;
+				break;
+			case 16384:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC16K;
+				break;
+			case 32768:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC32K;
+				break;
+			case 65536:
+				deviceCharacteristics |= SQLITE_IOCAP_ATOMIC64K;
+				break;
+			default:
+				//Do nothing. deviceCharacteristics was initialized with 0 at the beginning of the function body.
+				break;
+			}
+		}
+	return deviceCharacteristics;
+	}
+
+/**
+Retrieves and returns the sector size of the drive referred by the aDriveInfo parameter.
+The sector size must be a power of two.
+The sector size is extracted only if aDriveInfo refers to a removable device, otherwise the
+SQLITE_DEFAULT_SECTOR_SIZE value (512 bytes) will be used as a sector size.
+
+@param aDriveInfo	A TDriveInfo reference.
+@param aVolumeInfo	A TVolumeIOParamInfo reference.
+
+@return The sector size of the drive referred by the aDriveInfo parameter.
+
+@panic Sqlite 19 In _DEBUG mode - The sector size is negative, zero or is not a power of two.
+	    
+@see TVfs::Open()
+*/
+/* static */ TInt TVfs::DoGetSectorSize(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo)
+	{
+	//Initialize the sectorSize variable only if: 
+	// - aDriveInfo refers to a removable drive
+	// - aVolumeInfo.iBlockSize > SQLITE_DEFAULT_SECTOR_SIZE;
+	// - aVolumeInfo.iBlockSize is power of 2;
+	TInt sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+	if(aDriveInfo.iDriveAtt & KDriveAttRemovable)
+		{
+		if(aVolumeInfo.iBlockSize > SQLITE_DEFAULT_SECTOR_SIZE && (aVolumeInfo.iBlockSize & (aVolumeInfo.iBlockSize - 1)) == 0)
+			{
+			sectorSize = aVolumeInfo.iBlockSize;
+			}
+		}
+	__ASSERT_DEBUG(sectorSize > 0 && (sectorSize & (sectorSize - 1)) == 0, User::Panic(KPanicCategory, EPanicInternalError));
+	return sectorSize;
+	}
+
+/**
+Retrieves in a bit set the device characteristics of the device of the file referred by the aDbFile parameter.
+Retrieves the sector size of the drive of the file referred by the aDbFile parameter. 
+The sector size and the device characteristics will be stored in iSectorSize and iDeviceCharacteristics TDbFile data members.
+The stored values will be used later by TFileIo::DeviceCharacteristics() and TFileIo::SectorSize().
+
+@param aDbFile	Input/Output parameter. A TDriveInfo reference. The collected information will be stored in TDbDrive
+				data members.
+@param aRecReadBufSize Output parameter. The recommended buffer size for optimised reading performance.
+
+@return KErrNone,          The operation has completed succesfully;
+                           Note that other system-wide error codes may also be returned.
+
+@panic Sqlite 19 In _DEBUG mode - TDbFile::iSectorSize has been already initialized.
+@panic Sqlite 19 In _DEBUG mode - TDbFile::iDeviceCharacteristics has been already initialized.
+
+@see TVfs::DoGetDeviceCharacteristics();
+@see TVfs::DoGetSectorSize();
+@see TVfs::Open()
+@see TDbFile
+@see TFileIo::DeviceCharacteristics()
+@see TFileIo::SectorSize()
+*/
+/* static */ TInt TVfs::DoGetDeviceCharacteristicsAndSectorSize(TDbFile& aDbFile, TInt& aRecReadBufSize)
+	{
+	__ASSERT_DEBUG(aDbFile.iDeviceCharacteristics < 0, User::Panic(KPanicCategory, EPanicInternalError));
+	__ASSERT_DEBUG(aDbFile.iSectorSize <= 0, User::Panic(KPanicCategory, EPanicInternalError));
+	TInt driveNo;
+	TDriveInfo driveInfo;
+	TInt err = aDbFile.iFileBuf.Drive(driveNo, driveInfo);
+	if(err != KErrNone)
+		{
+		return err;	
+		}
+	TVolumeIOParamInfo volumeInfo;
+	err = TVfs::DoGetVolumeIoParamInfo(TStaticFs::Fs(), driveNo, volumeInfo);
+	if(err != KErrNone)
+		{
+		return err;	
+		}
+	aDbFile.iDeviceCharacteristics = TVfs::DoGetDeviceCharacteristics(driveInfo, volumeInfo);
+	aDbFile.iSectorSize = TVfs::DoGetSectorSize(driveInfo, volumeInfo);
+	aRecReadBufSize = volumeInfo.iRecReadBufSize;
+	return KErrNone;
+	}
+
+//Creates a temporary file. The file location will be the application's session path. 
+//If the session path does not exist, then the function will create the session path.
+static TInt CreateTempFile(TDbFile& aDbFile, TFileName& aFileNameOut, TInt aFileMode)
+	{
+	TFileName sessionPath;
+	TInt err = TStaticFs::Fs().SessionPath(sessionPath);
+	if(err == KErrNone)
+		{
+		err = aDbFile.iFileBuf.Temp(TStaticFs::Fs(), sessionPath, aFileNameOut, aFileMode);
+		if(err == KErrPathNotFound)
+			{
+			err = TStaticFs::Fs().MkDirAll(sessionPath);
+			if(err == KErrNone)
+				{
+				err = aDbFile.iFileBuf.Temp(TStaticFs::Fs(), sessionPath, aFileNameOut, aFileMode);
+				}
+			}
+		if(err == KErrNone)
+			{
+			aDbFile.iFullName = aFileNameOut.Alloc();
+			if(!aDbFile.iFullName)
+				{
+				aDbFile.iFileBuf.Close();
+				(void)TStaticFs::Fs().Delete(aFileNameOut);
+				err = KErrNoMemory;
+				}
+			}
+		}
+	return err;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Opens or creates a file which name is in the aFileName parameter.
+If the function succeeds, the file handle and other related information will be stored in the place pointed by the 
+aDbFile parameter, a memory block of sizeof(TDbFile) size for which is allocated by the caller.
+The function will also retrieve the sector size and the device characteristics and store them in aDbFile,
+which is actually a TDbFile pointer, for later use.
+
+@param aFileName Zero-terminated, UTF8 encoded file name.
+				 If aFileName is NULL then a temporary file is created.
+@param aDbFile Output parameter. The file handle and other related information will be stored there.
+@param aFlags  "Open/Create" input flags: 
+					SQLITE_OPEN_DELETEONCLOSE,
+					SQLITE_OPEN_READWRITE,
+					SQLITE_OPEN_EXCLUSIVE,
+					SQLITE_OPEN_CREATE
+@param aOutFlags  "Open/Create" output flags:
+					SQLITE_OPEN_READWRITE,
+					SQLITE_OPEN_READONLY
+
+@return SQLITE_CANTOPEN,    The aFileName parameter cannot be converted to UTF16.
+							Any other file I/O error will also be reported as SQLITE_CANTOPEN;
+	    SQLITE_IOERR_NOMEM,	An out of memory condition has occured;
+	    SQLITE_OK,			The operation has completed successfully.
+	    
+@see TDbFile
+*/
+/* static */ int TVfs::Open(sqlite3_vfs* aVfs, const char* aFileName, sqlite3_file* aDbFile, int aFlags, int* aOutFlags)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	TFileName fname;
+	if(aFileName && !::ConvertToUnicode(aFileName, fname))
+		{
+		return SQLITE_CANTOPEN;	
+		}
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileOpen, aDbFile, &fname));
+	new (aDbFile) TDbFile;
+	TDbFile& dbFile = ::DbFile(aDbFile);
+	if(aFileName && (aFlags & SQLITE_OPEN_DELETEONCLOSE))
+		{
+		dbFile.iFullName = fname.Alloc();
+		if(!dbFile.iFullName)
+			{
+			return SQLITE_IOERR_NOMEM;
+			}
+		}
+	TInt recReadBufSize = -1;
+	TInt err = KErrNone;
+	TInt fmode = EFileRead;
+	if(aFlags & SQLITE_OPEN_READWRITE)
+		{
+		fmode |= EFileWrite;
+		}
+	//SQLite TCL tests expect the journal file to be open in shared mode.
+	if(aFlags & SQLITE_OPEN_EXCLUSIVE && !(aFlags & SQLITE_OPEN_MAIN_JOURNAL))
+		{
+		fmode |= EFileShareExclusive;
+		}
+	else
+		{
+		fmode |= (fmode & EFileWrite) ? EFileShareAny : EFileShareReadersOnly;
+		}
+	if(!aFileName)	
+		{//Create temporary file
+		err = ::CreateTempFile(dbFile, fname, fmode);
+		}
+	else
+		{
+		err = KErrGeneral;//The error has to be set here, because, there is case where none of the file create/open operations will be executed
+		if(aFlags & SQLITE_OPEN_CREATE)
+			{
+			err = dbFile.iFileBuf.Create(TStaticFs::Fs(), fname, fmode);
+			}
+		if(err != KErrNone && err != KErrNoMemory)
+			{
+			err = dbFile.iFileBuf.Open(TStaticFs::Fs(), fname, fmode);
+			}
+		if((err != KErrNone && err != KErrNoMemory) && (aFlags & SQLITE_OPEN_READWRITE))
+			{
+			aFlags &= ~SQLITE_OPEN_READWRITE;
+			aFlags |= SQLITE_OPEN_READONLY;
+			fmode &= ~EFileWrite;
+			err = dbFile.iFileBuf.Open(TStaticFs::Fs(), fname, fmode);
+			}
+		}
+	if(err == KErrNone)
+		{
+		err = TVfs::DoGetDeviceCharacteristicsAndSectorSize(dbFile, recReadBufSize);
+		}
+	if(err != KErrNone)
+		{
+		dbFile.iFileBuf.Close();	
+		delete dbFile.iFullName;
+		dbFile.iFullName = NULL;
+		}
+	else
+		{
+		dbFile.pMethods = &TheFileIoApi;
+		dbFile.iReadOnly = !(aFlags & SQLITE_OPEN_READWRITE);
+		if(aOutFlags)
+			{
+			*aOutFlags = dbFile.iReadOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
+			}
+		(void)dbFile.iFileBuf.SetReadAheadSize(dbFile.iSectorSize, recReadBufSize);
+		OpenCounter(+1);
+		}
+	return ::Os2SqliteErr(err, SQLITE_CANTOPEN);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Deletes a file which name is in the aFileName parameter.
+
+@param aFileName Zero-terminated, UTF8 encoded file name.
+
+@return SQLITE_ERROR,    	The aFileName parameter cannot be converted to UTF16.
+							The file name refers to a private secure database;
+	    SQLITE_IOERR_NOMEM,	An out of memory condition has occured;
+	    SQLITE_IOERR_DELETE,The delete file operation has failed;
+	    SQLITE_OK,			The operation has completed successfully.
+*/
+/* static */ int TVfs::Delete(sqlite3_vfs* aVfs, const char* aFileName, int /*aSyncDir*/)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	SimulateIOError(return SQLITE_IOERR_DELETE);
+	TFileName fname;
+	if(!::ConvertToUnicode(aFileName, fname))
+		{
+		return SQLITE_ERROR;	
+		}
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileName, &fname));
+	TInt err = TStaticFs::Fs().Delete(fname);
+	return ::Os2SqliteErr(err, SQLITE_IOERR_DELETE);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Retrieves an information about a file which name is in the aFileName parameter.
+The requested information type can be: does the file exist, is the file read-only or read/write.
+
+@param aFileName Zero-terminated, UTF8 encoded file name.
+@param aFlags This parameter can be one of: SQLITE_ACCESS_READ, SQLITE_ACCESS_EXISTS or SQLITE_ACCESS_READWRITE.
+@param aResOut Output parameter, set to 1 if the tested condition is true, 0 otherwise.
+
+@return SQLITE_OK, 			The call has completed successfully,
+		SQLITE_IOERR_NOMEM, An out of memory conditon has occured,
+		SQLITE_IOERR_ACCESS,File I/O error;  
+*/
+/* static */ int TVfs::Access(sqlite3_vfs* aVfs, const char* aFileName, int aFlags, int* aResOut)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	TFileName fname;
+	if(!::ConvertToUnicode(aFileName, fname))
+		{
+		return SQLITE_IOERR_ACCESS;
+		}
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileName, &fname));
+	TEntry entry;
+	TInt err = TStaticFs::Fs().Entry(fname, entry);
+	if(aFlags == SQLITE_ACCESS_EXISTS && err == KErrNotFound)
+		{
+		*aResOut = 0;
+		return SQLITE_OK;
+		}
+	if(err != KErrNone)
+		{
+		return err == KErrNoMemory ? SQLITE_IOERR_NOMEM : SQLITE_IOERR_ACCESS;
+		}
+	*aResOut = 0;
+	switch(aFlags)
+		{
+		case SQLITE_ACCESS_READ:
+			*aResOut =  entry.IsReadOnly();
+			break;
+		case SQLITE_ACCESS_EXISTS:
+			*aResOut = 1;
+			break;
+		case SQLITE_ACCESS_READWRITE:
+			*aResOut = !entry.IsReadOnly();
+			break;
+		default:
+			break;			
+		}
+	return SQLITE_OK;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Accepts UTF8 encoded, zero-terminated file as an input argument in the aRelative parameter
+and constructs the full file path in the aBuf output parameter.
+
+If the format of aRelative argument is <[SID]FileName.[EXT]>, then the database file name will be 
+treated as a name of a secure database file which has to be created/opened in the server's private 
+directory on the system drive.
+
+If the format of aRelative argument is <Drive:[SID]FileName.[EXT]>, then the database file name 
+will be treated as a name of a secure database file which has to be created/opened in the server's 
+private directory on <Drive:> drive. 
+
+If the format of aRelative argument is <Drive:\Path\FileName.[EXT]>, then the database file name
+will be treated as a name of a non-secure database file in <Drive:\Path\> directory.
+If aRelative contains file handles, then it will be treated as a name of a file belonging to server's
+private data cage. 
+
+@param aRelative The input file name, zero-terminated, UTF8 encoded.
+@param aBufLen The output buffer length.
+@param aBuf Output buffer for the constructed full file name path. The allocated buffer length must be at least aBufLen bytes.
+
+@return SQLITE_ERROR, The aRelative parameter is NULL or cannot be converted to UTF16;
+		SQLITE_OK The operation has completed successfully.
+*/
+/* static */ int TVfs::FullPathName(sqlite3_vfs* aVfs, const char* aRelative, int aBufLen, char* aBuf)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	if(!aRelative)	//NULL argument
+		{
+		return SQLITE_ERROR;
+		}
+	//Convert the received file name to UTF16
+	TBuf<KMaxFileName + 1> fname;
+	if(!::ConvertToUnicode(aRelative, fname))
+		{
+		return SQLITE_ERROR;
+		}	
+	SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileName, &fname));
+	//Search if the file name begins with ".\" - current directory
+	if(fname.Find(KCwd) == 0)
+		{
+		fname.Delete(0, KCwd().Length());
+		}
+	fname.Append(TChar(0));//Zero-terminate the converted file name
+	TFileName defaultPath;
+	TInt err = TStaticFs::Fs().SessionPath(defaultPath);
+	if(err != KErrNone)
+		{
+		return SQLITE_ERROR;
+		}
+	TParse parse;
+	(void)parse.Set(fname, &defaultPath, 0);//If fname does not have a path, defaultPath will be used
+	TPtr8 dest8(reinterpret_cast <TUint8*> (aBuf), aBufLen);	
+	if(!::ConvertFromUnicode(parse.FullName(), dest8))
+		{
+		return SQLITE_ERROR;	
+		}
+	return SQLITE_OK;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Generates a set of random numbers and stores them in the aBuf output parameter.
+
+@param aBufLen The output buffer length.
+@param aBuf Output buffer for the generated random numbers. The allocated buffer length must be at least aBufLen bytes.
+
+@return The length of the used part of the output buffer.
+*/
+/* static */ int TVfs::Randomness(sqlite3_vfs* aVfs, int aBufLen, char* aBuf)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	const TInt KRandIterations = aBufLen / sizeof(int);
+	for(TInt i=0;i<KRandIterations;++i)
+		{
+		TInt val = Math::Rand(Seed());
+		Mem::Copy(&aBuf[i * sizeof(int)], &val, sizeof(val));
+		}
+	return KRandIterations * sizeof(int);
+	}
+
+/**
+SQLite OS porting layer API.
+
+Sleeps for aMicrosec microseconds.
+
+@param aMicrosec The sleep interval in microseconds.
+
+@return The aMicrosec value.
+*/
+/* static */ int TVfs::Sleep(sqlite3_vfs* aVfs, int aMicrosec)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	User::AfterHighRes(TTimeIntervalMicroSeconds32(aMicrosec));
+	return aMicrosec;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Retrieves the current date and time.
+
+@param aNow Output parameter, where the data and time value will be stored.
+			SQLite processes all times and dates as Julian Day numbers and
+			aNow parameter will contain the julian date and time.
+
+@return 0.
+*/
+/* static */ int TVfs::CurrentTime(sqlite3_vfs* aVfs, double* aNow)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	TTime now;
+	now.UniversalTime();
+	TDateTime date = now.DateTime();
+	TInt year = date.Year();
+	TInt month = date.Month() + 1;
+	TInt day = date.Day() + 1;
+	
+    //Calculate the Julian days
+	TInt jd = day - 32076 +
+	    1461*(year + 4800 + (month - 14)/12)/4 +
+	    367*(month - 2 - (month - 14)/12*12)/12 -
+	    3*((year + 4900 + (month - 14)/12)/100)/4;
+          	
+	*aNow = jd;
+
+    // Add the fractional hours, mins and seconds
+	*aNow += (date.Hour() + 12.0) / 24.0;
+	*aNow += date.Minute() / 1440.0;
+	*aNow += date.Second() / 86400.0;
+	
+#ifdef SQLITE_TEST
+	if( sqlite3_current_time )
+		{
+    	*aNow = sqlite3_current_time / 86400.0 + 2440587.5;
+		}
+#endif
+	return 0;
+	}
+
+/**
+SQLite OS porting layer API.
+
+Retrieves a text description of the last OS error.
+Note: the method has a default "no-op" implementation at the moment. 
+
+@return 0.
+*/
+/* static */int TVfs::GetLastError(sqlite3_vfs* aVfs, int /*aBufLen*/, char* /*aBuf*/)
+	{
+	SQLUTRACE_PROFILER(aVfs);
+	return 0;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#endif//SQLITE_OS_SYMBIAN