webengine/webkitutils/SqliteSymbian/os_symbian.cpp
changeset 0 dd21522fd290
child 68 92a765b5b3e7
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #ifdef  OS_SYMBIAN
       
    20 
       
    21 #ifdef __cplusplus
       
    22 extern "C" {
       
    23 #endif
       
    24 
       
    25 #include "sqliteInt.h"
       
    26 #include "os.h"
       
    27 
       
    28 #ifdef __cplusplus
       
    29 }  /* End of the 'extern "C"' block */
       
    30 #endif
       
    31 
       
    32 #include "os_common.h"
       
    33 #include "os_symbian.h"
       
    34 
       
    35 #include <f32file.h>
       
    36 #include <e32math.h>
       
    37 #include <hal.h>
       
    38 #include <BAUTILS.H>
       
    39 
       
    40 ///////////////////////////////////////////////////////////////////////////////////////////
       
    41 
       
    42 //Panic category - used by asserts in this file.
       
    43 _LIT(KPanicCategory, "SqliteSymbian");
       
    44 
       
    45 //Panic codes - used by asserts in this file.
       
    46 enum TPanicCodes
       
    47     {
       
    48     EPanicNullTlsPtr            = 1,
       
    49     EPanicInvalidWAmount        = 2,
       
    50     EPanicOffset64bit           = 3,
       
    51     EPanicInvalidLockType1      = 4,
       
    52     EPanicInvalidLockType2      = 5,
       
    53     EPanicInvalidLockType3      = 6,
       
    54     EPanicInvalidLockType4      = 7,
       
    55     EPanicInvalidLockType5      = 8,
       
    56     EPanicInvalidLockType6      = 9,
       
    57     EPanicInvalidLockType7      =10,
       
    58     EPanicInvalidOpType         =11,
       
    59     EPanicInvalidFhStr          =12,
       
    60     EPanicInvalidFhData         =13
       
    61     };
       
    62 
       
    63 //Define __COUNT_FILE_IO__ if want to get information about the file I/O 
       
    64 //operations count and the time spent in file I/O operations.
       
    65 #ifdef __COUNT_FILE_IO__
       
    66 
       
    67 //File I/O counters.
       
    68 static TDbFileIOCounters TheDbFileIOCounters;
       
    69 
       
    70 /**
       
    71 Resets all file I/O counters.
       
    72 
       
    73 This function is part of Symbian OS specific SQLITE API.
       
    74 
       
    75 @internalComponent
       
    76 */
       
    77 void sqlite3SymbianZeroDbFileIOCounters()
       
    78     {
       
    79     Mem::FillZ(&TheDbFileIOCounters, sizeof(TheDbFileIOCounters));
       
    80     }
       
    81 
       
    82 /**
       
    83 Copies file I/O counters to the place pointed by aDbFileIOCounters argument.
       
    84 
       
    85 @param aDbFileIOCounters Output parameter. The place where file I/O counters will be copied.
       
    86 
       
    87 This function is part of Symbian OS specific SQLITE API.
       
    88 
       
    89 @internalComponent
       
    90 */
       
    91 void sqlite3SymbianGetDbFileIOCounters(TDbFileIOCounters& aDbFileIOCounters)
       
    92     {
       
    93     aDbFileIOCounters = TheDbFileIOCounters;
       
    94     }
       
    95 
       
    96 //The following macros are used for managing file I/O counter values.
       
    97 //They are evaluated to nothing if __COUNT_FILE_IO__ is not defined.
       
    98 #define INC_COUNTER(cnt)            ++cnt
       
    99 #define GET_TIME(start)             TUint32 start = User::FastCounter()
       
   100 #define ADD_TIME_DIFF(start, var)   var += (User::FastCounter() - start);
       
   101 
       
   102 #else//__COUNT_FILE_IO__  //////////////////////////////////////////
       
   103 
       
   104 //The following macros are used for managing file I/O counter values.
       
   105 //They are evaluated to nothing if __COUNT_FILE_IO__ is not defined.
       
   106 #define INC_COUNTER(cnt)            void(0)
       
   107 #define GET_TIME(start)             void(0)
       
   108 #define ADD_TIME_DIFF(start, var)   void(0)
       
   109 
       
   110 #endif//__COUNT_FILE_IO__
       
   111 
       
   112 ///////////////////////////////////////////////////////////////////////////////////////////
       
   113 
       
   114 //If the following global variable points to a string which is the
       
   115 //name of a directory, then that directory will be used to store
       
   116 //temporary files.
       
   117 //
       
   118 //"PRAGMA temp_store_directory <dir_path>" command will set it!
       
   119 //This is a potential platform security hole and the temp dir path
       
   120 //is not used in os_symbian.cpp file. The temporaty files will be created
       
   121 //in the process's private data cage.
       
   122 //
       
   123 //There is a memory leak in SQLite if "PRAGMA temp_store_directory <dir_path>" is used,
       
   124 //because sqlite3_temp_directory stays undeleted when the program terminates.
       
   125 //So, it will be deleted in sqlite3SymbianFsClose() method.
       
   126 char *sqlite3_temp_directory;
       
   127 
       
   128 //Current thread's heap. Won't work in a mutithreaded environment.
       
   129 //Stored as a global variable to reduce Exec::Heap() calls count (made from User::Alloc()).
       
   130 static RAllocator* TheAllocator = NULL;
       
   131 
       
   132 ///////////////////////////////////////////////////////////////////////////////////////////
       
   133 
       
   134 // Static variables used for thread synchronization
       
   135 static TInt     TheMutexRefCounter = 0;
       
   136 
       
   137 //Zeroed thread data instance.
       
   138 const ThreadData TheZeroThreadData = {0};
       
   139 
       
   140 //Const buffer used for generating temporary file names.
       
   141 //No lower case letters in the buffer because the OS won't make difference between lower and upper case in file names.
       
   142 const char TheChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
       
   143 
       
   144 ///////////////////////////////////////////////////////////////////////////////////////////
       
   145 /////////////////////       TTlsData class - declaration, definition    ///////////////////
       
   146 ///////////////////////////////////////////////////////////////////////////////////////////
       
   147 
       
   148 //TTlsData class manages a per-thread copy of the following data: 
       
   149 //  - file session instance;
       
   150 //  - process's private data path, where the temporary file will be stored (on Drive C);
       
   151 //  - last OS error code, every Symbian OS API call will set it;
       
   152 //  - stored OS error code, initialized with the last OS error code only if stored OS error code is KErrNone.
       
   153 //      Each StoredOsErrorCode() call will reset it to KErrNone;
       
   154 //  - reference counter. Only one TTlsData instance gets created per thread;
       
   155 //
       
   156 //The reason of having two data members for storing the OS error codes is that if there is just one variable
       
   157 //and it gets initialized with the error value reported by a failed OS API call, the next successful OS API
       
   158 //call will reset it and the TTlsData client will miss the last "real" OS API error.
       
   159 class TTlsData
       
   160     {
       
   161 public: 
       
   162     static TInt Create();
       
   163     static void Release();
       
   164     static TTlsData& Instance();
       
   165     
       
   166     TInt SetOsErrorCode(TInt aError);
       
   167     inline TInt StoredOsErrorCode();
       
   168     
       
   169     inline void StoreFhData(const RMessage2* aMsg, TBool aReadOnly);
       
   170     inline void RetrieveAndResetFhData(const RMessage2*& aMsg, TBool& aReadOnly);
       
   171     
       
   172 private:
       
   173     TTlsData();
       
   174     ~TTlsData();
       
   175     TInt DoCreate();
       
   176     
       
   177 public:
       
   178     //File session instance.
       
   179     RFs         iFs;
       
   180     //"<system drive>:\" + process's private data path. Initialized in sqlite3SymbianFsOpen().
       
   181     //Used for storing sqlite temporary files.
       
   182     TFileName   iSysPrivDir;
       
   183     TParse      iParse;
       
   184     
       
   185 private:    
       
   186     //Contains the last OS error code.
       
   187     TInt                iStoredOsErrorCode;
       
   188     //Counts the number of times when an attempt has been made to create TTlsData instance.
       
   189     //TTlsData instance is created just once. This counter is useless in a true client-server
       
   190     //environment, but is very usefull when testing the prototype.
       
   191     TInt                iRefCounter;
       
   192     //Fh data
       
   193     const RMessage2*    iMessage;
       
   194     TBool               iReadOnly;  
       
   195     };
       
   196 
       
   197 //Returns the address of TlsHandle1() function. Used as a unique handle when calling UserSvr::DllTls()
       
   198 //and UserSvr::DllSetTls(). 
       
   199 //So, if the SQL server is a single threaded process, there is a need of only one TLS instance, identified
       
   200 //uniquely by TlsHandle1() address.
       
   201 static TInt TlsHandle1()
       
   202     {
       
   203     return reinterpret_cast <TInt> (&TlsHandle1);
       
   204     }
       
   205 
       
   206 //Checks if the TTlsData instance exists and if not the method creates it and stores it in the TLS.
       
   207 //The TTlsData instance reference counter is incremented.
       
   208 TInt TTlsData::Create()
       
   209     {
       
   210     TTlsData* data = static_cast <TTlsData*> (UserSvr::DllTls(TlsHandle1()));
       
   211     if(!data)
       
   212         {
       
   213         data = new TTlsData;
       
   214         if(!data)
       
   215             {
       
   216             return KErrNoMemory;    
       
   217             }
       
   218         TInt err = data->DoCreate();
       
   219         if(err == KErrNone)
       
   220             {
       
   221             err = UserSvr::DllSetTls(TlsHandle1(), data);
       
   222             }
       
   223         if(err != KErrNone)
       
   224             {
       
   225             delete data;
       
   226             return err;
       
   227             }
       
   228         }
       
   229     ++data->iRefCounter;
       
   230     //Do not delete "data"! The TLS keeps a pointer to it.
       
   231     return KErrNone;
       
   232     }
       
   233 
       
   234 //Destroys the TTlsData instance if it exists and the decremented reference counter reaches 0.
       
   235 void TTlsData::Release()
       
   236     {
       
   237     TTlsData* data = static_cast <TTlsData*> (UserSvr::DllTls(TlsHandle1()));
       
   238     if(data && !--data->iRefCounter)
       
   239         {
       
   240         sqliteFree((void*)sqlite3_temp_directory);
       
   241         sqlite3_temp_directory = 0;
       
   242         sqlite3_thread_cleanup();
       
   243         delete data;
       
   244         (void)UserSvr::DllSetTls(TlsHandle1(), 0);
       
   245         }
       
   246     }
       
   247 
       
   248 //Returns a reference to the TTlsData instance. 
       
   249 TTlsData& TTlsData::Instance()
       
   250     {
       
   251     TTlsData* data = static_cast <TTlsData*> (UserSvr::DllTls(TlsHandle1()));
       
   252     if (data == NULL) {
       
   253         sqlite3SymbianLibInit();
       
   254         data = static_cast <TTlsData*> (UserSvr::DllTls(TlsHandle1()));
       
   255     }
       
   256     __ASSERT_ALWAYS(data != NULL, User::Panic(KPanicCategory, EPanicNullTlsPtr));
       
   257     return *data;
       
   258     }
       
   259 
       
   260 //Sets the last OS error code data member. The stored OS error code data member will be set only if it is
       
   261 //KErrNone. (If it is not KErrNone it means that its value has not been accessed yet)
       
   262 //An exception from the rule described above is KErrDiskFull error which, if happens, will be set always, because
       
   263 //this error has a special meaning for the database clients - special actions may have to be taken if the
       
   264 //disk is full.
       
   265 //If aError is KErrNoMemory SQLITE will be notified with a sqlite3FailedMalloc() call.
       
   266 TInt TTlsData::SetOsErrorCode(TInt aError)
       
   267     {
       
   268     if(aError == KErrNoMemory)
       
   269         {
       
   270         sqlite3FailedMalloc();          
       
   271         }
       
   272     if(iStoredOsErrorCode == KErrNone || aError == KErrDiskFull)
       
   273         {
       
   274         iStoredOsErrorCode = aError;
       
   275         }
       
   276     return aError;
       
   277     }
       
   278 
       
   279 //Returns the last stored OS error code, which was stored by SetOsErrorCode() call.
       
   280 //The function also resets the stored OS error code to KErrNone.
       
   281 inline TInt TTlsData::StoredOsErrorCode()
       
   282     {
       
   283     TInt err = iStoredOsErrorCode;
       
   284     iStoredOsErrorCode = KErrNone;
       
   285     return err;
       
   286     }
       
   287 
       
   288 //Stores RMessage2 address, file and file session handles and the read-only flag for use when SQLITE issues a 
       
   289 //request for open the database file. 
       
   290 inline void TTlsData::StoreFhData(const RMessage2* aMsg, TBool aReadOnly)
       
   291     {
       
   292     iMessage = aMsg;
       
   293     iReadOnly = aReadOnly;
       
   294     }
       
   295 
       
   296 //Retrieves RMessage2 address, file and file session handles. The stored data will be reset.    
       
   297 inline void TTlsData::RetrieveAndResetFhData(const RMessage2*& aMsg, TBool& aReadOnly)
       
   298     {
       
   299     __ASSERT_DEBUG(iMessage != NULL, User::Panic(KPanicCategory, EPanicInvalidFhData));
       
   300     aMsg = iMessage; 
       
   301     aReadOnly = iReadOnly;
       
   302     iMessage = NULL;
       
   303     }
       
   304 
       
   305 //Reference counter is set to 0.
       
   306 TTlsData::TTlsData() :
       
   307     iStoredOsErrorCode(KErrNone),
       
   308     iRefCounter(0),
       
   309     iMessage(0),
       
   310     iReadOnly(EFalse)   
       
   311     {
       
   312     }
       
   313 
       
   314 //Closes the file session.
       
   315 TTlsData::~TTlsData()
       
   316     {
       
   317     iFs.Close();    
       
   318     }
       
   319 
       
   320 //Creates per-thread file session instance. 
       
   321 //Creates the private path, where the temporary files will be stored. (on the system drive)
       
   322 TInt TTlsData::DoCreate()
       
   323     {
       
   324     TInt err = iFs.Connect();
       
   325     if(err != KErrNone)
       
   326         {
       
   327         return err; 
       
   328         }
       
   329     //Get the system drive
       
   330     TDriveNumber drv;
       
   331     err = BaflUtils::GetSystemDrive( drv );
       
   332     if(err == KErrNotFound )
       
   333         {
       
   334         drv = EDriveC;
       
   335         err = KErrNone;
       
   336         }
       
   337     if( err == KErrNone )
       
   338         {
       
   339         TInt sysDrive = static_cast<TInt>(drv);
       
   340         if((err = iFs.CreatePrivatePath(sysDrive)) != KErrNone && err != KErrAlreadyExists)
       
   341             {
       
   342             return err; 
       
   343             }
       
   344         TFileName privateDir;
       
   345         if((err = iFs.PrivatePath(privateDir)) != KErrNone)
       
   346             {
       
   347             return err; 
       
   348             }
       
   349         TDriveUnit drive(sysDrive);
       
   350         TDriveName driveName = drive.Name();
       
   351         (void)iParse.Set(driveName, &privateDir, 0);//this call can't fail
       
   352         iSysPrivDir.Copy(iParse.DriveAndPath());
       
   353         return KErrNone;
       
   354         }
       
   355     return err;    
       
   356     }
       
   357 
       
   358 ///////////////////////////////////////////////////////////////////////////////////////////
       
   359 
       
   360 //aFileName argument is expected to point to UTF8 encoded, zero terminated string.
       
   361 //The function converts aFileName to UTF16 encoded file name, and stores the UTF16 encoded file name
       
   362 //to the place pointed by aFileNameDestBuf argument.
       
   363 //If the UTF16 conversion of the file name failed because the file name is too long or NULL, 
       
   364 //the function returns EFalse. 
       
   365 //Max allowed aFileName length is KMaxFileName (excluding terminating 0 character).
       
   366 //aFileNameDestBuf max length must be at least KMaxFileName characters.
       
   367 //
       
   368 //aFileNameDestBuf will hold UTF16, non-zero-terminated string
       
   369 static TBool ConvertToUnicode(const char *aFileName, TDes& aFileNameDestBuf)
       
   370     {
       
   371     if(aFileName)
       
   372         {
       
   373         wchar_t* dest = reinterpret_cast <wchar_t*> (const_cast <TUint16*> (aFileNameDestBuf.Ptr()));
       
   374         TInt len = mbstowcs(dest, aFileName, KMaxFileName);
       
   375         //Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid.
       
   376         if(len > 0 && len <= KMaxFileName)
       
   377             {
       
   378             aFileNameDestBuf.SetLength(len);
       
   379             return ETrue;
       
   380             }
       
   381         }
       
   382     return EFalse;
       
   383     }
       
   384 
       
   385 //aFileName argument is expected to point to UTF16 encoded, zero terminated string.
       
   386 //The function converts aFileName to UTF8 encoded file name, and stores the UTF8 encoded file name
       
   387 //to the place pointed by aFileNameDestBuf argument.
       
   388 //If the UTF8 conversion of the file name failed because the file name is too long or NULL, 
       
   389 //the function returns EFalse. 
       
   390 //Max allowed aFileName length is KMaxFileName (excluding terminating 0 character).
       
   391 //aFileNameDestBuf max length must be at least KMaxFileName characters.
       
   392 //
       
   393 //aFileNameDestBuf will hold UTF8, non-zero-terminated string
       
   394 static TBool ConvertFromUnicode(const TDesC& aFileName, TDes8& aFileNameDestBuf)
       
   395     {
       
   396     char* dest = reinterpret_cast <char*> (const_cast <TUint8*> (aFileNameDestBuf.Ptr()));
       
   397     const wchar_t* src = reinterpret_cast <const wchar_t*> (aFileName.Ptr());
       
   398     TInt len = wcstombs(dest, src, KMaxFileName);
       
   399     //Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid.
       
   400     if(len > 0 && len <= KMaxFileName)
       
   401         {
       
   402         aFileNameDestBuf.SetLength(len);
       
   403         return ETrue;
       
   404         }
       
   405     return EFalse;
       
   406     }
       
   407 
       
   408 ///////////////////////////////////////////////////////////////////////////////////////////
       
   409 //////////////////          File name, containing handles, related   //////////////////////
       
   410 ///////////////////////////////////////////////////////////////////////////////////////////
       
   411 
       
   412 const char KFhSeparator = '|';  //The symbol, which when used in the file name means that the string does not contain a real file name but file handles
       
   413 const TInt KFhSessHandleIdx = 2;//The index of the file session handle in RMessage2 object
       
   414 const TInt KFhFileHandleIdx = 3;//The index of the file handle in RMessage2 object
       
   415 const TInt KFhReconPos = 0;     //if the symbol in this position KFhSeparator, then the string contains file handles
       
   416 const TInt KFhRoPos = 1;        //read-only flag position in the string
       
   417 const TInt KFhMsgAddrPos = 2;   //RMessage2 address position in the string
       
   418 const TInt KFhMsgAddrLen = 8;   //RMessage2 address length
       
   419 //const TInt KFhDrivePos = 1;   //Drive position in the string (after removing the read-only flag and RMessage2 object's address)
       
   420 
       
   421 //Possible file name string types.
       
   422 enum TFhStrType
       
   423     {
       
   424     ENotFhStr,                      //The string does not contain file handles
       
   425     EFhStr,                         //The string contain file handles, but is not main db file
       
   426     EFhMainDbStr                    //The string contain file handles and is the main db file
       
   427     };
       
   428 
       
   429 //Returns:
       
   430 // - ENotFhStr    - aFileName is a normal file name
       
   431 // - EFhMainDbStr - aFile name contains the handle of a database file opened on the client side (and some other relevant information)
       
   432 // - EFhStr       - aFileName is a journal file name for example. The main database file was opened from a handle in this case.
       
   433 static TFhStrType FhStringProps(const char* aFileName)
       
   434     {
       
   435     char* first = strchr(aFileName, KFhSeparator);
       
   436     if(!first)
       
   437         {
       
   438         return ENotFhStr;
       
   439         }
       
   440     char* last = strchr(first + 1, KFhSeparator);
       
   441     if(!last)
       
   442         {
       
   443         return ENotFhStr;
       
   444         }
       
   445     return *(last + 1) == 0 ? EFhMainDbStr : EFhStr;
       
   446     }
       
   447 
       
   448 //Replaces all invalid characters in aFileName.
       
   449 static void FhConvertToFileName(TDes& aFileName, TParse& aParse, const TDesC& aPrivateDir)
       
   450     {
       
   451     TInt firstPos = aFileName.Locate(TChar(KFhSeparator));
       
   452     if(firstPos >= 0)
       
   453         {
       
   454         aFileName.Delete(firstPos, 1);
       
   455         TInt lastPos = aFileName.LocateReverse(TChar(KFhSeparator));
       
   456         if(lastPos >= 0)
       
   457             {
       
   458             aFileName.Delete(lastPos, 1);
       
   459             (void)aParse.Set(aFileName, &aPrivateDir, 0);//the file name should be verified by the server
       
   460             aFileName.Copy(aParse.FullName());
       
   461             }
       
   462         }
       
   463     }
       
   464 
       
   465 //Extracts read-only flag and RMessage address from aDbFileName and stores them in TLS.
       
   466 //aDbFileName will be reformatted and won't contain the already extracted data.
       
   467 //aDbFileName format is:
       
   468 //      |<R/O flag><RMessage2 pointer><drive><app SID><file_name><file_ext>|
       
   469 static void FhExtractAndStore(TDes& aDbFileName, TTlsData& aTls)
       
   470     {
       
   471     TInt fhStartPos = aDbFileName.Locate(TChar(KFhSeparator));
       
   472     __ASSERT_DEBUG(fhStartPos == KFhReconPos, User::Panic(KPanicCategory, EPanicInvalidFhStr));
       
   473     //If this file name string contains file handles
       
   474     if(fhStartPos == KFhReconPos)
       
   475         {
       
   476         //Extract from aDbFileName string RMessage2 object's address
       
   477         TLex lex(aDbFileName.Mid(fhStartPos + KFhMsgAddrPos, KFhMsgAddrLen));
       
   478         TUint32 addr;
       
   479         TInt err = lex.Val(addr, EHex);
       
   480         __ASSERT_DEBUG(err == KErrNone, User::Panic(KPanicCategory, EPanicInvalidFhStr));
       
   481         if(err == KErrNone)
       
   482             {
       
   483             //Cast the address to RMessage2 pointer.
       
   484             const RMessage2* msg = reinterpret_cast <const RMessage2*> (addr);
       
   485             __ASSERT_DEBUG(msg != NULL, User::Panic(KPanicCategory, EPanicInvalidFhStr));
       
   486             if(msg)
       
   487                 {
       
   488                 //Store the data from aDbFileName in TLS
       
   489                 TBool readOnly = aDbFileName[fhStartPos + KFhRoPos] > '0';
       
   490                 aTls.StoreFhData(msg, readOnly);
       
   491                 //Remove: read-only flag and RMessage2 object's address
       
   492                 aDbFileName.Delete(fhStartPos + KFhRoPos, 1 + KFhMsgAddrLen);
       
   493                 }
       
   494             }
       
   495         }
       
   496     }
       
   497 
       
   498 ///////////////////////////////////////////////////////////////////////////////////////////
       
   499 ///////////////////////     Symbian OS specific SQLITE API         ////////////////////////
       
   500 ///////////////////////////////////////////////////////////////////////////////////////////
       
   501 
       
   502 /**
       
   503 Returns the last OS error which occured durring the operations with the database files.
       
   504 The per-thread variable, where the last OS error is hold, will be set to KErrNone.
       
   505 
       
   506 This function is part of Symbian OS specific SQLITE API.
       
   507 
       
   508 @return The last OS error.
       
   509 @internalComponent
       
   510 */
       
   511 EXPORT_C TInt sqlite3SymbianLastOsError(void)
       
   512     {
       
   513     TTlsData& tls = TTlsData::Instance();
       
   514     return tls.StoredOsErrorCode();
       
   515     }
       
   516 
       
   517 /**
       
   518 This function must be called once before any other SQLITE API call. It does Symbian OS specific
       
   519 initialization. Each sqlite3SymbianLibInit() call must be paired with a sqlite3SymbianLibFinalize() call
       
   520 when finishing working with SQLITE.
       
   521 
       
   522 This function is part of Symbian OS specific SQLITE API.
       
   523 
       
   524 @return Symbian OS specific error code, including KErrNoMemory.
       
   525 @internalComponent
       
   526 */
       
   527 EXPORT_C TInt sqlite3SymbianLibInit(void)
       
   528     {
       
   529     TheAllocator = &User::Allocator();
       
   530     return TTlsData::Create();
       
   531     }
       
   532 
       
   533 /**
       
   534 This function must be called once after finishing working with sqlite.
       
   535 
       
   536 This function is part of Symbian OS specific SQLITE API.
       
   537 
       
   538 @internalComponent
       
   539 */
       
   540 EXPORT_C void sqlite3SymbianLibFinalize(void)
       
   541     {
       
   542     TTlsData::Release();
       
   543     TheAllocator = NULL;
       
   544     }
       
   545 
       
   546 /**
       
   547 This function is part of Symbian OS specific SQLITE API.
       
   548 
       
   549 @return A reference to RFs instance used for sqlite file I/O operations.
       
   550 @internalComponent
       
   551 */
       
   552 EXPORT_C RFs& sqlite3SymbianFs(void)
       
   553     {
       
   554     return TTlsData::Instance().iFs;
       
   555     }
       
   556 
       
   557 ///////////////////////////////////////////////////////////////////////////////////////////
       
   558 
       
   559 //Attempt to open a file descriptor for the directory that contains a
       
   560 //file.  This file descriptor can be used to fsync() the directory
       
   561 //in order to make sure the creation of a new file is actually written
       
   562 //to disk.
       
   563 //
       
   564 //This routine is only meaningful for Unix.  It is a no-op under
       
   565 //Symbian OS since Symbian OS does not support hard links.
       
   566 //
       
   567 //On success, a handle for a previously open file is at *aOsFile is
       
   568 //updated with the new directory file descriptor and SQLITE_OK is
       
   569 //returned.
       
   570 //
       
   571 //On failure, the function returns SQLITE_CANTOPEN and leaves
       
   572 //*aOsFile unchanged.
       
   573 int sqlite3SymbianOpenDirectory(OsFile* /*aOsFile*/, const char * /*aDirName*/)
       
   574     {
       
   575     return SQLITE_OK;
       
   576     }
       
   577 
       
   578 ///////////////////////////////////////////////////////////////////////////////////////////
       
   579 /////////////////////       CDbFile class - declaration, definition    ////////////////////
       
   580 ///////////////////////////////////////////////////////////////////////////////////////////
       
   581 
       
   582 // CDbFile class has a set of methods and data members used for the file I/O operations performed by SQLITE.
       
   583 // Following the recomendations made in the comments of OsFile structure in os.h file, CDbFile was declared
       
   584 // as a class derived from OsFile.
       
   585 // The class consists of two sets of methods:
       
   586 // - Non-static methods (most of them inlined). They just forward the call to the related RFile method call.
       
   587 // - Static methods. Used for the initialization of OsFile::pMethod data member (IoMethod structure).
       
   588 // The class also holds information about the current file lock type and a flag indicating should the
       
   589 // file be deleted after closing it.
       
   590 class CDbFile : public OsFile
       
   591     {
       
   592 public: 
       
   593     static CDbFile* New();
       
   594     inline TInt Create(const TDesC& aFileName);
       
   595     inline TInt CreateExclusive(const TDesC& aFileName, TBool aDeleteOnClose);
       
   596     inline TInt Open(const TDesC& aFileName);
       
   597     inline TInt OpenReadOnly(const TDesC& aFileName);
       
   598     inline TInt OpenFromHandle(const RMessage2& aMsg);
       
   599     inline TInt Read(TDes8& aDes, TInt aLength);
       
   600     inline TInt Write(const TDesC8& aData, TInt aLength);
       
   601     inline TInt Size(TInt& aSize) const;
       
   602     inline TInt SetSize(TInt aSize);
       
   603     inline TInt Flush();
       
   604     ~CDbFile();
       
   605     
       
   606     inline TInt Handle() const;
       
   607     inline void SetLockType(TInt aLockType);
       
   608     inline TInt LockType() const;
       
   609 
       
   610     //"IoMethod" methods
       
   611     static int Close(OsFile** aOsFile);
       
   612     static int Read(OsFile* aOsFile, void*, int amt);
       
   613     static int Write(OsFile* aOsFile, const void*, int amt);
       
   614     static int Seek(OsFile* aOsFile, i64 offset);
       
   615     static int Truncate(OsFile* aOsFile, i64 size);
       
   616     static int Sync(OsFile* aOsFile, int);
       
   617     static void SetFullSync(OsFile* aOsFile, int setting);
       
   618     static int FileHandle(OsFile* aOsFile);
       
   619     static int FileSize(OsFile* aOsFile, i64 *pSize);
       
   620     static int Lock(OsFile* aOsFile, int aLockType);
       
   621     static int Unlock(OsFile* aOsFile, int);
       
   622     static int LockState(OsFile* aOsFile);
       
   623     static int CheckReservedLock(OsFile* aOsFile);
       
   624     /////
       
   625     
       
   626 private:
       
   627     CDbFile();  
       
   628     static inline CDbFile& Instance(void* aDbFile);
       
   629 
       
   630 private:    
       
   631     RFile   iFile;
       
   632     HBufC*  iFileToBeDeleted;//Not NULL if CDbFile is a temporary file and will be deleted when closed
       
   633     TInt    iLockType;      // Type of lock currently held on this file: NO_LOCK, SHARED_LOCK, 
       
   634                             // RESERVED_LOCK, PENDING_LOCK, EXCLUSIVE_LOCK
       
   635     TInt    iFilePos;
       
   636     TInt    iFileSize;
       
   637     };
       
   638 
       
   639 #define CREATE_FILE_MODE()              EFileRead | EFileWrite
       
   640 #define CREATE_FILE_EXCLUSIVE_MODE()    EFileRead | EFileWrite
       
   641 #define OPEN_FILE_SHARED_MODE()         EFileRead | EFileWrite
       
   642 #define OPEN_FILE_READONLY_MODE()       EFileRead
       
   643     
       
   644 //Creates non-initializad CDbFile instance.
       
   645 CDbFile* CDbFile::New()
       
   646     {
       
   647     return new CDbFile;
       
   648     }
       
   649 
       
   650 //Creates a file with aFileName. The file will be created for shared reading/writing.
       
   651 //This call initializes CDbFile instance.
       
   652 inline TInt CDbFile::Create(const TDesC& aFileName)
       
   653     {
       
   654     return iFile.Create(TTlsData::Instance().iFs, aFileName, CREATE_FILE_MODE());
       
   655     }
       
   656     
       
   657 //Creates a file with aFileName. The file will be created for exclusive reading/writing.
       
   658 //This call initializes CDbFile instance.
       
   659 //The function may return KErrNoMemory.
       
   660 inline TInt CDbFile::CreateExclusive(const TDesC& aFileName, TBool aDeleteOnClose)
       
   661     {
       
   662     if(aDeleteOnClose)
       
   663         {
       
   664         iFileToBeDeleted = aFileName.Alloc();
       
   665         if(!iFileToBeDeleted)
       
   666             {
       
   667             return KErrNoMemory;    
       
   668             }
       
   669         }
       
   670     return iFile.Create(TTlsData::Instance().iFs, aFileName, CREATE_FILE_EXCLUSIVE_MODE());
       
   671     }
       
   672     
       
   673 //Opens a file with aFileName. The file will be opened for shared reading/writing.
       
   674 //This call initializes CDbFile instance.
       
   675 inline TInt CDbFile::Open(const TDesC& aFileName)
       
   676     {
       
   677     TInt err = iFile.Open(TTlsData::Instance().iFs, aFileName, OPEN_FILE_SHARED_MODE());
       
   678     if(err == KErrNone)
       
   679         {
       
   680         err = Size(iFileSize);
       
   681         }
       
   682     return err;
       
   683     }
       
   684     
       
   685 //Opens a file with aFileName. The file will be opened in shared read-only mode.
       
   686 //This call initializes CDbFile instance.
       
   687 inline TInt CDbFile::OpenReadOnly(const TDesC& aFileName)
       
   688     {
       
   689     TInt err = iFile.Open(TTlsData::Instance().iFs, aFileName, OPEN_FILE_READONLY_MODE());
       
   690     if(err == KErrNone)
       
   691         {
       
   692         err = Size(iFileSize);
       
   693         }
       
   694     return err;
       
   695     }
       
   696 
       
   697 //Opens database file from handle
       
   698 inline TInt CDbFile::OpenFromHandle(const RMessage2& aMsg)
       
   699     {
       
   700     TInt err = iFile.AdoptFromClient(aMsg, KFhSessHandleIdx, KFhFileHandleIdx);
       
   701     if(err == KErrNone)
       
   702         {
       
   703         err = Size(iFileSize);
       
   704         }
       
   705     return err;
       
   706     }
       
   707 
       
   708 //Reads aLength bytes from the file and stores them to the place pointed by aDes argument.
       
   709 inline TInt CDbFile::Read(TDes8& aDes, TInt aLength)
       
   710     {
       
   711     TInt err = iFile.Read(iFilePos, aDes, aLength);
       
   712     if(err == KErrNone)
       
   713         {
       
   714         if(aDes.Length() < aLength)
       
   715             {
       
   716             err = KErrEof;  
       
   717             }
       
   718         else
       
   719             {
       
   720             iFilePos += aLength;
       
   721             }
       
   722         }
       
   723     return err;
       
   724     }
       
   725 
       
   726 //Writes aLength bytes to the file usign as data source aData argument.
       
   727 inline TInt CDbFile::Write(const TDesC8& aData, TInt aLength)
       
   728     {
       
   729     TInt err = iFile.Write(iFilePos, aData, aLength);
       
   730     if(err == KErrNone)
       
   731         {
       
   732         iFilePos += aLength;
       
   733         if(iFilePos > iFileSize)
       
   734             {
       
   735             iFileSize = iFilePos;   
       
   736             }
       
   737         }
       
   738     return err;
       
   739     }
       
   740 
       
   741 //Returns the file size in bytes.
       
   742 inline TInt CDbFile::Size(TInt& aSize) const
       
   743     {
       
   744     return iFile.Size(aSize);
       
   745     }
       
   746     
       
   747 //Sets the file size. aSize - in bytes.
       
   748 //Not that if SetSize() truncates the file, iFilePos may become invalid!
       
   749 inline TInt CDbFile::SetSize(TInt aSize)
       
   750     {
       
   751     return iFile.SetSize(aSize);
       
   752     }
       
   753 
       
   754 //Flushes all unwritten file buffers to the file.   
       
   755 inline TInt CDbFile::Flush()
       
   756     {
       
   757     return iFile.Flush();
       
   758     }
       
   759 
       
   760 //Closes the file. If iFileToBeDeleted is not NULL, the file will be deleted.
       
   761 CDbFile::~CDbFile()
       
   762     {
       
   763     iFile.Close();
       
   764     if(iFileToBeDeleted)
       
   765         {
       
   766         GET_TIME(start);
       
   767         (void)TTlsData::Instance().iFs.Delete(*iFileToBeDeleted);
       
   768         ADD_TIME_DIFF(start, TheDbFileIOCounters.iDeleteOpTime);
       
   769         INC_COUNTER(TheDbFileIOCounters.iDeleteOpCnt);
       
   770         delete iFileToBeDeleted;
       
   771         }
       
   772     }
       
   773 
       
   774 //Returns the file handle. Used for debug purposes only.
       
   775 inline TInt CDbFile::Handle() const
       
   776     {
       
   777     return iFile.SubSessionHandle();    
       
   778     }
       
   779 
       
   780 //Sets the file lock type.
       
   781 inline void CDbFile::SetLockType(TInt aLockType)
       
   782     {
       
   783     iLockType = aLockType;
       
   784     }
       
   785     
       
   786 //Returns the current file lock type.
       
   787 inline TInt CDbFile::LockType() const
       
   788     {
       
   789     return iLockType;
       
   790     }
       
   791 
       
   792 //Closes the file. The file will be deleted if it has been marked for deletion (iFileToBeDeleted not NULL).
       
   793 int CDbFile::Close(OsFile** aOsFile)
       
   794     {
       
   795     if(aOsFile)
       
   796         {
       
   797         CDbFile* dbFile = static_cast <CDbFile*> (*aOsFile);
       
   798         TRACE2("CLOSE %X\n", dbFile->Handle());
       
   799         
       
   800         GET_TIME(start);
       
   801         delete dbFile;
       
   802         ADD_TIME_DIFF(start, TheDbFileIOCounters.iCloseOpTime);
       
   803         INC_COUNTER(TheDbFileIOCounters.iCloseOpCnt);
       
   804         
       
   805         OpenCounter(-1);
       
   806         *aOsFile = 0;
       
   807         }
       
   808     return SQLITE_OK;
       
   809     }
       
   810 
       
   811 //Read data from a file into a buffer.  Return SQLITE_OK if all
       
   812 //bytes were read successfully and SQLITE_IOERR if anything goes
       
   813 //wrong.
       
   814 int CDbFile::Read(OsFile *aOsFile, void *aBuf, int aAmt)
       
   815     {
       
   816     TTlsData& tls = TTlsData::Instance();
       
   817     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   818     
       
   819     SimulateIOError(SQLITE_IOERR);
       
   820     
       
   821     TRACE3("READ %X lock=%d\n", dbFile.Handle(), dbFile.LockType());
       
   822     
       
   823     TPtr8 ptr(reinterpret_cast <TUint8*> (aBuf), aAmt);
       
   824     INC_COUNTER(TheDbFileIOCounters.iReadOpCnt);
       
   825     GET_TIME(start);
       
   826     TInt err = dbFile.Read(ptr, aAmt);
       
   827     ADD_TIME_DIFF(start, TheDbFileIOCounters.iReadOpTime);
       
   828     
       
   829     tls.SetOsErrorCode(err);
       
   830     return err == KErrNone ? SQLITE_OK : SQLITE_IOERR;
       
   831     }
       
   832 
       
   833 //Write data from a buffer into a file.  Return SQLITE_OK on success
       
   834 //or some other error code on failure.
       
   835 int CDbFile::Write(OsFile *aOsFile, const void *aBuf, int aAmt)
       
   836     {
       
   837     TTlsData& tls = TTlsData::Instance();
       
   838     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   839     
       
   840     SimulateIOError(SQLITE_IOERR);
       
   841     SimulateDiskfullError;
       
   842         
       
   843     TRACE3("WRITE %X lock=%d\n", dbFile.Handle(), dbFile.LockType());
       
   844     
       
   845     __ASSERT_DEBUG(aAmt > 0, User::Panic(KPanicCategory, EPanicInvalidWAmount));
       
   846     TPtrC8 ptr(reinterpret_cast <const TUint8*> (aBuf), aAmt);
       
   847     INC_COUNTER(TheDbFileIOCounters.iWriteOpCnt);
       
   848     GET_TIME(start);
       
   849     TInt err = KErrNone;
       
   850     if(dbFile.iFilePos > dbFile.iFileSize)
       
   851         {
       
   852         err = dbFile.SetSize(dbFile.iFilePos);
       
   853         if(err == KErrNone)
       
   854             {
       
   855             dbFile.iFileSize = dbFile.iFilePos;
       
   856             }
       
   857         }
       
   858     if(err == KErrNone)
       
   859         {
       
   860         err = dbFile.Write(ptr, aAmt);
       
   861         }
       
   862     ADD_TIME_DIFF(start, TheDbFileIOCounters.iWriteOpTime);
       
   863     
       
   864     tls.SetOsErrorCode(err);
       
   865     return err == KErrNone ? SQLITE_OK : SQLITE_FULL;
       
   866     }
       
   867 
       
   868 //Move the read/write pointer in a file.
       
   869 //The function does not actually move the file pointer, it only stores the requested offset in the related CDbFile object.
       
   870 int CDbFile::Seek(OsFile* aOsFile, i64 aOffset)
       
   871     {
       
   872     //Symbian OS supports 32 bit file size only!
       
   873     __ASSERT_DEBUG((TInt32)aOffset == aOffset, User::Panic(KPanicCategory, EPanicOffset64bit));
       
   874 #ifdef SQLITE_TEST
       
   875     if(aOffset) 
       
   876         {
       
   877         SimulateDiskfullError;
       
   878         }
       
   879 #endif
       
   880     SEEK((TInt)(aOffset / 1024 + 1));   
       
   881     CDbFile::Instance(aOsFile).iFilePos = (TInt)aOffset;
       
   882     return SQLITE_OK;
       
   883     }
       
   884 
       
   885 //Make sure all writes to a particular file are committed to disk.
       
   886 int CDbFile::Sync(OsFile *aOsFile, int)
       
   887     {
       
   888     TTlsData& tls = TTlsData::Instance();
       
   889     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   890     
       
   891     TRACE3("SYNC %X lock=%d\n", dbFile.Handle(), dbFile.LockType());
       
   892     
       
   893     INC_COUNTER(TheDbFileIOCounters.iSyncOpCnt);
       
   894     GET_TIME(start);
       
   895     TInt err = dbFile.Flush();
       
   896     ADD_TIME_DIFF(start, TheDbFileIOCounters.iSyncOpTime);
       
   897     
       
   898     tls.SetOsErrorCode(err);
       
   899     return err == KErrNone ? SQLITE_OK : SQLITE_IOERR;
       
   900     }
       
   901 
       
   902 //Truncate an open file to a specified size
       
   903 //This operation invalidates iFilePos!!!
       
   904 int CDbFile::Truncate(OsFile *aOsFile, i64 aOffset)
       
   905     {
       
   906     TTlsData& tls = TTlsData::Instance();
       
   907     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   908     //Symbian OS supports 32 bit file size only!
       
   909     __ASSERT_DEBUG((TInt32)aOffset == aOffset, User::Panic(KPanicCategory, EPanicOffset64bit));
       
   910     TInt32 offset32 = (TInt)aOffset;//Symbian OS supports 32 bit file size only!
       
   911     TRACE3("TRUNCATE %X %d\n", dbFile.Handle(), offset32);
       
   912     SimulateIOError(SQLITE_IOERR);
       
   913     
       
   914     GET_TIME(start);
       
   915     TInt err = dbFile.SetSize(offset32);
       
   916     ADD_TIME_DIFF(start, TheDbFileIOCounters.iTruncateOpTime);
       
   917     INC_COUNTER(TheDbFileIOCounters.iTruncateOpCnt);
       
   918     
       
   919     tls.SetOsErrorCode(err);
       
   920     if(err == KErrNone)
       
   921         {
       
   922         dbFile.iFilePos = -1;
       
   923         dbFile.iFileSize = offset32;
       
   924         return SQLITE_OK;
       
   925         }
       
   926     return SQLITE_IOERR;    
       
   927     }
       
   928 
       
   929 //Determine the current size of a file in bytes
       
   930 int CDbFile::FileSize(OsFile *aOsFile, i64 *aSize)
       
   931     {
       
   932     TTlsData& tls = TTlsData::Instance();
       
   933     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   934     
       
   935     SimulateIOError(SQLITE_IOERR);
       
   936         
       
   937     TInt size32 = 0;//Symbian OS supports 32 bit file size only!
       
   938     
       
   939     GET_TIME(start);
       
   940     TInt err = dbFile.Size(size32);
       
   941     ADD_TIME_DIFF(start, TheDbFileIOCounters.iFileSizeOpTime);
       
   942     *aSize = size32;
       
   943     INC_COUNTER(TheDbFileIOCounters.iFileSizeOpCnt);
       
   944     
       
   945     tls.SetOsErrorCode(err);
       
   946     return err == KErrNone ? SQLITE_OK : SQLITE_IOERR;
       
   947     }
       
   948 
       
   949 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   950 //////////          FILE LOCKING - SERVER              ////////////////////////////////////////////////////////
       
   951 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   952 
       
   953 // - SERVER
       
   954 //Lock the file with the lock specified by parameter locktype - one
       
   955 //of the following:
       
   956 //
       
   957 //     (1) SHARED_LOCK
       
   958 //     (2) RESERVED_LOCK
       
   959 //     (3) PENDING_LOCK
       
   960 //     (4) EXCLUSIVE_LOCK
       
   961 //
       
   962 //Sometimes when requesting one lock state, additional lock states
       
   963 //are inserted in between.  The locking might fail on one of the later
       
   964 //transitions leaving the lock state different from what it started but
       
   965 //still short of its goal.  The following chart shows the allowed
       
   966 //transitions and the inserted intermediate states:
       
   967 //
       
   968 //   UNLOCKED -> SHARED
       
   969 //   SHARED -> RESERVED
       
   970 //   SHARED -> (PENDING) -> EXCLUSIVE
       
   971 //   RESERVED -> (PENDING) -> EXCLUSIVE
       
   972 //   PENDING -> EXCLUSIVE
       
   973 //
       
   974 //This routine will only increase a lock.  The sqlite3OsUnlock() routine
       
   975 //erases all locks at once and returns us immediately to locking level 0.
       
   976 //It is not possible to lower the locking level one step at a time.  You
       
   977 //must go straight to locking level 0.
       
   978 //This happens on the server side, which is a single threaded process - no need of a file locking/unlocking.
       
   979 int CDbFile::Lock(OsFile *aOsFile, int aLockType)
       
   980     {
       
   981     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   982     //If there is already a lock of this type or more restrictive on the OsFile, do nothing.
       
   983     if(dbFile.LockType() >= aLockType)
       
   984         {
       
   985         return SQLITE_OK;
       
   986         }
       
   987     dbFile.SetLockType(aLockType);
       
   988     return SQLITE_OK;
       
   989     }
       
   990 
       
   991 // - SERVER
       
   992 //This routine checks if there is a RESERVED lock held on the specified
       
   993 //file by this or any other process. If such a lock is held, return
       
   994 //non-zero, otherwise zero.
       
   995 //This happens on the server side, which is a single threaded process - no need of a file locking/unlocking.
       
   996 int CDbFile::CheckReservedLock(OsFile *aOsFile)
       
   997     {
       
   998     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
   999     return dbFile.LockType() >= RESERVED_LOCK ? 1 : 0;
       
  1000     }
       
  1001 
       
  1002 // - SERVER
       
  1003 //Lower the locking level on file descriptor id to locktype.  locktype
       
  1004 //must be either NO_LOCK or SHARED_LOCK.
       
  1005 //
       
  1006 //If the locking level of the file descriptor is already at or below
       
  1007 //the requested locking level, this routine is a no-op.
       
  1008 //
       
  1009 //This happens on the server side, which is a single threaded process - no need of a file locking/unlocking.
       
  1010 int CDbFile::Unlock(OsFile *aOsFile, int aLockType)
       
  1011     {
       
  1012     CDbFile& dbFile = CDbFile::Instance(aOsFile);
       
  1013     dbFile.SetLockType(aLockType);
       
  1014     return SQLITE_OK;
       
  1015     }
       
  1016     
       
  1017 // The fullSync option is meaningless on Symbian. This is a no-op.
       
  1018 void CDbFile::SetFullSync(OsFile*, int)
       
  1019     {
       
  1020     }
       
  1021 
       
  1022 // Return the underlying file handle for an OsFile
       
  1023 int CDbFile::FileHandle(OsFile *aOsFile)
       
  1024     {
       
  1025     return CDbFile::Instance(aOsFile).Handle();
       
  1026     }
       
  1027 
       
  1028 // Return an integer that indices the type of lock currently held
       
  1029 // by this handle.  (Used for testing and analysis only.)
       
  1030 int CDbFile::LockState(OsFile *aOsFile)
       
  1031     {
       
  1032     return  CDbFile::Instance(aOsFile).LockType();
       
  1033     }
       
  1034 
       
  1035 //TheIoMethods holds a pointers to the file functions used later for initialization of 
       
  1036 //OsFile::pMethod data member.
       
  1037 static const IoMethod TheIoMethods = 
       
  1038     {
       
  1039     &CDbFile::Close,
       
  1040     &sqlite3SymbianOpenDirectory,
       
  1041     &CDbFile::Read,
       
  1042     &CDbFile::Write,
       
  1043     &CDbFile::Seek,
       
  1044     &CDbFile::Truncate,
       
  1045     &CDbFile::Sync,
       
  1046     &CDbFile::SetFullSync,
       
  1047     &CDbFile::FileHandle,
       
  1048     &CDbFile::FileSize,
       
  1049     &CDbFile::Lock,
       
  1050     &CDbFile::Unlock,
       
  1051     &CDbFile::LockState,
       
  1052     &CDbFile::CheckReservedLock
       
  1053     };
       
  1054     
       
  1055 CDbFile::CDbFile() :
       
  1056     iFileToBeDeleted(NULL),
       
  1057     iLockType(NO_LOCK),
       
  1058     iFilePos(0),
       
  1059     iFileSize(0)
       
  1060     {
       
  1061     pMethod = &TheIoMethods;
       
  1062     }
       
  1063 
       
  1064 inline CDbFile& CDbFile::Instance(void* aDbFile)
       
  1065     {
       
  1066     __ASSERT_DEBUG(aDbFile != NULL, User::Invariant());
       
  1067     return *(static_cast <CDbFile*> (aDbFile));
       
  1068     }
       
  1069 
       
  1070 ///////////////////////////////////////////////////////////////////////////////////////////
       
  1071 /////////////////////       SQLITE OS proting layer, API definitions    ///////////////////
       
  1072 ///////////////////////////////////////////////////////////////////////////////////////////
       
  1073 
       
  1074 //Delete the named file.
       
  1075 //aFilename is expected to be UTF8 encoded, zero terminated string.
       
  1076 //Although the function returns an integer, representing the error code, it always returns SQLITE_OK
       
  1077 //(To keep it compatible with what the SQLITE library is expecting).
       
  1078 //But if an error occurs while deleting the file, the function will set the returned error code in
       
  1079 //TheOsErrorCode variable, which may be analyzed later by the SQLITE client(s).
       
  1080 int sqlite3SymbianDelete(const char *aFileName)
       
  1081     {
       
  1082     TFhStrType fhStrType = FhStringProps(aFileName);
       
  1083     TFileName fname;
       
  1084     if(ConvertToUnicode(aFileName, fname))
       
  1085         {
       
  1086         GET_TIME(start);
       
  1087         TTlsData& tls = TTlsData::Instance();
       
  1088         if(fhStrType == EFhMainDbStr)
       
  1089             {//Deleting files in somebody else's private data cage - not allowed!
       
  1090             tls.SetOsErrorCode(KErrPermissionDenied);
       
  1091             }
       
  1092         else
       
  1093             {
       
  1094             if(fhStrType == EFhStr)
       
  1095                 {
       
  1096                 FhConvertToFileName(fname, tls.iParse, tls.iSysPrivDir);//If fname does not have a path, iSysPrivDir will be used
       
  1097                 }
       
  1098             tls.SetOsErrorCode(tls.iFs.Delete(fname));
       
  1099             }
       
  1100         ADD_TIME_DIFF(start, TheDbFileIOCounters.iDeleteOpTime);
       
  1101         }
       
  1102     TRACE2("DELETE \"%s\"\n", aFileName);
       
  1103     INC_COUNTER(TheDbFileIOCounters.iDeleteOpCnt);
       
  1104     return SQLITE_OK;
       
  1105     }
       
  1106 
       
  1107 //Return TRUE if the named file exists.
       
  1108 //aFilename is expected to be UTF8 encoded, zero terminated string.
       
  1109 //Returns:
       
  1110 //     0 -  a file with "aFileName" name  does not exist or RFs()::Entry() call failed;
       
  1111 // non-0 -  a file with "aFileName" exists;
       
  1112 int sqlite3SymbianFileExists(const char *aFileName)
       
  1113     {
       
  1114     TFhStrType fhStrType = FhStringProps(aFileName);
       
  1115     TBool res = EFalse;
       
  1116     TFileName fname;
       
  1117     if(ConvertToUnicode(aFileName, fname))
       
  1118         {
       
  1119         GET_TIME(start);
       
  1120         TTlsData& tls = TTlsData::Instance();
       
  1121         if(fhStrType == EFhStr)
       
  1122             {
       
  1123             FhConvertToFileName(fname, tls.iParse, tls.iSysPrivDir);//If fname does not have a path, iSysPrivDir will be used
       
  1124             }
       
  1125         TEntry entry;
       
  1126         res = tls.iFs.Entry(fname, entry) == KErrNone;
       
  1127         ADD_TIME_DIFF(start, TheDbFileIOCounters.iExistOpTime);
       
  1128         }
       
  1129     INC_COUNTER(TheDbFileIOCounters.iExistOpCnt);
       
  1130     return res;
       
  1131     }
       
  1132 
       
  1133 //All possible "file open" operations
       
  1134 enum TOpenFileOpType {EOpenReadWrite, EOpenExclusive, EOpenReadOnly};
       
  1135 
       
  1136 //File open function
       
  1137 //aReadOnly flag is an output parameter, indicating wheter the file was open in read-only mode or not
       
  1138 //It is a non-null pointer only for EOpenReadWrite operations.
       
  1139 static TInt DoOpenFile(TOpenFileOpType aOpType, const char *aFileName, OsFile** aOsFile, int* aReadOnly, int aDeleteOnClose)
       
  1140     {
       
  1141     TFhStrType fhStrType = FhStringProps(aFileName);
       
  1142     TTlsData& tls = TTlsData::Instance();
       
  1143     //Convert the name from UTF8 to UTF16
       
  1144     TFileName fname;
       
  1145     if(!ConvertToUnicode(aFileName, fname))
       
  1146         {
       
  1147         tls.SetOsErrorCode(KErrBadName);
       
  1148         return SQLITE_CANTOPEN; 
       
  1149         }
       
  1150     //Create new, unitialized CDbFile object
       
  1151     CDbFile* dbFile = CDbFile::New();
       
  1152     if(!dbFile)
       
  1153         {
       
  1154         tls.SetOsErrorCode(KErrNoMemory);
       
  1155         return SQLITE_NOMEM;
       
  1156         }
       
  1157     /////////////////////////////////
       
  1158     TInt err = KErrNone;//Symbian OS error
       
  1159     /////////////////////////////////  FILE OPEN/CREATE CODE  BEGIN  /////////////////////////////////////////
       
  1160     GET_TIME(start);
       
  1161     if(fhStrType == EFhMainDbStr)
       
  1162         {//Main db file, open from handle
       
  1163         const RMessage2* msg;
       
  1164         TBool readOnly;
       
  1165         tls.RetrieveAndResetFhData(msg, readOnly);
       
  1166         *aReadOnly = readOnly;
       
  1167         err = msg != NULL ? dbFile->OpenFromHandle(*msg) : KErrGeneral;
       
  1168         }
       
  1169     else
       
  1170         {
       
  1171         if(fhStrType == EFhStr)
       
  1172             {//Not the main db file. Replace invalid characters in the file name
       
  1173             FhConvertToFileName(fname, tls.iParse, tls.iSysPrivDir);//If fname does not have a path, iSysPrivDir will be used
       
  1174             }
       
  1175         //Open for read/write
       
  1176         if(aOpType == EOpenReadWrite)
       
  1177             {
       
  1178             *aReadOnly = 0;
       
  1179             //If the file exists - open it, otherwise - create it.(R/W mode)
       
  1180             //The reason that "Open" and "Create" calls are packed in a "for" loop is:
       
  1181             //1) Current thread calls  dbFile->Open() and the returned error code is KErrNotFound. Then the thread will try to create the file.
       
  1182             //2) But another thread takes the CPU time and creates the file before the curent thread.
       
  1183             //3) Current thread tries to create the file but gets KErrAlreadyExists error code.
       
  1184             //4) Then the current thread has to call dbFile->Open() again to open the file if it already exists.
       
  1185             for(err=KErrAlreadyExists;err==KErrAlreadyExists;)
       
  1186                 {
       
  1187                 if((err = dbFile->Open(fname)) == KErrNotFound)
       
  1188                     {
       
  1189                     err = dbFile->Create(fname);
       
  1190                     }
       
  1191                 }
       
  1192             if(err != KErrNone) 
       
  1193                 {
       
  1194                 TInt prevErr = err;
       
  1195                 err = dbFile->OpenReadOnly(fname);
       
  1196                 if(err == KErrNone)
       
  1197                     {
       
  1198                     *aReadOnly = 1;
       
  1199                     }
       
  1200                 else if(prevErr == KErrAccessDenied) //this is attempt to create a file on a read-only drive
       
  1201                     {
       
  1202                     err = KErrAccessDenied;
       
  1203                     }
       
  1204                 }
       
  1205             }
       
  1206         //Open for exclusive access
       
  1207         else if(aOpType == EOpenExclusive)
       
  1208             {
       
  1209             err = dbFile->CreateExclusive(fname, aDeleteOnClose);
       
  1210             }
       
  1211         //Open for read-only access
       
  1212         else if(aOpType == EOpenReadOnly)
       
  1213             {
       
  1214             err = dbFile->OpenReadOnly(fname);
       
  1215             }
       
  1216         else
       
  1217             {
       
  1218             __ASSERT_DEBUG(0, User::Panic(KPanicCategory, EPanicInvalidOpType));
       
  1219             }
       
  1220         }//end of - "if(fromHandle)"
       
  1221     ADD_TIME_DIFF(start, TheDbFileIOCounters.iOpenOpTime);
       
  1222     /////////////////////////////////  FILE OPEN/CREATE CODE  END    /////////////////////////////////////////
       
  1223     tls.SetOsErrorCode(err);
       
  1224     if(err != KErrNone)
       
  1225         {
       
  1226         delete dbFile;
       
  1227         return err == KErrNoMemory ? SQLITE_NOMEM : SQLITE_CANTOPEN;
       
  1228         }
       
  1229     *aOsFile = dbFile;
       
  1230     OpenCounter(+1);
       
  1231     INC_COUNTER(TheDbFileIOCounters.iOpenOpCnt);
       
  1232     return SQLITE_OK;
       
  1233     }
       
  1234 
       
  1235 // Attempt to open a file for both reading and writing.  If that
       
  1236 // fails, try opening it read-only.  If the file does not exist,
       
  1237 // try to create it.
       
  1238 //
       
  1239 // On success, a handle for the open file is written to *aOsFile
       
  1240 // and *aReadOnly is set to 0 if the file was opened for reading and
       
  1241 // writing or 1 if the file was opened read-only.  The function returns
       
  1242 // SQLITE_OK.
       
  1243 //
       
  1244 // On failure, the function returns SQLITE_CANTOPEN and leaves
       
  1245 // *aOsFile and *aReadOnly unchanged.
       
  1246 int sqlite3SymbianOpenReadWrite(const char *aFileName, OsFile** aOsFile, int* aReadOnly)
       
  1247     {
       
  1248     return DoOpenFile(EOpenReadWrite, aFileName, aOsFile, aReadOnly, 0);
       
  1249     }
       
  1250 
       
  1251 // Attempt to open a new file for exclusive access by this process.
       
  1252 // The file will be opened for both reading and writing.  To avoid
       
  1253 // a potential security problem, we do not allow the file to have
       
  1254 // previously existed.  Nor do we allow the file to be a symbolic
       
  1255 // link.
       
  1256 //
       
  1257 // If aDelFlag is true, then make arrangements to automatically delete
       
  1258 // the file when it is closed.
       
  1259 //
       
  1260 // On success, write the file handle into *aOsFile and return SQLITE_OK.
       
  1261 //
       
  1262 // On failure, return SQLITE_CANTOPEN.
       
  1263 int sqlite3SymbianOpenExclusive(const char *aFileName, OsFile** aOsFile, int aDelFlag)
       
  1264     {
       
  1265     return DoOpenFile(EOpenExclusive, aFileName, aOsFile, NULL, aDelFlag);
       
  1266     }
       
  1267 
       
  1268 // Attempt to open a new file for read-only access.
       
  1269 //
       
  1270 // On success, write the file handle into *aOsFile and return SQLITE_OK.
       
  1271 //
       
  1272 // On failure, return SQLITE_CANTOPEN.
       
  1273 int sqlite3SymbianOpenReadOnly(const char *aFileName, OsFile** aOsFile)
       
  1274     {
       
  1275     return DoOpenFile(EOpenReadOnly, aFileName, aOsFile, NULL, 0);
       
  1276     }
       
  1277 
       
  1278 //Create a temporary file name in aBuf.  aBuf must be big enough to
       
  1279 //hold at least SQLITE_TEMPNAME_SIZE characters.
       
  1280 //After the call aBuf will hold the temporary file name, UTF8 encoded, zero terminated string.
       
  1281 //The function does not use "sqlite3_temp_directory" global variable. All temporary files will
       
  1282 //be created in the process's private data cage.
       
  1283 int sqlite3SymbianTempFileName(char *aBuf)
       
  1284     {
       
  1285     GET_TIME(start);
       
  1286     TBuf<SQLITE_TEMPNAME_SIZE> tmpFileName;
       
  1287     tmpFileName.Copy(TTlsData::Instance().iSysPrivDir);
       
  1288     const TInt KFileNamePos = tmpFileName.Length();
       
  1289     TUint32 randomVal = Math::Random(); 
       
  1290     TInt64 seed = (TInt64)randomVal;
       
  1291     const TInt KFileNameLen = 15;
       
  1292     tmpFileName.SetLength(tmpFileName.Length() + KFileNameLen);
       
  1293     
       
  1294     for(;;)
       
  1295         {
       
  1296         TInt pos = KFileNamePos;
       
  1297         for(TInt i=0;i<KFileNameLen;++i,++pos)
       
  1298             {
       
  1299             TInt j = Math::Rand(seed) % (sizeof(TheChars) - 1);
       
  1300             tmpFileName[pos] = TheChars[j];
       
  1301             }
       
  1302         TTlsData& tls = TTlsData::Instance();
       
  1303         TUint attr;
       
  1304         if(tls.iFs.Att(tmpFileName, attr) == KErrNotFound)
       
  1305             {
       
  1306             break;
       
  1307             }
       
  1308         }
       
  1309 
       
  1310     //No need to convert the temporary file name to its unicode presentation: the file name contains only 
       
  1311     //ASCII characters!!!
       
  1312     TPtr8 dest(reinterpret_cast <TUint8*> (aBuf), SQLITE_TEMPNAME_SIZE);
       
  1313     dest.Copy(tmpFileName);
       
  1314     dest.Append(TChar(0));
       
  1315     
       
  1316     ADD_TIME_DIFF(start, TheDbFileIOCounters.iTempFileNameOpTime);
       
  1317     INC_COUNTER(TheDbFileIOCounters.iTempFileNameOpCnt);
       
  1318     TRACE2("TEMP FILENAME: %s\n", aBuf);
       
  1319     return SQLITE_OK; 
       
  1320     }
       
  1321 
       
  1322 //Sync the directory zDirname. This is a no-op on operating systems other
       
  1323 //than UNIX.
       
  1324 int sqlite3SymbianSyncDirectory(const char* /*aDirName*/)
       
  1325     {
       
  1326     SimulateIOError(SQLITE_IOERR);
       
  1327     return SQLITE_OK;
       
  1328     }
       
  1329     
       
  1330 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
       
  1331 
       
  1332 //Check that a given pathname is a directory and is writable.
       
  1333 //aDirName is expected to be UTF8 encoded, zero terminated string.
       
  1334 int sqlite3SymbianIsDirWritable(char *aDirName)
       
  1335     {
       
  1336     int res = 0;
       
  1337     TFileName dirName;
       
  1338     if(ConvertToUnicode(aDirName, dirName))
       
  1339         {
       
  1340         GET_TIME(start);
       
  1341         TEntry entry;
       
  1342         if(TTlsData::Instance().iFs.Entry(dirName, entry) == KErrNone)
       
  1343             {
       
  1344             if(entry.IsDir() && !entry.IsReadOnly())
       
  1345                 {
       
  1346                 res = 1;    
       
  1347                 }
       
  1348             }
       
  1349         ADD_TIME_DIFF(start, TheDbFileIOCounters.iIsDirWOpTime);
       
  1350         }
       
  1351     INC_COUNTER(TheDbFileIOCounters.iIsDirWOpCnt);
       
  1352     
       
  1353     return res;
       
  1354     }
       
  1355 
       
  1356 #endif//SQLITE_OMIT_PAGER_PRAGMAS
       
  1357 
       
  1358 //Turn a relative pathname into a full pathname.  Return a pointer
       
  1359 //to the full pathname stored in space obtained from sqliteMalloc().
       
  1360 //The calling function is responsible for freeing this space once it
       
  1361 //is no longer needed.
       
  1362 //
       
  1363 //The input file name is expected to be UTF8, zero-terminated. The output file name will be UTF8, zero-terminated.
       
  1364 char *sqlite3SymbianFullPathname(const char *aRelative)
       
  1365     {
       
  1366     TTlsData& tls = TTlsData::Instance();
       
  1367     tls.StoreFhData(NULL, EFalse);
       
  1368     if(!aRelative)  //NULL argument
       
  1369         {
       
  1370         return 0;
       
  1371         }
       
  1372     TFhStrType strType = FhStringProps(aRelative);//Detect string type - it may not be a real file name
       
  1373     //Convert the received file name to UTF16
       
  1374     TBuf<KMaxFileName + 1> fname;
       
  1375     if(!ConvertToUnicode(aRelative, fname))
       
  1376         {
       
  1377         return 0;
       
  1378         }
       
  1379     //Zero-terminate the converted file name
       
  1380     fname.Append(TChar(0));
       
  1381     char* result = static_cast <char*> (sqliteMalloc(KMaxFileName + 1));
       
  1382     if(!result)
       
  1383         {
       
  1384         return 0;
       
  1385         }
       
  1386     //    If the format of aRelative argument is <[SID]FileName.[EXT]>, then the database file name will be 
       
  1387     //treated as a name of a secure database file which has to be created/opened in the server's private 
       
  1388     //directory on the system drive.
       
  1389     //    If the format of aRelative argument is <Drive:[SID]FileName.[EXT]>, then the database file name 
       
  1390     //will be treated as a name of a secure database file which has to be created/opened in the server's 
       
  1391     //private directory on <Drive:> drive. 
       
  1392     //    If the format of aRelative argument is <Drive:\Path\FileName.[EXT]>, then the database file name
       
  1393     //will be treated as a name of a non-secure database file in <Drive:\Path\> directory.
       
  1394     //    If aRelative contains file handles, then it will be treated as a name of a file belonging to server's
       
  1395     //private data cage. 
       
  1396     if(strType == EFhMainDbStr)
       
  1397         {//The additonal information has to be extracted and fnmae reformatted, because SQLITE will
       
  1398          //use the returned full file name when making a decission to share the cache.
       
  1399         FhExtractAndStore(fname, tls);
       
  1400         (void)tls.iParse.Set(fname, 0, 0);//the file name has to be verified by the server
       
  1401         }
       
  1402     else
       
  1403         {
       
  1404         (void)tls.iParse.Set(fname, &tls.iSysPrivDir, 0);//If fname does not have a path, iSysPrivDir will be used
       
  1405         }
       
  1406     TPtr8 dest8(reinterpret_cast <TUint8*> (result), KMaxFileName + 1); 
       
  1407     if(!ConvertFromUnicode(tls.iParse.FullName(), dest8))
       
  1408         {
       
  1409         tls.StoreFhData(NULL, EFalse);
       
  1410         sqliteFree(result);
       
  1411         return 0;   
       
  1412         }
       
  1413     return result;
       
  1414     }
       
  1415 
       
  1416 // ***************************************************************************
       
  1417 // ** Everything above deals with file I/O.  Everything that follows deals
       
  1418 // ** with other miscellanous aspects of the operating system interface
       
  1419 // ***************************************************************************
       
  1420 
       
  1421 //Get information to seed the random number generator.  The seed
       
  1422 //is written into the buffer aBuf[256].  The calling function must
       
  1423 //supply a sufficiently large buffer.
       
  1424 int sqlite3SymbianRandomSeed(char *aBuf)
       
  1425     {
       
  1426     //We have to initialize aBuf to prevent valgrind from reporting
       
  1427     //errors.  The reports issued by valgrind are incorrect - we would
       
  1428     //prefer that the randomness be increased by making use of the
       
  1429     //uninitialized space in aBuf - but valgrind errors tend to worry
       
  1430     //some users.  Rather than argue, it seems easier just to initialize
       
  1431     //the whole array and silence valgrind, even if that means less randomness
       
  1432     //in the random seed.
       
  1433     //
       
  1434     //When testing, initializing aBuf[] to zero is all we do.  That means
       
  1435     //that we always use the same random number sequence.* This makes the
       
  1436     //tests repeatable.
       
  1437     Mem::FillZ(aBuf, 256);
       
  1438     TUint32 randomVal[2];
       
  1439     randomVal[0] = Math::Random();
       
  1440     randomVal[1] = Math::Random();
       
  1441     Mem::Copy(aBuf, randomVal, sizeof(randomVal));
       
  1442     return SQLITE_OK;
       
  1443     }
       
  1444 
       
  1445 //Sleep for a little while.  Return the amount of time slept.
       
  1446 int sqlite3SymbianSleep(int ms)
       
  1447     {
       
  1448     User::AfterHighRes(TTimeIntervalMicroSeconds32(ms * 1000));
       
  1449     return ms;
       
  1450     }
       
  1451 
       
  1452 //The following pair of routine implement mutual exclusion for
       
  1453 //multi-threaded processes.  Only a single thread is allowed to
       
  1454 //executed code that is surrounded by EnterMutex() and LeaveMutex().
       
  1455 //
       
  1456 //SQLite uses only a single Mutex.  There is not much critical
       
  1457 //code and what little there is executes quickly and without blocking.
       
  1458 //
       
  1459 //Version 3.3.1 and earlier used a simple mutex.  Beginning with
       
  1460 //version 3.3.2, a recursive mutex is required.
       
  1461 void sqlite3SymbianEnterMutex()
       
  1462     {
       
  1463     ++TheMutexRefCounter;
       
  1464     }
       
  1465     
       
  1466 void sqlite3SymbianLeaveMutex()
       
  1467     {
       
  1468     --TheMutexRefCounter;
       
  1469     }
       
  1470 
       
  1471 //Return TRUE if the mutex is currently held.
       
  1472 //
       
  1473 //If the thisThreadOnly parameter is true, return true if and only if the
       
  1474 //calling thread holds the mutex.  If the parameter is false, return
       
  1475 //true if any thread holds the mutex.
       
  1476 int sqlite3SymbianInMutex(int /*aThisThreadOnly*/)
       
  1477     {
       
  1478     return TheMutexRefCounter > 0;
       
  1479     }
       
  1480 
       
  1481 /*
       
  1482 ** The following variable, if set to a non-zero value, becomes the result
       
  1483 ** returned from sqlite3OsCurrentTime().  This is used for testing.
       
  1484 */
       
  1485 #ifdef SQLITE_TEST
       
  1486 int sqlite3_current_time = 0;
       
  1487 #endif
       
  1488 
       
  1489 //Find the current time (in Universal Coordinated Time).  Write the
       
  1490 //current time and date as a Julian Day number into *prNow and
       
  1491 //return 0.  Return 1 if the time and date cannot be found.
       
  1492 int sqlite3SymbianCurrentTime(double *prNow)
       
  1493     {
       
  1494     TTime now;
       
  1495     now.UniversalTime();
       
  1496     TDateTime date = now.DateTime();
       
  1497     TInt year = date.Year(), month = date.Month() + 1, day = date.Day() + 1;
       
  1498     
       
  1499     TInt jd = ( 1461 * ( year + 4800 + ( month - 14 ) / 12 ) ) / 4 +
       
  1500           ( 367 * ( month - 2 - 12 * ( ( month - 14 ) / 12 ) ) ) / 12 -
       
  1501           ( 3 * ( ( year + 4900 + ( month - 14 ) / 12 ) / 100 ) ) / 4 +
       
  1502           day - 32075;
       
  1503           
       
  1504     *prNow = jd;
       
  1505 #ifdef SQLITE_TEST
       
  1506     if( sqlite3_current_time )
       
  1507         {
       
  1508         *prNow = sqlite3_current_time / 86400.0 + 2440587.5;
       
  1509         }
       
  1510 #endif
       
  1511   return 0;
       
  1512 }
       
  1513 
       
  1514 static TInt TlsHandle2()
       
  1515     {
       
  1516     return reinterpret_cast <TInt> (&TlsHandle2);
       
  1517     }
       
  1518 
       
  1519 // If called with aAllocateFlag>1, then return a pointer to thread
       
  1520 // specific data for the current thread.  Allocate and zero the
       
  1521 // thread-specific data if it does not already exist necessary.
       
  1522 //
       
  1523 // If called with aAllocateFlag==0, then check the current thread
       
  1524 // specific data.  Return it if it exists.  If it does not exist,
       
  1525 // then return NULL.
       
  1526 //
       
  1527 // If called with aAllocateFlag<0, check to see if the thread specific
       
  1528 // data is allocated and is all zero.  If it is then deallocate it.
       
  1529 // Return a pointer to the thread specific data or NULL if it is
       
  1530 // unallocated or gets deallocated.
       
  1531 ThreadData* sqlite3SymbianThreadSpecificData(int aAllocateFlag)
       
  1532     {
       
  1533     ThreadData* data = static_cast <ThreadData*> (UserSvr::DllTls(TlsHandle2()));
       
  1534     if(aAllocateFlag > 0)
       
  1535         {
       
  1536         if(!data)
       
  1537             {
       
  1538             data = static_cast <ThreadData*> (sqlite3OsMalloc(sizeof(ThreadData)));
       
  1539             if(data)
       
  1540                 {
       
  1541                 Mem::FillZ(data, sizeof(ThreadData));
       
  1542                 TTlsData& tls = TTlsData::Instance();
       
  1543                 TInt err = UserSvr::DllSetTls(TlsHandle2(), data);
       
  1544                 tls.SetOsErrorCode(err);
       
  1545                 if(err != KErrNone)
       
  1546                     {
       
  1547                     sqlite3OsFree(data);
       
  1548                     return 0;
       
  1549                     }
       
  1550                 }
       
  1551             }
       
  1552         }
       
  1553     else if(data != 0 && aAllocateFlag < 0)
       
  1554         {
       
  1555         if(Mem::Compare(reinterpret_cast <const TUint8*> (data), sizeof(ThreadData), 
       
  1556                         reinterpret_cast <const TUint8*> (&TheZeroThreadData), sizeof(ThreadData)) == 0)
       
  1557             {
       
  1558             sqlite3OsFree(data);
       
  1559             data = 0;
       
  1560             (void)UserSvr::DllSetTls(TlsHandle2(), 0);
       
  1561             }
       
  1562         }
       
  1563     return data;
       
  1564     }
       
  1565 
       
  1566 ///////////////////////////////////////////////////////////////////////////////////////////
       
  1567 /////////////////////       SQLITE OS proting layer      //////////////////////////////////
       
  1568 ////////////////////       memory allocation routines    //////////////////////////////////
       
  1569 ///////////////////////////////////////////////////////////////////////////////////////////
       
  1570 
       
  1571 #ifdef __MEM_TRACE__
       
  1572 
       
  1573 ////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1574 
       
  1575 static TInt TheMallocCount = 0;
       
  1576 static TInt TheReallocCount = 0;
       
  1577 static TInt TheFreeCount = 0;
       
  1578 static TInt TheAllocSizeCount = 0;
       
  1579 static TInt TheTotalAllocated = 0;
       
  1580 static TInt TheTotalFreed = 0;
       
  1581 
       
  1582 /**
       
  1583 */
       
  1584 void* sqlite3SymbianMalloc(int aSize)
       
  1585     {
       
  1586     void* res = TheAllocator->Alloc(aSize);
       
  1587     TInt len = res ? TheAllocator->AllocLen(res) : 0;
       
  1588     RDebug::Print(_L("*** OS MALLOC: Size=%d, rounded=%d, p=%X\r\n"), aSize, len, res);
       
  1589     ++TheMallocCount;
       
  1590     return res;
       
  1591     }
       
  1592     
       
  1593 /**
       
  1594 */
       
  1595 void* sqlite3SymbianRealloc(void* aPtr, int aSize)
       
  1596     {
       
  1597     TInt oldSize = aPtr ? TheAllocator->AllocLen(aPtr) : 0;
       
  1598     void* res = TheAllocator->ReAlloc(aPtr, aSize);
       
  1599     RDebug::Print(_L("*** OS REALLOC: Old size=%d, Size=%d, p_old=%X, p_new=%X\r\n"), oldSize, aSize, aPtr, res);
       
  1600     ++TheReallocCount;
       
  1601     return res;
       
  1602     }
       
  1603     
       
  1604 /**
       
  1605 */
       
  1606 void sqlite3SymbianFree(void* aPtr)
       
  1607     {
       
  1608     TInt len = aPtr ? TheAllocator->AllocLen(aPtr) : 0;
       
  1609     RDebug::Print(_L("*** OS FREE: size=%d, p=%X\r\n"), len, aPtr);
       
  1610     TheAllocator->Free(aPtr);
       
  1611     ++TheFreeCount;
       
  1612     TheTotalFreed += len;   
       
  1613     }
       
  1614     
       
  1615 /**
       
  1616 */
       
  1617 int sqlite3SymbianAllocationSize(void* aPtr)
       
  1618     {
       
  1619     TInt len = aPtr ? TheAllocator->AllocLen(aPtr) : 0;
       
  1620     RDebug::Print(_L("*** OS ALLOCSIZE: Size=%d, p=%X\r\n"), len, aPtr);
       
  1621     ++TheAllocSizeCount;
       
  1622     return len;
       
  1623     }
       
  1624 
       
  1625 /**
       
  1626 */
       
  1627 void sqlite3SymbianPrintMemCounters(void)
       
  1628     {
       
  1629     RDebug::Print(_L("*** OS MALLOC COUNT=%d\r\n"), TheMallocCount);
       
  1630     RDebug::Print(_L("*** OS REALLOC COUNT=%d\r\n"), TheReallocCount);
       
  1631     RDebug::Print(_L("*** OS FREE COUNT=%d\r\n"), TheFreeCount);
       
  1632     RDebug::Print(_L("*** OS ALLOCSIZE COUNT=%d\r\n"), TheAllocSizeCount);
       
  1633     RDebug::Print(_L("*** OS TOTAL ALLOCATED=%d\r\n"), TheTotalAllocated);
       
  1634     RDebug::Print(_L("*** OS TOTAL FREED=%d\r\n"), TheTotalFreed);
       
  1635     }
       
  1636 
       
  1637 /**
       
  1638 */
       
  1639 void sqlite3SymbianResetMemCounters(void)
       
  1640     {
       
  1641     TheMallocCount = TheReallocCount = TheFreeCount = TheAllocSizeCount = 0;
       
  1642     }
       
  1643 
       
  1644 ////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1645 
       
  1646 #else //__MEM_TRACE__
       
  1647 
       
  1648 ////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1649 
       
  1650 /**
       
  1651 */
       
  1652 void* sqlite3SymbianMalloc(int aSize)
       
  1653     {
       
  1654     return TheAllocator->Alloc(aSize);
       
  1655     }
       
  1656     
       
  1657 /**
       
  1658 */
       
  1659 void* sqlite3SymbianRealloc(void* aPtr, int aSize)
       
  1660     {
       
  1661     return TheAllocator->ReAlloc(aPtr, aSize);
       
  1662     }
       
  1663     
       
  1664 /**
       
  1665 */
       
  1666 void sqlite3SymbianFree(void* aPtr)
       
  1667     {
       
  1668     TheAllocator->Free(aPtr);
       
  1669     }
       
  1670     
       
  1671 /**
       
  1672 */
       
  1673 int sqlite3SymbianAllocationSize(void* aPtr)
       
  1674     {
       
  1675     return aPtr ? TheAllocator->AllocLen(aPtr) : 0;
       
  1676     }
       
  1677 
       
  1678 ////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1679 
       
  1680 #endif//__MEM_TRACE__
       
  1681 
       
  1682 ////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1683 
       
  1684 #endif//OS_SYMBIAN