engine/sqlite/src/os_symbian.cpp
changeset 2 29cda98b007e
--- /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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <e32std.h>
+#include <f32file.h>
+#include <charconv.h>
+#include <bautils.h>
+#include <unistd.h>
+
+/*
+** 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<MAX_PATH> 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<MAX_PATH> 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<MAX_PATH> 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<nBuf; ++i)
+	{
+		zBuf[i] = rand() % 255;
+	}
+	return nBuf;
+}
+
+
+/*
+** Sleep for a little while.  Return the amount of time slept.
+*/
+int winSleep(sqlite3_vfs *pVfs, int microsec){
+	return sleep(microsec / 1000);
+}
+
+/*
+** The following variable, if set to a non-zero value, becomes the result
+** returned from sqlite3OsCurrentTime().  This is used for testing.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_current_time = 0;
+#endif
+
+/*
+** Find the current time (in Universal Coordinated Time).  Write the
+** current time and date as a Julian Day number into *prNow and
+** return 0.  Return 1 if the time and date cannot be found.
+*/
+int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
+  double now;
+
+  now = time(NULL);
+  *prNow = now;
+
+  return 0;
+}
+
+
+/*
+** Return a pointer to the sqlite3DefaultVfs structure.   We use
+** a function rather than give the structure global scope because
+** some compilers (MSVC) do not allow forward declarations of
+** initialized structures.
+*/
+sqlite3_vfs *sqlite3OsDefaultVfs(void){
+  static sqlite3_vfs winVfs = {
+    1,                 /* iVersion */
+    -1,   /* szOsFile */
+    MAX_PATH,          /* mxPathname */
+    0,                 /* pNext */
+    "symbian",           /* zName */
+    0,                 /* pAppData */
+    };
+  
+  winVfs.szOsFile = sizeof(symbianFile);
+  return &winVfs;
+}
+
+#endif /* OS_SYMBIAN */