diff -r 5f8e5adbbed9 -r 29cda98b007e engine/sqlite/src/os_symbian.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/sqlite/src/os_symbian.cpp Thu Feb 25 14:29:19 2010 +0000 @@ -0,0 +1,616 @@ +/* +** 2008 February 09 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code that is specific to windows. +*/ +#include "sqliteInt.h" +#if OS_SYMBIAN /* This file is used for symbian only */ + +#define MAX_PATH 260 +/* +** A Note About Memory Allocation: +** +** This driver uses malloc()/free() directly rather than going through +** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers +** are designed for use on embedded systems where memory is scarce and +** malloc failures happen frequently. Win32 does not typically run on +** embedded systems, and when it does the developers normally have bigger +** problems to worry about than running out of memory. So there is not +** a compelling need to use the wrappers. +** +** But there is a good reason to not use the wrappers. If we use the +** wrappers then we will get simulated malloc() failures within this +** driver. And that causes all kinds of problems for our tests. We +** could enhance SQLite to deal with simulated malloc failures within +** the OS driver, but the code to deal with those failure would not +** be exercised on Linux (which does not need to malloc() in the driver) +** and so we would have difficulty writing coverage tests for that +** code. Better to leave the code out, we think. +** +** The point of this discussion is as follows: When creating a new +** OS layer for an embedded system, if you use this file as an example, +** avoid the use of malloc()/free(). Those routines work ok on windows +** desktops but not so well in embedded systems. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* +** Macros used to determine whether or not to use threads. +*/ +#if defined(THREADSAFE) && THREADSAFE +# define SQLITE_W32_THREADS 1 +#endif + +/* +** Include code that is common to all os_*.c files +*/ +#include "os_common.h" + +/* +** The symbianFile structure is a subclass of sqlite3_file* specific to the win32 +** portability layer. +*/ + +typedef struct symbianFile symbianFile; +struct symbianFile { + int isOpen; + unsigned char locktype; /* Type of lock currently held on this file */ + short sharedLockByte; /* Randomly chosen byte used as a shared lock */ + char fileName[512]; + RFs session; + RFile file; +}; + +/***************************************************************************** +** The next group of routines implement the I/O methods specified +** by the sqlite3_io_methods object. +******************************************************************************/ + +/* +** Close a file. +** +** It is reported that an attempt to close a handle might sometimes +** fail. This is a very unreasonable result, but windows is notorious +** for being unreasonable so I do not doubt that it might happen. If +** the close fails, we pause for 100 milliseconds and try again. As +** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before +** giving up and returning an error. +*/ +#define MX_CLOSE_ATTEMPT 3 +int winClose(sqlite3_file *id){ + int rc, cnt = 0; + symbianFile *pFile = (symbianFile*)id; + pFile->file.Close(); + pFile->session.Close(); + return SQLITE_OK; +} + +/* +** Some microsoft compilers lack this definition. +*/ +#ifndef INVALID_SET_FILE_POINTER +# define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +/* +** Read data from a file into a buffer. Return SQLITE_OK if all +** bytes were read successfully and SQLITE_IOERR if anything goes +** wrong. +*/ +int winRead( + sqlite3_file *id, /* File to read from */ + void *pBuf, /* Write content into this buffer */ + int amt, /* Number of bytes to read */ + sqlite3_int64 offset /* Begin reading at this offset */ +){ + int rc; + size_t got; + symbianFile *pFile = (symbianFile*)id; + assert( id!=0 ); + SimulateIOError(return SQLITE_IOERR_READ); + TInt tOffset = (TInt)offset; + rc = pFile->file.Seek(ESeekStart, tOffset); + if( rc!= KErrNone){ + return SQLITE_FULL; + } + + HBufC8* buf = HBufC8::NewL(amt) ; + TPtr8 ptr = buf->Des(); + + if (pFile->file.Read(ptr, amt) != KErrNone) + { + delete buf; + return SQLITE_IOERR_READ; + } + + got = buf->Length(); + + if( got == 0 ){ + delete buf; + TInt size = 0; + if (pFile->file.Size(size) != KErrNone) + { + return SQLITE_IOERR_READ; + } + if (size == 0) + { + return SQLITE_IOERR_SHORT_READ; + } + return SQLITE_IOERR_READ; + } + memcpy(pBuf, ptr.Ptr(), got); + delete buf; + if( got == amt ){ + return SQLITE_OK; + }else{ + memset(&((char*)pBuf)[got], 0, amt-got); + return SQLITE_IOERR_SHORT_READ; + } +} + +/* +** Write data from a buffer into a file. Return SQLITE_OK on success +** or some other error code on failure. +*/ +int winWrite( + sqlite3_file *id, /* File to write into */ + const void *pBuf, /* The bytes to be written */ + int amt, /* Number of bytes to write */ + sqlite3_int64 offset /* Offset into the file to begin writing at */ +){ + int rc; + symbianFile *pFile = (symbianFile*)id; + assert( id!=0 ); + SimulateIOError(return SQLITE_IOERR_WRITE); + SimulateDiskfullError(return SQLITE_FULL); + TInt tOffset = (TInt)offset; + rc = pFile->file.Seek(ESeekStart, tOffset); + if( rc!= KErrNone){ + return SQLITE_FULL; + } + + assert( amt>0 ); + + rc = SQLITE_OK; + TPtrC8 ptr((TUint8 *)pBuf,amt); + + if (pFile->file.Write(ptr, amt) != KErrNone) rc = SQLITE_FULL; + + return rc; +} + +/* +** Truncate an open file to a specified size +*/ +int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ + symbianFile *pFile = (symbianFile*)id; + + if (pFile->file.SetSize(nByte) != KErrNone) + { + return SQLITE_IOERR; + } + + return SQLITE_OK; +} + +#ifdef SQLITE_TEST +/* +** Count the number of fullsyncs and normal syncs. This is used to test +** that syncs and fullsyncs are occuring at the right times. +*/ +int sqlite3_sync_count = 0; +int sqlite3_fullsync_count = 0; +#endif + +/* +** Make sure all writes to a particular file are committed to disk. +*/ +int winSync(sqlite3_file *id, int flags){ + symbianFile *pFile = (symbianFile*)id; + OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype); +#ifdef SQLITE_TEST + if( flags & SQLITE_SYNC_FULL ){ + sqlite3_fullsync_count++; + } + sqlite3_sync_count++; +#endif + TInt error = pFile->file.Flush(); + if (error != KErrNone) + { + return SQLITE_IOERR; + }else{ + return SQLITE_OK; + } +} + +/* +** Determine the current size of a file in bytes +*/ +int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ + symbianFile *pFile = (symbianFile*)id; + + TInt size = 0; + if (pFile->file.Size(size) != KErrNone) + { + return SQLITE_IOERR; + } + + *pSize = size; + + return SQLITE_OK; +} + + +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. The winUnlock() routine +** erases all locks at once and returns us immediately to locking level 0. +** It is not possible to lower the locking level one step at a time. You +** must go straight to locking level 0. +*/ +int winLock(sqlite3_file *id, int locktype){ + int rc = SQLITE_OK; /* Return code from subroutines */ + int res = 1; /* Result of a windows lock call */ + int newLocktype; /* Set pFile->locktype to this value before exiting */ + int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ + symbianFile *pFile = (symbianFile*)id; + + assert( pFile!=0 ); + OSTRACE5("LOCK %d %d was %d(%d)\n", + pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); + + // one smartphone only one application can control the database + + TInt size = 0; + if (pFile->file.Size(size) == KErrNone) return SQLITE_OK; + + return SQLITE_BUSY; +} + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, return +** non-zero, otherwise zero. +*/ +int winCheckReservedLock(sqlite3_file *id){ + int rc; + symbianFile *pFile = (symbianFile*)id; + assert( pFile!=0 ); + if( pFile->locktype>=RESERVED_LOCK ){ + rc = 1; + OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); + }else{ + TInt size = 0; + if (pFile->file.Size(size) == KErrNone) rc = 1; + OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); + } + return rc; +} + +/* +** Lower the locking level on file descriptor id to locktype. locktype +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +** +** It is not possible for this routine to fail if the second argument +** is NO_LOCK. If the second argument is SHARED_LOCK then this routine +** might return SQLITE_IOERR; +*/ +int winUnlock(sqlite3_file *id, int locktype){ + int type; + symbianFile *pFile = (symbianFile*)id; + int rc = SQLITE_OK; + assert( pFile!=0 ); + return rc; +} + +/* +** Control and query of the open file handle. +*/ +int winFileControl(sqlite3_file *id, int op, void *pArg){ + switch( op ){ + case SQLITE_FCNTL_LOCKSTATE: { + *(int*)pArg = ((symbianFile*)id)->locktype; + return SQLITE_OK; + } + } + return SQLITE_ERROR; +} + +/* +** Return the sector size in bytes of the underlying block device for +** the specified file. This is almost always 512 bytes, but may be +** larger for some devices. +** +** SQLite code assumes this function cannot fail. It also assumes that +** if two files are created in the same file-system directory (i.e. +** a database and its journal file) that the sector size will be the +** same for both. +*/ +int winSectorSize(sqlite3_file *id){ + return SQLITE_DEFAULT_SECTOR_SIZE; +} + +/* +** Return a vector of device characteristics. +*/ +int winDeviceCharacteristics(sqlite3_file *id){ + return 0; +} + + +/*************************************************************************** +** Here ends the I/O methods that form the sqlite3_io_methods object. +** +** The next block of code implements the VFS methods. +****************************************************************************/ + +void ConvertToUnicode(RFs session, TDes16& aUnicode, const char *str) +{ + CCnvCharacterSetConverter *converter = CCnvCharacterSetConverter::NewL(); + converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierUtf8, session); + + TPtrC8 ptr((const unsigned char*)str); + + int state = CCnvCharacterSetConverter::KStateDefault; + converter->ConvertToUnicode(aUnicode, ptr, state); + delete converter; +} + +/* +** Open a file. +*/ +int winOpen( + sqlite3_vfs *pVfs, /* Not used */ + const char *zName, /* Name of the file (UTF-8) */ + sqlite3_file *id, /* Write the SQLite file handle here */ + int flags, /* Open mode flags */ + int *pOutFlags /* Status return flags */ +){ + symbianFile *pFile = (symbianFile*)id; + TBuf16 filename; + + pFile->isOpen = 0; + memset(pFile, 0, sizeof(*pFile)); + strcpy(pFile->fileName, zName); + pFile->session.Connect(); + + ConvertToUnicode(pFile->session, filename, zName); + + int ret = 0; + if( flags & SQLITE_OPEN_CREATE ){ + if (BaflUtils::FileExists(pFile->session, filename) == 1) + { + ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileWrite); + } + else + { + ret = pFile->file.Create(pFile->session, filename, EFileStream | EFileWrite); + } + } + else + if( flags & SQLITE_OPEN_READWRITE ){ + ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileWrite); + }else{ + ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileRead); + } + + OpenCounter(+1); + + if (ret != KErrNone) + { + return SQLITE_IOERR; + } + + pFile->isOpen = 1; + return SQLITE_OK; +} + +/* +** Delete the named file. +** +** Note that windows does not allow a file to be deleted if some other +** process has it open. Sometimes a virus scanner or indexing program +** will open a journal file shortly after it is created in order to do +** whatever does. While this other process is holding the +** file open, we will be unable to delete it. To work around this +** problem, we delay 100 milliseconds and try to delete again. Up +** to MX_DELETION_ATTEMPTs deletion attempts are run before giving +** up and returning an error. +*/ +#define MX_DELETION_ATTEMPTS 5 +int winDelete( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to delete */ + int syncDir /* Not used on win32 */ +){ + SimulateIOError(return SQLITE_IOERR_DELETE); + TBuf16 filename; + + RFs session; + session.Connect(); + ConvertToUnicode(session, filename, zFilename); + BaflUtils::DeleteFile(session, filename); + OSTRACE2("DELETE \"%s\"\n", zFilename); + session.Close(); + return SQLITE_OK; +} + +/* +** Check the existance and status of a file. +*/ +int winAccess( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to check */ + int flags /* Type of test to make on this file */ +){ + TBuf16 filename; + + RFs session; + session.Connect(); + ConvertToUnicode(session, filename, zFilename); + int ret = BaflUtils::FileExists(session, filename); + session.Close(); + + return ret; +} + + +/* +** Create a temporary file name in zBuf. zBuf must be big enough to +** hold at pVfs->mxPathname characters. +*/ +int winGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + static char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + char zTempPath[MAX_PATH+1]; + if( sqlite3_temp_directory ){ + sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); + } + else + { + } + + for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} + zTempPath[i] = 0; + sqlite3_snprintf(nBuf-30, zBuf, + "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); + j = strlen(zBuf); + sqlite3Randomness(20, &zBuf[j]); + for(i=0; i<20; i++, j++){ + zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + } + zBuf[j] = 0; + OSTRACE2("TEMP FILENAME: %s\n", zBuf); + return SQLITE_OK; +} + +/* +** Turn a relative pathname into a full pathname. Write the full +** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname +** bytes in size. +*/ +int winFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zRelative, /* Possibly relative input path */ + int nFull, /* Size of output buffer in bytes */ + char *zFull /* Output buffer */ +){ + + /* WinCE has no concept of a relative pathname, or so I am told. */ + sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative); + return SQLITE_OK; +} + + #define winDlOpen 0 + #define winDlError 0 + #define winDlSym 0 + #define winDlClose 0 + + +/* +** Write up to nBuf bytes of randomness into zBuf. +*/ +int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + + int i; + for (i=0; i