sl@0: // Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // os_symbian.cpp sl@0: // The Symbian OS porting layer - multi-threaded implementation. sl@0: // SQLite never accesses the file system and the OS services directly. sl@0: // SQLite uses for that sqlite3_vfs and sqlite3_file objects. sl@0: // sqlite3_vfs and sqlite3_file functionality is implemented in this file - sl@0: // TVfs and TFileIo classes. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @see TVfs sl@0: @see TFileIo sl@0: */ sl@0: sl@0: #ifdef SQLITE_OS_SYMBIAN sl@0: sl@0: extern "C" sl@0: { sl@0: #include "sqliteInt.h" sl@0: #include "os.h" sl@0: #include "os_common.h" sl@0: } sl@0: #include sl@0: #include "os_symbian.h" sl@0: #include "SqliteUtil.h" sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "os_symbian_mtTraces.h" sl@0: #endif sl@0: #include "SqliteTraceDef.h" sl@0: sl@0: //Bit-mask constant. If xOpen()'s "aFlag" parameter contains one of these bits set, then the the file top be sl@0: //opened or created is a journal file. sl@0: const TUint KJournalFileTypeBitMask = SQLITE_OPEN_MAIN_JOURNAL | SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_MASTER_JOURNAL; sl@0: sl@0: #ifdef SQLITE_TEST sl@0: sl@0: //Count the number of fullsyncs and normal syncs. This is used to test sl@0: //that syncs and fullsyncs are occuring at the right times. sl@0: extern "C" int sqlite3_sync_count = 0; sl@0: extern "C" int sqlite3_fullsync_count = 0; sl@0: sl@0: //The following variable, if set to a non-zero value, becomes the result sl@0: //returned from sqlite3OsCurrentTime(). This is used for testing. sl@0: extern "C" int sqlite3_current_time = 0; sl@0: sl@0: #endif//SQLITE_TEST sl@0: sl@0: _LIT(KCwd, ".\\"); sl@0: sl@0: //Used for the random numbers generation sl@0: static inline TInt64& Seed() sl@0: { sl@0: static TInt64 seed = 0; sl@0: if(seed == 0) sl@0: { sl@0: TTime now; sl@0: now.UniversalTime(); sl@0: seed = now.Int64(); sl@0: } sl@0: return seed; sl@0: } sl@0: sl@0: /** sl@0: Os2SqliteErr() is called at the end of many of the interface functions of the OS porting layer (wherever it is appropriate - sl@0: TFileIo and TVfs interfaces). The purpose of this function is to identify the "out of memory" and "disk is full" errors sl@0: reported by the used Symbian OS APIs (aOsErr parameter) and report them to SQLite as SQLITE_FULL and SQLITE_NOMEM errors. sl@0: The KErrEof error (TFileIo::Read() can return KErrEof) is reported to SQLite as SQLITE_IOERR_SHORT_READ. The rest of failures sl@0: are reported as the error specified in aDefaultErr parameter. sl@0: sl@0: @param aOsErr Symbian OS error sl@0: @param aDefaultErr The default SQLite error that should be used if the aOsErr parameter is not one of: sl@0: KErrNone, KErrEof, KErrNoMemory, KErrDiskFull sl@0: @return SQLITE_OK, The OS porting layer function call has completed successfully, sl@0: SQLITE_IOERR_SHORT_READ, The amount of the data read is less than the requested amount, sl@0: SQLITE_IOERR_NOMEM, Out of memory, sl@0: SQLITE_FULL, The disk is full, sl@0: aDefaultErr, The rest of failures will be reported as aDefaultErr. sl@0: */ sl@0: static TInt Os2SqliteErr(TInt aOsErr, TInt aDefaultErr) sl@0: { sl@0: switch(aOsErr) sl@0: { sl@0: case KErrNone: sl@0: return SQLITE_OK; sl@0: case KErrEof: sl@0: return SQLITE_IOERR_SHORT_READ; sl@0: case KErrNoMemory: sl@0: return SQLITE_IOERR_NOMEM; sl@0: case KErrDiskFull: sl@0: return SQLITE_FULL; sl@0: default: sl@0: #ifdef _DEBUG sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, OS2SQLITEERR, "OS;0;Os2SqliteErr;aOsErr=%d", aOsErr)); sl@0: #endif sl@0: break; sl@0: } sl@0: return aDefaultErr; sl@0: } sl@0: sl@0: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ////////////////////////// TStaticFs ///////////////////////////////////////////////////////////////////////////////////////// sl@0: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Connects the file session used by the SQLite OS porting layer. sl@0: Single RFs instance per process is used. sl@0: sl@0: @return KErrNone The operation was completed successfully, sl@0: System-wide error code if the operation has failed. sl@0: */ sl@0: TInt TStaticFs::Connect() sl@0: { sl@0: TInt err = iFs.Connect(); sl@0: if(err == KErrNone) sl@0: { sl@0: err = iFs.ShareAuto(); sl@0: } sl@0: if(err != KErrNone) sl@0: { sl@0: iFs.Close(); sl@0: } sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TSTATICFS_CONNECT, "OS;0;TStaticFs::Connect;iFs.Handle()=0x%X;err=%d", iFs.Handle(), err)); sl@0: return err; sl@0: } sl@0: sl@0: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ////////////////////////// sqlite3_mutex ///////////////////////////////////////////////////////////////////////////////////// sl@0: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Initializes sqlite3_mutex data members with their default values. sl@0: */ sl@0: sqlite3_mutex::sqlite3_mutex() : sl@0: iRefCount(0), sl@0: iOwnerThreadId(KMaxTUint64) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, SQLITE3_MUTEX_SQLITE3_MUTEX, "OS;0x%X;sqlite3_mutex::sqlite3_mutex", (TUint)this)); sl@0: } sl@0: sl@0: /** sl@0: Closes the mutex handle. sl@0: */ sl@0: sqlite3_mutex::~sqlite3_mutex() sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, SQLITE3_MUTEX_SQLITE3_MUTEX2, "OS;0x%X;sqlite3_mutex::~sqlite3_mutex", (TUint)this)); sl@0: iMutex.Close(); sl@0: } sl@0: sl@0: /** sl@0: Gives the calling thread an exclusive access to the SQLite resources (global variables, file handles, buffers, cache, etc.). sl@0: The calling thread becomes a mutex owner. sl@0: If the mutex is already locked by another thread, the calling thread will block until the other thread releases the mutex. sl@0: The method can be called by the mutex owning thread more than once, even if the mutex is already entered. sl@0: sl@0: @panic SqliteMt 23 Negative mutex lock counter (in debug builds only) sl@0: */ sl@0: void sqlite3_mutex::Enter() sl@0: { sl@0: __ASSERT_DEBUG(iRefCount >= 0, __SQLITEPANIC(ESqliteOsPanicMutexLockCounter)); sl@0: iMutex.Wait(); sl@0: RThread currThread; sl@0: iOwnerThreadId = currThread.Id(); sl@0: ++iRefCount; sl@0: } sl@0: sl@0: /** sl@0: Unlocks the mutex. If sqlite3_mutex::Enter() was called more than once by the owning thread, then the number of sl@0: sqlite3_mutex::Leave() calls must eventually match the number of sqlite3_mutex::Enter() calls. sl@0: If there are thread(s) blocked on sqlite3_mutex::Enter(), after the mutex gets unlocked one of the waiting threads sl@0: will be able to lock the mutex and get an exclusive access to the guarded resources. sl@0: sl@0: @panic SqliteMt 23 Negative mutex lock counter (in debug builds only) sl@0: @panic SqliteMt 24 The mutex has been entered (locked) by a different thread than the current one (in debug builds only) sl@0: */ sl@0: void sqlite3_mutex::Leave() sl@0: { sl@0: __ASSERT_DEBUG(iRefCount > 0, __SQLITEPANIC(ESqliteOsPanicMutexLockCounter)); sl@0: #ifdef _DEBUG sl@0: RThread currThread; sl@0: __ASSERT_DEBUG(iOwnerThreadId == currThread.Id(), __SQLITEPANIC(ESqliteOsPanicMutexOwner)); sl@0: #endif sl@0: --iRefCount; sl@0: iMutex.Signal(); sl@0: } sl@0: sl@0: /** sl@0: Returns true if the mutex is already locked (entered). sl@0: sl@0: @return True if the mutex is locked, false otherwise sl@0: */ sl@0: TBool sqlite3_mutex::IsHeld() const sl@0: { sl@0: RThread currThread; sl@0: return iRefCount > 0 && iOwnerThreadId == currThread.Id(); sl@0: } sl@0: sl@0: /** sl@0: Creates the mutex. sl@0: sl@0: @return KErrNone The operation was completed successfully, sl@0: System-wide error code if the operation has failed. sl@0: */ sl@0: TInt sqlite3_mutex::Create() sl@0: { sl@0: TInt err = iMutex.CreateLocal(); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, SQLITE3_MUTEX_CREATE, "OS;0x%X;sqlite3_mutex::Create;err=%d", (TUint)this, err)); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Creates new CRecursiveMutex object. sl@0: sl@0: @return A pointer to the created CRecursiveMutex object or NULL if the operation has failed. sl@0: */ sl@0: CRecursiveMutex* CRecursiveMutex::New() sl@0: { sl@0: CRecursiveMutex* self = new CRecursiveMutex; sl@0: if(self) sl@0: { sl@0: if(self->Create() != KErrNone) sl@0: { sl@0: delete self; sl@0: self = NULL; sl@0: } sl@0: } sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, CRECURSIVEMUTEX_NEWL, "OS;0x%X;CRecursiveMutex::New", (TUint)self)); sl@0: return self; sl@0: } sl@0: sl@0: CRecursiveMutex::~CRecursiveMutex() sl@0: { sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ////////////////////////// TMutexApi //////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Initializes the mutex system. sl@0: No-op function. sl@0: sl@0: @return SQLITE_OK sl@0: */ sl@0: int TMutexApi::Init() sl@0: { sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: /** sl@0: Finalizes the mutex system. sl@0: No-op function. sl@0: sl@0: @return SQLITE_OK sl@0: */ sl@0: int TMutexApi::End() sl@0: { sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: /** sl@0: Creates a new mutex. sl@0: If the request is for a static mutex, a pointer to already created static mutex will be returned. sl@0: sl@0: @param aType The mutex type: static, fast, recursive sl@0: @return A pointer to the created mutex or NULL if the operation has failed sl@0: */ sl@0: sqlite3_mutex* TMutexApi::Alloc(int aType) sl@0: { sl@0: sqlite3_mutex* mutex = NULL; sl@0: switch(aType) sl@0: { sl@0: case SQLITE_MUTEX_FAST: sl@0: case SQLITE_MUTEX_RECURSIVE: sl@0: mutex = CRecursiveMutex::New(); sl@0: break; sl@0: default: sl@0: mutex = ::StaticMutex(aType - 2);//"aType - 2" because the first SQLITE_MUTEX_STATIC_ mutex definition sl@0: //value is 2 (SQLITE_MUTEX_FAST is 0, SQLITE_MUTEX_RECURSIVE is 1). sl@0: break; sl@0: } sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TMUTEXAPI_ALLOC, "OS;0;TMutexApi::Alloc;aType=%d;mutex=0x%X", aType, (TUint)mutex)); sl@0: return mutex; sl@0: } sl@0: sl@0: /** sl@0: Destroys a mutex, created previously by a call to TMutexApi::Alloc(). sl@0: @param aMutex Pointer to the mutex object that has to be destroyed sl@0: */ sl@0: void TMutexApi::Free(sqlite3_mutex* aMutex) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TMUTEXAPI_FREE, "OS;0;TMutexApi::Free;mutex=0x%X", (TUint)aMutex)); sl@0: delete aMutex; sl@0: } sl@0: sl@0: /** sl@0: Locks the mutex. sl@0: See sqlite3_mutex::Enter() for more details. sl@0: sl@0: @param aMutex Pointer to the mutex object sl@0: sl@0: @see sqlite3_mutex::Enter() sl@0: */ sl@0: void TMutexApi::Enter(sqlite3_mutex* aMutex) sl@0: { sl@0: aMutex->Enter(); sl@0: } sl@0: sl@0: /** sl@0: No-op. Always returns SQLITE_BUSY. sl@0: sl@0: @return SQLITE_BUSY sl@0: */ sl@0: int TMutexApi::Try(sqlite3_mutex*) sl@0: { sl@0: return SQLITE_BUSY; sl@0: } sl@0: sl@0: /** sl@0: Unlocks the mutex. sl@0: See sqlite3_mutex::Leave() for more details. sl@0: sl@0: @param aMutex Pointer to the mutex object sl@0: sl@0: @see sqlite3_mutex::Leave() sl@0: */ sl@0: void TMutexApi::Leave(sqlite3_mutex* aMutex) sl@0: { sl@0: aMutex->Leave(); sl@0: } sl@0: sl@0: /** sl@0: Checks whether the mutex is locked or not. sl@0: See sqlite3_mutex::IsHeld() for more details. sl@0: sl@0: @param aMutex Pointer to the mutex object sl@0: sl@0: @return True if the mutex is locked, false otherwise sl@0: sl@0: @see sqlite3_mutex::IsHeld() sl@0: */ sl@0: int TMutexApi::Held(sqlite3_mutex* aMutex) sl@0: { sl@0: return aMutex->IsHeld(); sl@0: } sl@0: sl@0: /** sl@0: Checks whether the mutex is locked or not. sl@0: See sqlite3_mutex::IsHeld() for more details. sl@0: sl@0: @param aMutex Pointer to the mutex object sl@0: sl@0: @return False if the mutex is locked, true otherwise sl@0: sl@0: @see sqlite3_mutex::IsHeld() sl@0: */ sl@0: int TMutexApi::Notheld(sqlite3_mutex* aMutex) sl@0: { sl@0: return !aMutex->IsHeld(); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////// SQLite init/release functions /////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Initializes the OS porting layer global data. sl@0: */ sl@0: extern "C" SQLITE_EXPORT int sqlite3_os_init(void) sl@0: { sl@0: TInt err = sqlite3_vfs_register(VfsApi(), 1); sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, SQLITE3_OS_INIT, "OS;0;sqlite3_os_init;err=%d", err)); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Destroys the OS porting layer global data. sl@0: */ sl@0: extern "C" SQLITE_EXPORT int sqlite3_os_end(void) sl@0: { sl@0: TInt err = sqlite3_vfs_unregister(VfsApi()); sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, SQLITE3_OS_END, "OS;0;sqlite3_os_end;err=%d", err)); sl@0: return err; sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ////////////////////////// TheFileIoApi ///////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Single sqlite3_io_methods instance, which data members (function pointers) are initialized with the addresses of sl@0: TFileIo members. sl@0: TheFileIoApi is used by SQLite for performing OS independent file I/O. sl@0: sl@0: @see TFileIo sl@0: @see TVfs sl@0: sl@0: @internalComponent sl@0: */ sl@0: const static sqlite3_io_methods TheFileIoApi = sl@0: { sl@0: 1, //Version sl@0: &TFileIo::Close, sl@0: &TFileIo::Read, sl@0: &TFileIo::Write, sl@0: &TFileIo::Truncate, sl@0: &TFileIo::Sync, sl@0: &TFileIo::FileSize, sl@0: &TFileIo::Lock, sl@0: &TFileIo::Unlock, sl@0: &TFileIo::CheckReservedLock, sl@0: &TFileIo::FileControl, sl@0: &TFileIo::SectorSize, sl@0: &TFileIo::DeviceCharacteristics sl@0: }; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ////////////////////////// TheMutexMethods ////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: sqlite3_mutex_methods is a structure declared in sqlite3.h header file. sl@0: sqlite3_mutex_methods defines the mutex interface used by SQLite and implemented by the OS porting layer. sl@0: */ sl@0: static sqlite3_mutex_methods TheMutexMethods = sl@0: { sl@0: &TMutexApi::Init, sl@0: &TMutexApi::End, sl@0: &TMutexApi::Alloc, sl@0: &TMutexApi::Free, sl@0: &TMutexApi::Enter, sl@0: &TMutexApi::Try, sl@0: &TMutexApi::Leave, sl@0: &TMutexApi::Held, sl@0: &TMutexApi::Notheld sl@0: }; sl@0: sl@0: extern "C" sqlite3_mutex_methods* sqlite3DefaultMutex(void) sl@0: { sl@0: return &TheMutexMethods; sl@0: }; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ////////////////// UTF16<-->UTF8, conversion functions //////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: The function converts aFileName to UTF16 encoded file name, and stores the UTF16 encoded file name sl@0: to the place pointed by aFileNameDestBuf argument. sl@0: If the UTF16 conversion of the file name failed because the file name is too long or NULL, sl@0: the function returns EFalse. sl@0: sl@0: @param aFileName Expected to point to UTF8 encoded, zero terminated string. sl@0: Max allowed aFileName length is KMaxFileName (excluding terminating 0 character). sl@0: @param aFileNameDestBuf Output parameter. Will hold UTF16, non-zero-terminated string. sl@0: The max length must be at least KMaxFileName characters. sl@0: sl@0: @return True if the conversion has been completed successfully sl@0: */ sl@0: static TBool ConvertToUnicode(const char *aFileName, TDes& aFileNameDestBuf) sl@0: { sl@0: if(aFileName) sl@0: { sl@0: wchar_t* dest = reinterpret_cast (const_cast (aFileNameDestBuf.Ptr())); sl@0: TInt len = mbstowcs(dest, aFileName, KMaxFileName); sl@0: //Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid. sl@0: if(len > 0 && len <= KMaxFileName) sl@0: { sl@0: aFileNameDestBuf.SetLength(len); sl@0: return ETrue; sl@0: } sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: /** sl@0: The function converts aFileName to UTF8 encoded file name, and stores the UTF8 encoded file name sl@0: to the place pointed by aFileNameDestBuf argument. sl@0: If the UTF8 conversion of the file name failed because the file name is too long or NULL, sl@0: the function returns EFalse. sl@0: sl@0: @param aFileName Expected to point to UTF16 encoded, zero terminated string. sl@0: Max allowed aFileName length is KMaxFileName (excluding terminating 0 character). sl@0: @param aFileNameDestBuf Output parameter. Will hold UTF8, non-zero-terminated string. sl@0: The max length must be at least KMaxFileName characters. sl@0: sl@0: @return True if the conversion has been completed successfully sl@0: */ sl@0: static TBool ConvertFromUnicode(const TDesC& aFileName, TDes8& aFileNameDestBuf) sl@0: { sl@0: char* dest = reinterpret_cast (const_cast (aFileNameDestBuf.Ptr())); sl@0: const wchar_t* src = reinterpret_cast (aFileName.Ptr()); sl@0: TInt len = wcstombs(dest, src, KMaxFileName); sl@0: //Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid. sl@0: if(len > 0 && len <= KMaxFileName) sl@0: { sl@0: aFileNameDestBuf.SetLength(len); sl@0: return ETrue; sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////// TDbFile class definition /////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: const TInt KFileBufSize = 8 * 1024; sl@0: sl@0: /** sl@0: Initializes TDbFile data members with their default values. sl@0: */ sl@0: inline TDbFile::TDbFile() : sl@0: iFileBuf(KFileBufSize), sl@0: iFullName(NULL), sl@0: iSharedLockByte(0), sl@0: iLockType(SQLITE_LOCK_NONE), sl@0: iReadOnly(EFalse), sl@0: iSectorSize(0), sl@0: iDeviceCharacteristics(-1) sl@0: { sl@0: pMethods = 0; sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TDBFILE_TDBFILE, "OS;0x%X;TDbFile::TDbFile", (TUint)this)); sl@0: } sl@0: sl@0: /** sl@0: Casts the passed sqlite3_file pointer to a reference to the derived class - TDbFile&. sl@0: All sqlite3_file pointers passed to TFileIo methods are actually pointers to TDbFile instances. sl@0: So the cast is safe. sl@0: sl@0: @param aDbFile A pointer to a sqlite3_file instance sl@0: sl@0: @return A TDbFile reference. sl@0: @see TFileIo sl@0: @see TVfs sl@0: @see TDbFile sl@0: sl@0: @panic Sqlite 20 In _DEBUG mode if aDbFile is NULL. sl@0: sl@0: @internalComponent sl@0: */ sl@0: static inline TDbFile& DbFile(sqlite3_file* aDbFile) sl@0: { sl@0: __ASSERT_DEBUG(aDbFile != 0, __SQLITEPANIC2(ESqliteOsPanicNullDbFilePtr)); sl@0: return *(static_cast (aDbFile)); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////// TFileIo class definition /////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Closes the file referred by aDbFile parameter. sl@0: If aDbFile.iFullName data member is not NULL, then the file will be deleted. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, than contains the file handle to be closed. sl@0: sl@0: @return SQLITE_OK sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::Close(sqlite3_file* aDbFile) sl@0: { sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TFILEIO_CLOSE1, "OS;0x%X;TFileIo::Close", (TUint)&dbFile)); sl@0: dbFile.iFileBuf.Close(); sl@0: if(dbFile.iFullName) sl@0: {//"iFullName" will not be NULL only when TVfs::Open() is called with SQLITE_OPEN_DELETEONCLOSE flag. sl@0: //That means - SQlite expects the file to be deleted after the file close operation. sl@0: __SQLITETRACE_OSEXPR(TInt err = ) TStaticFs::Fs().Delete(*dbFile.iFullName); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_CLOSE2, "OS;0x%X;TFileIo::Close;delete fileName=%S;err=%d", (TUint)&dbFile, __SQLITEPRNSTR(*dbFile.iFullName), err)); sl@0: delete dbFile.iFullName; sl@0: dbFile.iFullName = NULL; sl@0: } sl@0: OpenCounter(-1); sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Reads from the file referred by the aDbFile parameter. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle to be read from. sl@0: @param aBuf Output parameter. The data read from the file will be copied there. sl@0: The buffer size must be at least aAmt bytes. sl@0: @param aAmt The amount of data to be read form the file. sl@0: @param aOffset The offset in the file where the read operation should start. sl@0: sl@0: @return SQLITE_FULL, The disk is full, sl@0: SQLITE_IOERR_SHORT_READ, The amount of the data read is less than aAmt, sl@0: SQLITE_IOERR_READ, File read error, sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured, sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::Read(sqlite3_file* aDbFile, void* aBuf, int aAmt, sqlite3_int64 aOffset) sl@0: { sl@0: SimulateIOError(return SQLITE_IOERR_READ); sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_READ_ENTRY, "OS-Entry;0x%X;TFileIo::Read;aAmt=%d;aOffset=%lld", (TUint)&dbFile, aAmt, aOffset)); sl@0: TPtr8 ptr((TUint8*)aBuf, 0, aAmt); sl@0: TInt err = dbFile.iFileBuf.Read(aOffset, ptr); sl@0: TInt cnt = ptr.Length(); sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_READ); sl@0: if(cnt != aAmt && (sqliteErr == SQLITE_OK || sqliteErr == SQLITE_IOERR_SHORT_READ)) sl@0: { sl@0: Mem::FillZ(static_cast (aBuf) + cnt, aAmt - cnt); sl@0: sqliteErr = SQLITE_IOERR_SHORT_READ; sl@0: } sl@0: SQLITE_TRACE_OS(OstTraceExt4(TRACE_INTERNALS, TFILEIO_READ_EXIT, "OS-Exit;0x%X;TFileIo::Read;cnt=%d;err=%d;sqliteErr=%d", (TUint)&dbFile, cnt, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Writes to the file referred by the aDbFile parameter. sl@0: "Write beyond the end of the file" operations are allowed. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle to be written to. sl@0: @param aData The data to be written to the file. The buffer size must be at least aAmt bytes. sl@0: @param aAmt The amount of data to be written to the file. sl@0: @param aOffset The offset in the file where the write operation should start. sl@0: sl@0: @return SQLITE_IOERR_WRITE, the file write operation has failed or the file is read-only, sl@0: SQLITE_FULL, The disk is full, sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured, sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::Write(sqlite3_file* aDbFile, const void* aData, int aAmt, sqlite3_int64 aOffset) sl@0: { sl@0: SimulateIOError(return SQLITE_IOERR_WRITE); sl@0: SimulateDiskfullError(return SQLITE_FULL); sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_WRITE_ENTRY, "OS-Entry;0x%X;TFileIo::Write;aAmt=%d;aOffset=%lld", (TUint)&dbFile, aAmt, aOffset)); sl@0: TInt err = KErrAccessDenied; sl@0: if(!dbFile.iReadOnly) sl@0: { sl@0: TPtrC8 ptr((const TUint8*)aData, aAmt); sl@0: err = dbFile.iFileBuf.Write(aOffset, ptr); sl@0: } sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_WRITE); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_WRITE_EXIT, "OS-Exit;0x%X;TFileIo::Write;err=%d;sqliteErr=%d", (TUint)&dbFile, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Truncates the file referred by the aDbFile parameter. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aLength The new file size in bytes. sl@0: sl@0: @return SQLITE_IOERR_TRUNCATE, the file truncate operation has failed or the file is read-only, sl@0: SQLITE_FULL, The disk is full, sl@0: The file truncate operation has failed, sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured, sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::Truncate(sqlite3_file* aDbFile, sqlite3_int64 aLength) sl@0: { sl@0: SimulateIOError(return SQLITE_IOERR_TRUNCATE); sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_TRUNCATE_ENTRY, "OS-Entry;0x%X;TFileIo::Truncate;aLength=%lld", (TUint)&dbFile, aLength)); sl@0: TInt err = KErrAccessDenied; sl@0: if(!dbFile.iReadOnly) sl@0: { sl@0: err = dbFile.iFileBuf.SetSize(aLength); sl@0: } sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_TRUNCATE); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_TRUNCATE_EXIT, "OS-Exit;0x%X;TFileIo::Truncate;err=%d;sqliteErr=%d", (TUint)&dbFile, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Flushes the file referred by the aDbFile parameter. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aFlags This parameter is not used in the production builds. It may be one of sl@0: SQLITE_SYNC_NORMAL or SQLITE_SYNC_FULL and is used only by the TCL test suite. sl@0: sl@0: @return SQLITE_IOERR_FSYNC, This is a read-only file, or the file flush operation has failed, sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured, sl@0: SQLITE_FULL, The disk is full, sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */int TFileIo::Sync(sqlite3_file* aDbFile, int aFlags) sl@0: { sl@0: SimulateIOError(return SQLITE_IOERR_FSYNC); sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TFILEIO_SYNC_ENTRY, "OS-Entry;0x%X;TFileIo::Sync", (TUint)&dbFile)); sl@0: #ifdef SQLITE_TEST sl@0: if(aFlags & SQLITE_SYNC_FULL) sl@0: { sl@0: sqlite3_fullsync_count++; sl@0: } sl@0: sqlite3_sync_count++; sl@0: #else sl@0: aFlags = aFlags; sl@0: #endif sl@0: TInt err = KErrAccessDenied; sl@0: if(!dbFile.iReadOnly) sl@0: { sl@0: err = dbFile.iFileBuf.Flush(); sl@0: } sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_FSYNC); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_SYNC_EXIT, "OS-Exit;0x%X;TFileIo::Sync;err=%d;sqliteErr=%d", (TUint)&dbFile, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Returns the size of the file referred by the aDbFile parameter. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aSize Output parameter. If the function completes successfully, the file size will be stored there. sl@0: sl@0: @return SQLITE_IOERR_FSTAT, The file size operation has failed; sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured; sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::FileSize(sqlite3_file* aDbFile, sqlite3_int64* aSize) sl@0: { sl@0: SimulateIOError(return SQLITE_IOERR_FSTAT); sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TFILEIO_FILESIZE_ENTRY, "OS-Entry;0x%X;TFileIo::FileSize", (TUint)&dbFile)); sl@0: TInt err = dbFile.iFileBuf.Size(*aSize); sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_FSTAT); sl@0: SQLITE_TRACE_OS(OstTraceExt4(TRACE_INTERNALS, TFILEIO_FILESIZE_EXIT, "OS-Exit;0x%X;TFileIo::FileSize;aSize=%lld;err=%d;sqliteErr=%d", (TUint)&dbFile, *aSize, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: This function is called when SQLite needs to obtain a read lock. This is done by generating a sl@0: random file position within the first page beyond the first Gb of the file and locking a single byte there. sl@0: There is a possible problem with that random file position, because the database file may be shared between multiple sl@0: connections. That increases the possibility of generating the same "random" file position by different connections to the sl@0: same file. In order to minimise that, TFileIo::GetReadLock() will generate up to 3 different file positions in a case of sl@0: a "lock byte" failure. sl@0: The generated file position will be stored in TDbFile::iSharedLockByte data member and will be used later for the sl@0: unlock operation. sl@0: sl@0: @param aDbFile The Os porting layer file handle sl@0: @return KErrNone The locking operation has completed successfully, sl@0: KErrLocked The 1 byte file area that begins from the generated file position is already locked, sl@0: Some other system-wide error codes in a case of failure. sl@0: sl@0: @see TFileIo::UnlockReadLock() sl@0: */ sl@0: /* static */TInt TFileIo::GetReadLock(TDbFile& aDbFile) sl@0: { sl@0: const TInt KLockTryCount = 3; sl@0: TInt rc = KErrLocked; sl@0: for(TInt i=0;i SQLITE_LOCK_SHARED sl@0: SQLITE_LOCK_SHARED -> SQLITE_LOCK_RESERVED sl@0: SQLITE_LOCK_SHARED -> (SQLITE_LOCK_PENDING) -> SQLITE_LOCK_EXCLUSIVE sl@0: SQLITE_LOCK_RESERVED -> (SQLITE_LOCK_PENDING) -> SQLITE_LOCK_EXCLUSIVE sl@0: SQLITE_LOCK_PENDING -> SQLITE_LOCK_EXCLUSIVE sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aLockType Lock type: SQLITE_LOCK_NONE, SQLITE_LOCK_SHARED, SQLITE_LOCK_RESERVED, SQLITE_LOCK_PENDING or sl@0: SQLITE_LOCK_EXCLUSIVE. sl@0: sl@0: @return SQLITE_IOERR_NOMEM, An out of memory condition has occured; sl@0: SQLITE_BUSY, The requested lock cannot be obtained; sl@0: SQLITE_LOCK, File locking error, sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TFileIo::CheckReservedLock() sl@0: @see TFileIo::Unlock() sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::Lock(sqlite3_file* aDbFile, int aLockType) sl@0: { sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: //If there is already a lock of this type or more restrictive on the aDbFile, then - do nothing. sl@0: if(dbFile.iLockType >= aLockType) sl@0: { sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_LOCK1, "OS;0x%X;TFileIo::Lock;dbFile.iLockType=%d;aLockType=%d", (TUint)&dbFile, dbFile.iLockType, aLockType)); sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: //The file flushing here must be done in order to get the file buffer object content (iFileBuf data member)) sl@0: //synchronised with the database file content (the database file content may get modified by a different connection sl@0: //at the same time). sl@0: if(aLockType == SQLITE_LOCK_SHARED && !dbFile.iReadOnly) sl@0: { sl@0: TInt err = dbFile.iFileBuf.Flush(ETrue); sl@0: if(err != KErrNone) sl@0: { sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_LOCK2, "OS;0x%X;TFileIo::Lock;iFileBuf.Flush() failed, err=%d", (TUint)&dbFile, err)); sl@0: return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); sl@0: } sl@0: } sl@0: sl@0: //Make sure the locking sequence is correct sl@0: __ASSERT_DEBUG(dbFile.iLockType != SQLITE_LOCK_NONE || aLockType == SQLITE_LOCK_SHARED, __SQLITEPANIC2(ESqliteOsPanicInvalidLock)); sl@0: __ASSERT_DEBUG(aLockType != SQLITE_LOCK_PENDING, __SQLITEPANIC2(ESqliteOsPanicInvalidLock)); sl@0: __ASSERT_DEBUG(aLockType != SQLITE_LOCK_RESERVED || dbFile.iLockType == SQLITE_LOCK_SHARED, __SQLITEPANIC2(ESqliteOsPanicInvalidLock)); sl@0: sl@0: TInt rc = SQLITE_OK; //Return code from subroutines sl@0: TBool locked = ETrue; //Result of a file lock call (the default value means: "lock accuired") sl@0: TInt newLockType = -1; //Set dbFile.iLockType to this value before exiting sl@0: TBool gotPendingLock = EFalse;//True if we acquired a SQLITE_LOCK_PENDING lock this time sl@0: sl@0: //Lock the SQLITE_LOCK_PENDING byte if we need to acquire a SQLITE_LOCK_PENDING lock or sl@0: //SQLITE_LOCK_SHARED lock. If we are acquiring a SQLITE_LOCK_SHARED lock, the acquisition of sl@0: //the SQLITE_LOCK_PENDING byte is temporary. sl@0: newLockType = dbFile.iLockType; sl@0: if(dbFile.iLockType == SQLITE_LOCK_NONE || (aLockType == SQLITE_LOCK_EXCLUSIVE && dbFile.iLockType == SQLITE_LOCK_RESERVED)) sl@0: { sl@0: //Try 3 times to get the pending lock. The pending lock might be sl@0: //held by another reader process who will release it momentarily. sl@0: const TInt KLockTryCnt = 3; sl@0: locked = EFalse; sl@0: for(TInt i=0;i= SQLITE_LOCK_SHARED, __SQLITEPANIC2(ESqliteOsPanicInvalidLock)); sl@0: (void)TFileIo::UnlockReadLock(dbFile); sl@0: TInt err = dbFile.iFileBuf.Lock(SHARED_FIRST, SHARED_SIZE); sl@0: if(err != KErrNone && err != KErrLocked) sl@0: { sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_LOCK5, "OS;0x%X;TFileIo::Lock;iFileBuf.Lock()-2 failed, err=%d", (TUint)&dbFile, err)); sl@0: return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); sl@0: } sl@0: locked = (err == KErrNone); sl@0: if(locked) sl@0: { sl@0: newLockType = SQLITE_LOCK_EXCLUSIVE; sl@0: } sl@0: } sl@0: sl@0: // If we are holding a PENDING lock that ought to be released, then sl@0: // release it now. sl@0: if(gotPendingLock && aLockType == SQLITE_LOCK_SHARED) sl@0: { sl@0: __SQLITETRACE_OSEXPR(TInt err =) dbFile.iFileBuf.UnLock(PENDING_BYTE, 1); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_LOCK6, "OS;0x%X;TFileIo::Lock;iFileBuf.UnLock()=%d", (TUint)&dbFile, err)); sl@0: } sl@0: sl@0: // Update the state of the lock has held in the file descriptor then sl@0: // return the appropriate result code. sl@0: rc = locked ? SQLITE_OK : SQLITE_BUSY; sl@0: dbFile.iLockType = newLockType; sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_LOCK7, "OS;0x%X;TFileIo::Lock;rc=%d;newLockType=%d", (TUint)&dbFile, rc, newLockType)); sl@0: return rc; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Lower the locking level on file descriptor id to locktype. locktype sl@0: must be either SQLITE_LOCK_NONE or SQLITE_LOCK_SHARED. sl@0: sl@0: If the locking level of the file descriptor is already at or below sl@0: the requested locking level, this routine is a no-op. sl@0: sl@0: It is not possible for this routine to fail if the second argument sl@0: is SQLITE_LOCK_NONE. If the second argument is SQLITE_LOCK_SHARED then this routine sl@0: might return SQLITE_IOERR; sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aLockType Lock type: SQLITE_LOCK_NONE, SQLITE_LOCK_SHARED, SQLITE_LOCK_RESERVED, SQLITE_LOCK_PENDING or sl@0: SQLITE_LOCK_EXCLUSIVE. sl@0: sl@0: @return SQLITE_OK, The operation has completed successfully, sl@0: SQLITE_IOERR_UNLOCK, The unlock operation has failed. sl@0: sl@0: @see TFileIo::CheckReservedLock() sl@0: @see TFileIo::Lock() sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::Unlock(sqlite3_file* aDbFile, int aLockType) sl@0: { sl@0: __ASSERT_DEBUG(aLockType <= SQLITE_LOCK_SHARED, __SQLITEPANIC2(ESqliteOsPanicInvalidLock)); sl@0: sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: TInt rc = SQLITE_OK; sl@0: TInt currLockType = dbFile.iLockType; sl@0: sl@0: if(currLockType >= SQLITE_LOCK_EXCLUSIVE) sl@0: { sl@0: __SQLITETRACE_OSEXPR(TInt err2 =) dbFile.iFileBuf.UnLock(SHARED_FIRST, SHARED_SIZE); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_UNLOCK1, "OS;0x%X;TFileIo::Unlock;iFileBuf.UnLock()=%d", (TUint)&dbFile, err2)); sl@0: if(aLockType == SQLITE_LOCK_SHARED) sl@0: { sl@0: TInt err = TFileIo::GetReadLock(dbFile); sl@0: if(err != KErrNone && err != KErrLocked) sl@0: { sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_UNLOCK2, "OS;0x%X;TFileIo::Unlock;TFileIo::GetReadLock() failed, err=%d", (TUint)&dbFile, err)); sl@0: return ::Os2SqliteErr(err, SQLITE_IOERR_UNLOCK); sl@0: } sl@0: if(err == KErrLocked) sl@0: { sl@0: //This should never happen. We should always be able to reacquire the read lock sl@0: rc = SQLITE_IOERR_UNLOCK; sl@0: } sl@0: } sl@0: } sl@0: if(currLockType >= SQLITE_LOCK_RESERVED) sl@0: { sl@0: __SQLITETRACE_OSEXPR(TInt err2 =) dbFile.iFileBuf.UnLock(RESERVED_BYTE, 1); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_UNLOCK3, "OS;0x%X;TFileIo::Unlock;iFileBuf.UnLock()-2=%d", (TUint)&dbFile, err2)); sl@0: } sl@0: if(aLockType == SQLITE_LOCK_NONE && currLockType >= SQLITE_LOCK_SHARED) sl@0: { sl@0: __SQLITETRACE_OSEXPR(TInt err2 =) TFileIo::UnlockReadLock(dbFile); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_UNLOCK4, "OS;0x%X;TFileIo::Unlock;TFileIo::UnlockReadLock()=%d", (TUint)&dbFile, err2)); sl@0: } sl@0: if(currLockType>= SQLITE_LOCK_PENDING) sl@0: { sl@0: __SQLITETRACE_OSEXPR(TInt err2 =) dbFile.iFileBuf.UnLock(PENDING_BYTE, 1); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_UNLOCK5, "OS;0x%X;TFileIo::Unlock;iFileBuf.UnLock()-3=%d", (TUint)&dbFile, err2)); sl@0: } sl@0: sl@0: dbFile.iLockType = aLockType; sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_UNLOCK6, "OS;0x%X;TFileIo::Unlock;rc=%d;newLockType=%d", (TUint)&dbFile, rc, aLockType)); sl@0: return rc; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Checks if the file lock type is SQLITE_LOCK_RESERVED or bigger. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aResOut Output parameter. It will be set to be non-zero if the stored lock type is bigger or equal sl@0: than SQLITE_LOCK_RESERVED. sl@0: sl@0: @return SQLITE_IOERR_CHECKRESERVEDLOCK, The operation has failed, sl@0: SQLITE_OK The operation has completed successfully. sl@0: sl@0: @see TFileIo::Lock() sl@0: @see TFileIo::Unlock() sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::CheckReservedLock(sqlite3_file* aDbFile, int *aResOut) sl@0: { sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: TInt rc; sl@0: if(dbFile.iLockType >= SQLITE_LOCK_RESERVED) sl@0: { sl@0: rc = 1; sl@0: } sl@0: else sl@0: { sl@0: TInt err = dbFile.iFileBuf.Lock(RESERVED_BYTE, 1); sl@0: if(err != KErrNone && err != KErrLocked) sl@0: { sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_CHECKRESERVEDLOCK1, "OS;0x%X;TFileIo::CheckReservedLock;iFileBuf.Lock(), err=%d", (TUint)&dbFile, err)); sl@0: return ::Os2SqliteErr(err, SQLITE_IOERR_CHECKRESERVEDLOCK); sl@0: } sl@0: rc = (err == KErrNone); sl@0: if(rc) //non-zero rc means: the lock has been successful (there wasn't a reserved lock on this file) sl@0: { sl@0: __SQLITETRACE_OSEXPR(TInt err2 =) dbFile.iFileBuf.UnLock(RESERVED_BYTE, 1); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_CHECKRESERVEDLOCK2, "OS;0x%X;TFileIo::CheckReservedLock;iFileBuf.UnLock()=%d", (TUint)&dbFile, err2)); sl@0: } sl@0: rc = !rc; sl@0: } sl@0: *aResOut = rc; sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TFILEIO_CHECKRESERVEDLOCK3, "OS;0x%X;TFileIo::CheckReservedLock;rc=%d", (TUint)&dbFile, rc)); sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Performs an aOp operation on the file referred by the aDbFile parameter. sl@0: Since the only supported operation at the moment is SQLITE_FCNTL_LOCKSTATE, and the current lock type is stored as sl@0: a data memebr of TDbFile, the function implementation has been optimised - no file I/O calls. The stored file lock type sl@0: is retured if the operation is SQLITE_FCNTL_LOCKSTATE. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aOp File operation type. Currently only SQLITE_FCNTL_LOCKSTATE is supported. sl@0: @param aArg An additional input/output parameter which purpose depends on the type of the current file operation. sl@0: If the file operation is SQLITE_FCNTL_LOCKSTATE, then aArg is used as an output parameter, where sl@0: the file lock type is stored. sl@0: sl@0: @return SQLITE_ERROR, Non-supported operation, sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TFileIo::FileControl(sqlite3_file* aDbFile, int aOp, void* aArg) sl@0: { sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: TInt err = KErrNone; sl@0: switch(aOp) sl@0: { sl@0: case SQLITE_FCNTL_LOCKSTATE: sl@0: *(int*)aArg = dbFile.iLockType; sl@0: break; sl@0: default: sl@0: err = KErrArgument; sl@0: break; sl@0: } sl@0: TInt sqliteErr = err == KErrNone ? SQLITE_OK : SQLITE_ERROR; sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TFILEIO_FILECONTROL, "OS;0x%X;TFileIo::FileControl;err=%d;sqliteErr=%d", (TUint)&dbFile, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Retrieves the sector size of the media of the file referred by the aDbFile parameter. sl@0: Since the sector size never changes till the file is open, the function has been optimised - no file I/O calls. sl@0: The sector size is retrieved during the TVfs::Open() call and stored in TDbFile::iSectorSize. The SectorSize() sl@0: call returns the value of TDbFile::iSectorSize. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: sl@0: @return The sector size. sl@0: sl@0: @panic Sqlite 19 In _DEBUG mode - TDbFile::iSectorSize is negative or 0 . sl@0: sl@0: @see TDbFile sl@0: @see TVfs::Open() sl@0: */ sl@0: /* static */ int TFileIo::SectorSize(sqlite3_file* aDbFile) sl@0: { sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: __ASSERT_DEBUG(dbFile.iSectorSize > 0, __SQLITEPANIC2(ESqliteOsPanicInternalError)); sl@0: if(dbFile.iSectorSize > 0) sl@0: { sl@0: return dbFile.iSectorSize; sl@0: } sl@0: return SQLITE_DEFAULT_SECTOR_SIZE; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Retrieves the device characteristics of the device of the file referred by the aDbFile parameter. sl@0: Since the device characteristics never change till the file is open, the function has been optimised - no file I/O calls. sl@0: The device characteristics are retrieved during the TVfs::Open() call and stored in TDbFile::iDeviceCharacteristics. sl@0: The DeviceCharacteristics() call returns the value of TDbFile::iDeviceCharacteristics. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: sl@0: @return A bit set containing the device characteristics. sl@0: sl@0: @panic Sqlite 19 In _DEBUG mode - TDbFile::iDeviceCharacteristics is negative or 0 . sl@0: sl@0: @see TDbFile sl@0: @see TVfs::Open() sl@0: */ sl@0: /* static */ int TFileIo::DeviceCharacteristics(sqlite3_file* aDbFile) sl@0: { sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: __ASSERT_DEBUG(dbFile.iDeviceCharacteristics >= 0, __SQLITEPANIC2(ESqliteOsPanicInternalError)); sl@0: if(dbFile.iDeviceCharacteristics >= 0) sl@0: { sl@0: return dbFile.iDeviceCharacteristics; sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////// TVfs class definition /////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Collects information about the drive referred by the aDriveNo parameter. sl@0: sl@0: @param aFs RFs instance. sl@0: @param aDriveNo The drive about which an information will be collected. sl@0: @param aVolumeInfo Output parameter. A reference to a TVolumeIOParamInfo object where the collected information will be stored. sl@0: sl@0: @return KErrNone, The operation has completed succesfully; sl@0: KErrNoMemory, Out of memory condition has occured; sl@0: Note that other system-wide error codes may also be returned. sl@0: sl@0: @see TVfs::Open() sl@0: */ sl@0: /* static */ inline TInt TVfs::DoGetVolumeIoParamInfo(RFs& aFs, TInt aDriveNo, TVolumeIOParamInfo& aVolumeInfo) sl@0: { sl@0: TInt err = aFs.VolumeIOParam(aDriveNo, aVolumeInfo); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TVFS_DOGETVOLUMEIOPARAMINFO, "OS;0;TVfs::DoGetVolumeIoParamInfo;aDriveNo=%d;err=%d", aDriveNo, err)); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Retrieves and returns in a bit set the device characteristics. sl@0: sl@0: @param aDriveInfo A TDriveInfo reference from which the device characteristics will be extracted. sl@0: @param aVolumeInfo A TVolumeIOParamInfo reference from which the device characteristics will be extracted. sl@0: sl@0: @return A bit set containing the device characteristics: sl@0: SQLITE_IOCAP_SAFE_APPEND, SQLITE_IOCAP_ATOMIC, the atomic block size. sl@0: sl@0: @see TVfs::DoGetDriveInfo(); sl@0: @see TVfs::DoGetVolumeIoParamInfo(); sl@0: @see TVfs::Open() sl@0: */ sl@0: /* static */ TInt TVfs::DoGetDeviceCharacteristics(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo) sl@0: { sl@0: TInt deviceCharacteristics = 0; sl@0: if(aDriveInfo.iDriveAtt & (KDriveAttLocal | KDriveAttInternal)) sl@0: { sl@0: deviceCharacteristics |= SQLITE_IOCAP_SAFE_APPEND;//Data written first, file size updated second sl@0: } sl@0: if(aDriveInfo.iDriveAtt & KDriveAttTransaction) sl@0: { sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC; sl@0: } sl@0: if(aVolumeInfo.iBlockSize >= SQLITE_DEFAULT_SECTOR_SIZE && (aVolumeInfo.iBlockSize & (aVolumeInfo.iBlockSize - 1)) == 0) sl@0: { sl@0: switch(aVolumeInfo.iBlockSize) sl@0: { sl@0: case 512: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC512; sl@0: break; sl@0: case 1024: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC1K; sl@0: break; sl@0: case 2048: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC2K; sl@0: break; sl@0: case 4096: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC4K; sl@0: break; sl@0: case 8192: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC8K; sl@0: break; sl@0: case 16384: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC16K; sl@0: break; sl@0: case 32768: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC32K; sl@0: break; sl@0: case 65536: sl@0: deviceCharacteristics |= SQLITE_IOCAP_ATOMIC64K; sl@0: break; sl@0: default: sl@0: //Do nothing. deviceCharacteristics was initialized with 0 at the beginning of the function body. sl@0: break; sl@0: } sl@0: } sl@0: return deviceCharacteristics; sl@0: } sl@0: sl@0: /** sl@0: Retrieves and returns the sector size of the drive referred by the aDriveInfo parameter. sl@0: The sector size must be a power of two. sl@0: The sector size is extracted only if aDriveInfo refers to a removable device, otherwise the sl@0: SQLITE_DEFAULT_SECTOR_SIZE value (512 bytes) will be used as a sector size. sl@0: sl@0: @param aDriveInfo A TDriveInfo reference. sl@0: @param aVolumeInfo A TVolumeIOParamInfo reference. sl@0: sl@0: @return The sector size of the drive referred by the aDriveInfo parameter. sl@0: sl@0: @panic Sqlite 19 In _DEBUG mode - The sector size is negative, zero or is not a power of two. sl@0: sl@0: @see TVfs::Open() sl@0: */ sl@0: /* static */ TInt TVfs::DoGetSectorSize(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo) sl@0: { sl@0: //Initialize the sectorSize variable only if: sl@0: // - aDriveInfo refers to a removable drive sl@0: // - aVolumeInfo.iBlockSize > SQLITE_DEFAULT_SECTOR_SIZE; sl@0: // - aVolumeInfo.iBlockSize is power of 2; sl@0: TInt sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; sl@0: if(aDriveInfo.iDriveAtt & KDriveAttRemovable) sl@0: { sl@0: if(aVolumeInfo.iBlockSize > SQLITE_DEFAULT_SECTOR_SIZE && (aVolumeInfo.iBlockSize & (aVolumeInfo.iBlockSize - 1)) == 0) sl@0: { sl@0: sectorSize = aVolumeInfo.iBlockSize; sl@0: } sl@0: } sl@0: __ASSERT_DEBUG(sectorSize > 0 && (sectorSize & (sectorSize - 1)) == 0, __SQLITEPANIC2(ESqliteOsPanicInternalError)); sl@0: return sectorSize; sl@0: } sl@0: sl@0: /** sl@0: Retrieves in a bit set the device characteristics of the device of the file referred by the aDbFile parameter. sl@0: Retrieves the sector size of the drive of the file referred by the aDbFile parameter. sl@0: The sector size and the device characteristics will be stored in iSectorSize and iDeviceCharacteristics TDbFile data members. sl@0: The stored values will be used later by TFileIo::DeviceCharacteristics() and TFileIo::SectorSize(). sl@0: sl@0: @param aDbFile Input/Output parameter. A TDriveInfo reference. The collected information will be stored in TDbDrive sl@0: data members. sl@0: @param aRecReadBufSize Output parameter. The recommended buffer size for optimised reading performance. sl@0: sl@0: @return KErrNone, The operation has completed succesfully; sl@0: Note that other system-wide error codes may also be returned. sl@0: sl@0: @panic Sqlite 19 In _DEBUG mode - TDbFile::iSectorSize has been already initialized. sl@0: @panic Sqlite 19 In _DEBUG mode - TDbFile::iDeviceCharacteristics has been already initialized. sl@0: sl@0: @see TVfs::DoGetDeviceCharacteristics(); sl@0: @see TVfs::DoGetSectorSize(); sl@0: @see TVfs::Open() sl@0: @see TDbFile sl@0: @see TFileIo::DeviceCharacteristics() sl@0: @see TFileIo::SectorSize() sl@0: */ sl@0: /* static */ TInt TVfs::DoGetDeviceCharacteristicsAndSectorSize(TDbFile& aDbFile, TInt& aRecReadBufSize) sl@0: { sl@0: __ASSERT_DEBUG(aDbFile.iDeviceCharacteristics < 0, __SQLITEPANIC2(ESqliteOsPanicInternalError)); sl@0: __ASSERT_DEBUG(aDbFile.iSectorSize <= 0, __SQLITEPANIC2(ESqliteOsPanicInternalError)); sl@0: TInt driveNo; sl@0: TDriveInfo driveInfo; sl@0: TInt err = aDbFile.iFileBuf.Drive(driveNo, driveInfo); sl@0: if(err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: TVolumeIOParamInfo volumeInfo; sl@0: err = TVfs::DoGetVolumeIoParamInfo(TStaticFs::Fs(), driveNo, volumeInfo); sl@0: if(err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: aDbFile.iDeviceCharacteristics = TVfs::DoGetDeviceCharacteristics(driveInfo, volumeInfo); sl@0: aDbFile.iSectorSize = TVfs::DoGetSectorSize(driveInfo, volumeInfo); sl@0: aRecReadBufSize = volumeInfo.iRecReadBufSize; sl@0: SQLITE_TRACE_OS(OstTraceExt5(TRACE_INTERNALS, TVFS_DOGETGETDEVICECHARACTERISTICSANDSECTORSIZE, "OS;0x%X;TVfs::DoGetDeviceCharacteristicsAndSectorSize;driveNo=%d;sectorSize=%d;devCharact=0x%X;readBufSize=%d", (TUint)&aDbFile, driveNo, aDbFile.iSectorSize, (TUint)aDbFile.iDeviceCharacteristics, volumeInfo.iRecReadBufSize)); sl@0: return KErrNone; sl@0: } sl@0: sl@0: //Creates a temporary file. The file location will be the application's session path. sl@0: //If the session path does not exist, then the function will create the session path. sl@0: static TInt CreateTempFile(TDbFile& aDbFile, TFileName& aFileNameOut, TInt aFileMode) sl@0: { sl@0: TFileName sessionPath; sl@0: TInt err = TStaticFs::Fs().SessionPath(sessionPath); sl@0: if(err == KErrNone) sl@0: { sl@0: err = aDbFile.iFileBuf.Temp(TStaticFs::Fs(), sessionPath, aFileNameOut, aFileMode); sl@0: if(err == KErrPathNotFound) sl@0: { sl@0: err = TStaticFs::Fs().MkDirAll(sessionPath); sl@0: if(err == KErrNone) sl@0: { sl@0: err = aDbFile.iFileBuf.Temp(TStaticFs::Fs(), sessionPath, aFileNameOut, aFileMode); sl@0: } sl@0: } sl@0: if(err == KErrNone) sl@0: { sl@0: aDbFile.iFullName = aFileNameOut.Alloc(); sl@0: if(!aDbFile.iFullName) sl@0: { sl@0: aDbFile.iFileBuf.Close(); sl@0: (void)TStaticFs::Fs().Delete(aFileNameOut); sl@0: err = KErrNoMemory; sl@0: } sl@0: } sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: The behaviour of the RFile/RFile64::SetSize operation is not atomic for non-rugged drives. sl@0: When RFile/RFile64::SetSize() is called 2 operations occurs:- sl@0: sl@0: 1)The cluster chain of the file is updated. sl@0: 2)The new file size is added to the file cache. sl@0: sl@0: If a power loss occurs after a SetSize there is a chance that the cluster chain was updated sl@0: but the new file size is not yet flushed to the file. This puts the file into an inconsistent state. sl@0: This is most likely to occur in the journal file where the time between a SetSize and Flush can sl@0: be long. sl@0: sl@0: For this reason this check is added when the file is opened to see if the end of the file can sl@0: be read straight away, if an error is returned then it is assumed that the SetSize has not be sl@0: completed previously. In this case the file is deleted and re-created. sl@0: sl@0: @param aDbFile A pointer to a TDbFile instance, that contains the file handle. sl@0: @param aFname A string of 16-bit wide characters containing name of the file to be checked. sl@0: @param aFmode The mode in which the file is opened. These mode are documented in TFileMode. sl@0: sl@0: @return KErrNone, The operation has completed succesfully; sl@0: Note that other system-wide error codes may also be returned. sl@0: @see TFileMode sl@0: @see TVfs::Open() sl@0: @see TDbFile sl@0: */ sl@0: /* static */ TInt TVfs::DoFileSizeCorruptionCheck(TDbFile& aDbFile, const TDesC& aFname, TInt aFmode) sl@0: { sl@0: const TInt KMinSize = 16; sl@0: TInt64 size; sl@0: TInt err = KErrNone ; sl@0: TBuf8 buf; sl@0: sl@0: err = aDbFile.iFileBuf.Size(size); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: TBool IsMinFileSize = (size >= KMinSize); sl@0: sl@0: if (IsMinFileSize) sl@0: { sl@0: err = aDbFile.iFileBuf.Read(size - KMinSize, buf); sl@0: } sl@0: sl@0: if (err == KErrCorrupt || err == KErrEof || !IsMinFileSize) sl@0: { sl@0: aDbFile.iFileBuf.Close(); sl@0: __SQLITETRACE_OSEXPR(TInt err2 =) TStaticFs::Fs().Delete(aFname); sl@0: SQLITE_TRACE_OS(OstTraceExt4(TRACE_INTERNALS, TVFS_DOFILESIZECORRUPTIONCHECK1, "OS;0x%X;TVfs::DoFileSizeCorruptionCheck;size=%lld;err=%d;deleteErr=%d", (TUint)&aDbFile, size, err, err2)); sl@0: err = aDbFile.iFileBuf.Create(TStaticFs::Fs(), aFname, aFmode); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TVFS_DOFILESIZECORRUPTIONCHECK2, "OS;0x%X;TVfs::DoFileSizeCorruptionCheck;createErr=%d", (TUint)&aDbFile, err)); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Opens or creates a file which name is in the aFileName parameter. sl@0: If the function succeeds, the file handle and other related information will be stored in the place pointed by the sl@0: aDbFile parameter, a memory block of sizeof(TDbFile) size for which is allocated by the caller. sl@0: The function will also retrieve the sector size and the device characteristics and store them in aDbFile, sl@0: which is actually a TDbFile pointer, for later use. sl@0: sl@0: @param aFileName Zero-terminated, UTF8 encoded file name. sl@0: If aFileName is NULL then a temporary file is created. sl@0: @param aDbFile Output parameter. The file handle and other related information will be stored there. sl@0: @param aFlags "Open/Create" input flags: sl@0: SQLITE_OPEN_DELETEONCLOSE, sl@0: SQLITE_OPEN_READWRITE, sl@0: SQLITE_OPEN_EXCLUSIVE, sl@0: SQLITE_OPEN_CREATE sl@0: @param aOutFlags "Open/Create" output flags: sl@0: SQLITE_OPEN_READWRITE, sl@0: SQLITE_OPEN_READONLY sl@0: sl@0: @return SQLITE_CANTOPEN, The aFileName parameter cannot be converted to UTF16. sl@0: Any other file I/O error will also be reported as SQLITE_CANTOPEN; sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured; sl@0: SQLITE_OK, The operation has completed successfully. sl@0: sl@0: @see TDbFile sl@0: */ sl@0: /* static */ int TVfs::Open(sqlite3_vfs* aVfs, const char* aFileName, sqlite3_file* aDbFile, int aFlags, int* aOutFlags) sl@0: { sl@0: TFileName fname; sl@0: if(aFileName && !::ConvertToUnicode(aFileName, fname)) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_OPEN1, "OS;0;TVfs::Open;ConvertToUnicode() failed")); sl@0: return SQLITE_CANTOPEN; sl@0: } sl@0: new (aDbFile) TDbFile; sl@0: TDbFile& dbFile = ::DbFile(aDbFile); sl@0: SQLITE_TRACE_OS(OstTraceExt3(TRACE_INTERNALS, TVFS_OPEN_ENTRY, "OS-Entry;0x%X;TVfs::Open;fname=%S;aFlags=0x%X", (TUint)&aDbFile, __SQLITEPRNSTR(fname), (TUint)aFlags)); sl@0: if(aFileName && (aFlags & SQLITE_OPEN_DELETEONCLOSE)) sl@0: { sl@0: dbFile.iFullName = fname.Alloc(); sl@0: if(!dbFile.iFullName) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_OPEN2, "OS;0;TVfs::Open;fname.Alloc() failed")); sl@0: return SQLITE_IOERR_NOMEM; sl@0: } sl@0: } sl@0: TInt recReadBufSize = -1; sl@0: TInt err = KErrNone; sl@0: TInt fmode = EFileRead; sl@0: if(aFlags & SQLITE_OPEN_READWRITE) sl@0: { sl@0: fmode |= EFileWrite; sl@0: } sl@0: //SQLite TCL tests expect the journal file to be open in shared mode. sl@0: if(aFlags & SQLITE_OPEN_EXCLUSIVE && !(aFlags & SQLITE_OPEN_MAIN_JOURNAL)) sl@0: { sl@0: fmode |= EFileShareExclusive; sl@0: } sl@0: else sl@0: { sl@0: fmode |= (fmode & EFileWrite) ? EFileShareAny : EFileShareReadersOnly; sl@0: } sl@0: if(!aFileName) sl@0: {//Create temporary file sl@0: err = ::CreateTempFile(dbFile, fname, fmode); sl@0: } sl@0: else sl@0: { sl@0: err = KErrAccessDenied;//The error has to be set here, because, there is a case where none of the file create/open operations will be executed sl@0: TInt prevErr = KErrNone; sl@0: if(aFlags & SQLITE_OPEN_CREATE) sl@0: { sl@0: prevErr = err = dbFile.iFileBuf.Create(TStaticFs::Fs(), fname, fmode); sl@0: } sl@0: if(err != KErrNone && err != KErrNoMemory && err != KErrDiskFull) sl@0: { sl@0: err = dbFile.iFileBuf.Open(TStaticFs::Fs(), fname, fmode); sl@0: if(err == KErrNone && (aFlags & KJournalFileTypeBitMask)) sl@0: { sl@0: err = TVfs::DoFileSizeCorruptionCheck(dbFile, fname, fmode); sl@0: } sl@0: } sl@0: if((err != KErrNone && err != KErrNoMemory && err != KErrDiskFull) && (aFlags & SQLITE_OPEN_READWRITE)) sl@0: { sl@0: aFlags &= ~SQLITE_OPEN_READWRITE; sl@0: aFlags |= SQLITE_OPEN_READONLY; sl@0: fmode &= ~EFileWrite; sl@0: err = dbFile.iFileBuf.Open(TStaticFs::Fs(), fname, fmode); sl@0: } sl@0: if(err != KErrNone && prevErr == KErrAccessDenied) sl@0: { sl@0: err = KErrAccessDenied; sl@0: } sl@0: } sl@0: if(err == KErrNone) sl@0: { sl@0: err = TVfs::DoGetDeviceCharacteristicsAndSectorSize(dbFile, recReadBufSize); sl@0: } sl@0: if(err != KErrNone) sl@0: { sl@0: dbFile.iFileBuf.Close(); sl@0: delete dbFile.iFullName; sl@0: dbFile.iFullName = NULL; sl@0: if(!aFileName && fname.Length() > 0) sl@0: {//temporary file, the error is not KErrNone. Then delete the file (after a successfull sl@0: //temporary file creation there could be a failed memory allocation) sl@0: (void)TStaticFs::Fs().Delete(fname); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: dbFile.pMethods = &TheFileIoApi; sl@0: dbFile.iReadOnly = !(aFlags & SQLITE_OPEN_READWRITE); sl@0: if(aOutFlags) sl@0: { sl@0: *aOutFlags = dbFile.iReadOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; sl@0: } sl@0: (void)dbFile.iFileBuf.SetReadAheadSize(dbFile.iSectorSize, recReadBufSize); sl@0: OpenCounter(+1); sl@0: } sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_CANTOPEN); sl@0: SQLITE_TRACE_OS(OstTraceExt4(TRACE_INTERNALS, TVFS_OPEN_EXIT, "OS-Exit;0x%X;TVfs::Open;outFlags=0x%X;err=%d;sqliteErr=%d", (TUint)&aDbFile, aOutFlags ? (TUint)*aOutFlags : 0, err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Deletes a file which name is in the aFileName parameter. sl@0: sl@0: @param aFileName Zero-terminated, UTF8 encoded file name. sl@0: sl@0: @return SQLITE_ERROR, The aFileName parameter cannot be converted to UTF16. sl@0: The file name refers to a private secure database; sl@0: SQLITE_IOERR_NOMEM, An out of memory condition has occured; sl@0: SQLITE_IOERR_DELETE,The delete file operation has failed; sl@0: SQLITE_OK, The operation has completed successfully. sl@0: */ sl@0: /* static */ int TVfs::Delete(sqlite3_vfs* aVfs, const char* aFileName, int /*aSyncDir*/) sl@0: { sl@0: SimulateIOError(return SQLITE_IOERR_DELETE); sl@0: TFileName fname; sl@0: if(!::ConvertToUnicode(aFileName, fname)) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_DELETE1, "OS;0;TVfs::Delete;ConvertToUnicode() failed")); sl@0: return SQLITE_ERROR; sl@0: } sl@0: TInt err = TStaticFs::Fs().Delete(fname); sl@0: TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_DELETE); sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TVFS_DELETE2, "OS;0;TVfs::Delete;err=%d;sqliteErr=%d", err, sqliteErr)); sl@0: return sqliteErr; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Retrieves an information about a file which name is in the aFileName parameter. sl@0: The requested information type can be: does the file exist, is the file read-only or read/write. sl@0: sl@0: @param aFileName Zero-terminated, UTF8 encoded file name. sl@0: @param aFlags This parameter can be one of: SQLITE_ACCESS_READ, SQLITE_ACCESS_EXISTS or SQLITE_ACCESS_READWRITE. sl@0: @param aResOut Output parameter, set to 1 if the tested condition is true, 0 otherwise. sl@0: sl@0: @return SQLITE_OK, The call has completed successfully, sl@0: SQLITE_IOERR_NOMEM, An out of memory conditon has occured, sl@0: SQLITE_IOERR_ACCESS,File I/O error; sl@0: */ sl@0: /* static */ int TVfs::Access(sqlite3_vfs* aVfs, const char* aFileName, int aFlags, int* aResOut) sl@0: { sl@0: TFileName fname; sl@0: if(!::ConvertToUnicode(aFileName, fname)) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_ACCESS1, "OS;0;TVfs::Access;ConvertToUnicode() failed")); sl@0: return SQLITE_IOERR_ACCESS; sl@0: } sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TVFS_ACCESS_ENTRY, "OS-Entry;0;TVfs::Access;fname=%S;aFlags=0x%X", __SQLITEPRNSTR(fname), (TUint)aFlags)); sl@0: TEntry entry; sl@0: TInt err = TStaticFs::Fs().Entry(fname, entry); sl@0: if(aFlags == SQLITE_ACCESS_EXISTS && err == KErrNotFound) sl@0: { sl@0: *aResOut = 0; sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_ACCESS_EXIT1, "OS-Exit;0;TVfs::Access;Exists-NoFound")); sl@0: return SQLITE_OK; sl@0: } sl@0: if(err != KErrNone) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TVFS_ACCESS_EXIT2, "OS-Exit;0;TVfs::Access;err=%d", err)); sl@0: return err == KErrNoMemory ? SQLITE_IOERR_NOMEM : SQLITE_IOERR_ACCESS; sl@0: } sl@0: *aResOut = 0; sl@0: switch(aFlags) sl@0: { sl@0: case SQLITE_ACCESS_READ: sl@0: *aResOut = entry.IsReadOnly(); sl@0: break; sl@0: case SQLITE_ACCESS_EXISTS: sl@0: *aResOut = 1; sl@0: break; sl@0: case SQLITE_ACCESS_READWRITE: sl@0: *aResOut = !entry.IsReadOnly(); sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TVFS_ACCESS_EXIT3, "OS-Exit;0;TVfs::Access;aResOut=%d", *aResOut)); sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Accepts UTF8 encoded, zero-terminated file as an input argument in the aRelative parameter sl@0: and constructs the full file path in the aBuf output parameter. sl@0: sl@0: If the format of aRelative argument is <[SID]FileName.[EXT]>, then the database file name will be sl@0: treated as a name of a secure database file which has to be created/opened in the server's private sl@0: directory on the system drive. sl@0: sl@0: If the format of aRelative argument is , then the database file name sl@0: will be treated as a name of a secure database file which has to be created/opened in the server's sl@0: private directory on drive. sl@0: sl@0: If the format of aRelative argument is , then the database file name sl@0: will be treated as a name of a non-secure database file in directory. sl@0: If aRelative contains file handles, then it will be treated as a name of a file belonging to server's sl@0: private data cage. sl@0: sl@0: @param aRelative The input file name, zero-terminated, UTF8 encoded. sl@0: @param aBufLen The output buffer length. sl@0: @param aBuf Output buffer for the constructed full file name path. The allocated buffer length must be at least aBufLen bytes. sl@0: sl@0: @return SQLITE_ERROR, The aRelative parameter is NULL or cannot be converted to UTF16; sl@0: SQLITE_OK The operation has completed successfully. sl@0: */ sl@0: /* static */ int TVfs::FullPathName(sqlite3_vfs* aVfs, const char* aRelative, int aBufLen, char* aBuf) sl@0: { sl@0: if(!aRelative) //NULL argument sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_FULLPATHNAME1, "OS;0;TVfs::FullPathName;err=SQLITE_ERROR")); sl@0: return SQLITE_ERROR; sl@0: } sl@0: //Convert the received file name to UTF16 sl@0: TBuf fname; sl@0: if(!::ConvertToUnicode(aRelative, fname)) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_FULLPATHNAME_EXIT1, "OS-Exit;0;TVfs::FullPathName;ConvertToUnicode() failed")); sl@0: return SQLITE_ERROR; sl@0: } sl@0: SQLITE_TRACE_OS(OstTraceExt2(TRACE_INTERNALS, TVFS_FULLPATHNAME_ENTRY, "OS-Entry;0;TVfs::FullPathName;fname=%S;aBufLen=%d", __SQLITEPRNSTR(fname), aBufLen)); sl@0: //Search if the file name begins with ".\" - current directory sl@0: if(fname.Find(KCwd) == 0) sl@0: { sl@0: fname.Delete(0, KCwd().Length()); sl@0: } sl@0: fname.Append(TChar(0));//Zero-terminate the converted file name sl@0: TFileName defaultPath; sl@0: TInt err = TStaticFs::Fs().SessionPath(defaultPath); sl@0: if(err != KErrNone) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace1(TRACE_INTERNALS, TVFS_FULLPATHNAME_EXIT4, "OS-Exit;0;TVfs::FullPathName;SessionPath() failed, err=%d", err)); sl@0: return SQLITE_ERROR; sl@0: } sl@0: TParse parse; sl@0: (void)parse.Set(fname, &defaultPath, 0);//If fname does not have a path, defaultPath will be used sl@0: TPtr8 dest8(reinterpret_cast (aBuf), aBufLen); sl@0: if(!::ConvertFromUnicode(parse.FullName(), dest8)) sl@0: { sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_FULLPATHNAME_EXIT2, "OS-Exit;0;TVfs::FullPathName;ConvertFromUnicode() failed")); sl@0: return SQLITE_ERROR; sl@0: } sl@0: SQLITE_TRACE_OS(OstTrace0(TRACE_INTERNALS, TVFS_FULLPATHNAME_EXIT3, "OS-Exit;0;TVfs::FullPathName;err=SQLITE_OK")); sl@0: return SQLITE_OK; sl@0: } sl@0: sl@0: /** sl@0: SQLite OS porting layer API. sl@0: sl@0: Generates a set of random numbers and stores them in the aBuf output parameter. sl@0: sl@0: @param aBufLen The output buffer length. sl@0: @param aBuf Output buffer for the generated random numbers. The allocated buffer length must be at least aBufLen bytes. sl@0: sl@0: @return The length of the used part of the output buffer. sl@0: */ sl@0: /* static */ int TVfs::Randomness(sqlite3_vfs* aVfs, int aBufLen, char* aBuf) sl@0: { sl@0: const TInt KRandIterations = aBufLen / sizeof(int); sl@0: for(TInt i=0;i