engine/sqlite/src/os_symbian.cpp
changeset 2 29cda98b007e
equal deleted inserted replaced
1:5f8e5adbbed9 2:29cda98b007e
       
     1 /*
       
     2 ** 2008 February 09
       
     3 **
       
     4 ** The author disclaims copyright to this source code.  In place of
       
     5 ** a legal notice, here is a blessing:
       
     6 **
       
     7 **    May you do good and not evil.
       
     8 **    May you find forgiveness for yourself and forgive others.
       
     9 **    May you share freely, never taking more than you give.
       
    10 **
       
    11 ******************************************************************************
       
    12 **
       
    13 ** This file contains code that is specific to windows.
       
    14 */
       
    15 #include "sqliteInt.h"
       
    16 #if OS_SYMBIAN               /* This file is used for symbian only */
       
    17 
       
    18 #define MAX_PATH 260
       
    19 /*
       
    20 ** A Note About Memory Allocation:
       
    21 **
       
    22 ** This driver uses malloc()/free() directly rather than going through
       
    23 ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free().  Those wrappers
       
    24 ** are designed for use on embedded systems where memory is scarce and
       
    25 ** malloc failures happen frequently.  Win32 does not typically run on
       
    26 ** embedded systems, and when it does the developers normally have bigger
       
    27 ** problems to worry about than running out of memory.  So there is not
       
    28 ** a compelling need to use the wrappers.
       
    29 **
       
    30 ** But there is a good reason to not use the wrappers.  If we use the
       
    31 ** wrappers then we will get simulated malloc() failures within this
       
    32 ** driver.  And that causes all kinds of problems for our tests.  We
       
    33 ** could enhance SQLite to deal with simulated malloc failures within
       
    34 ** the OS driver, but the code to deal with those failure would not
       
    35 ** be exercised on Linux (which does not need to malloc() in the driver)
       
    36 ** and so we would have difficulty writing coverage tests for that
       
    37 ** code.  Better to leave the code out, we think.
       
    38 **
       
    39 ** The point of this discussion is as follows:  When creating a new
       
    40 ** OS layer for an embedded system, if you use this file as an example,
       
    41 ** avoid the use of malloc()/free().  Those routines work ok on windows
       
    42 ** desktops but not so well in embedded systems.
       
    43 */
       
    44 
       
    45 #include <stdlib.h>
       
    46 #include <string.h>
       
    47 #include <time.h>
       
    48 #include <e32std.h>
       
    49 #include <f32file.h>
       
    50 #include <charconv.h>
       
    51 #include <bautils.h>
       
    52 #include <unistd.h>
       
    53 
       
    54 /*
       
    55 ** Macros used to determine whether or not to use threads.
       
    56 */
       
    57 #if defined(THREADSAFE) && THREADSAFE
       
    58 # define SQLITE_W32_THREADS 1
       
    59 #endif
       
    60 
       
    61 /*
       
    62 ** Include code that is common to all os_*.c files
       
    63 */
       
    64 #include "os_common.h"
       
    65 
       
    66 /*
       
    67 ** The symbianFile structure is a subclass of sqlite3_file* specific to the win32
       
    68 ** portability layer.
       
    69 */
       
    70 
       
    71 typedef struct symbianFile symbianFile;
       
    72 struct symbianFile {
       
    73 	int isOpen;
       
    74   unsigned char locktype; /* Type of lock currently held on this file */
       
    75   short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
       
    76   char fileName[512];
       
    77   RFs session;
       
    78   RFile file;
       
    79 };
       
    80 
       
    81 /*****************************************************************************
       
    82 ** The next group of routines implement the I/O methods specified
       
    83 ** by the sqlite3_io_methods object.
       
    84 ******************************************************************************/
       
    85 
       
    86 /*
       
    87 ** Close a file.
       
    88 **
       
    89 ** It is reported that an attempt to close a handle might sometimes
       
    90 ** fail.  This is a very unreasonable result, but windows is notorious
       
    91 ** for being unreasonable so I do not doubt that it might happen.  If
       
    92 ** the close fails, we pause for 100 milliseconds and try again.  As
       
    93 ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
       
    94 ** giving up and returning an error.
       
    95 */
       
    96 #define MX_CLOSE_ATTEMPT 3
       
    97 int winClose(sqlite3_file *id){
       
    98   int rc, cnt = 0;
       
    99   symbianFile *pFile = (symbianFile*)id;
       
   100   pFile->file.Close();
       
   101   pFile->session.Close();
       
   102   return SQLITE_OK;
       
   103 }
       
   104 
       
   105 /*
       
   106 ** Some microsoft compilers lack this definition.
       
   107 */
       
   108 #ifndef INVALID_SET_FILE_POINTER
       
   109 # define INVALID_SET_FILE_POINTER ((DWORD)-1)
       
   110 #endif
       
   111 
       
   112 /*
       
   113 ** Read data from a file into a buffer.  Return SQLITE_OK if all
       
   114 ** bytes were read successfully and SQLITE_IOERR if anything goes
       
   115 ** wrong.
       
   116 */
       
   117 int winRead(
       
   118   sqlite3_file *id,          /* File to read from */
       
   119   void *pBuf,                /* Write content into this buffer */
       
   120   int amt,                   /* Number of bytes to read */
       
   121   sqlite3_int64 offset       /* Begin reading at this offset */
       
   122 ){
       
   123   int rc;
       
   124   size_t got;
       
   125   symbianFile *pFile = (symbianFile*)id;
       
   126   assert( id!=0 );
       
   127   SimulateIOError(return SQLITE_IOERR_READ);
       
   128   TInt tOffset = (TInt)offset;
       
   129   rc = pFile->file.Seek(ESeekStart, tOffset);
       
   130   if( rc!= KErrNone){
       
   131     return SQLITE_FULL;
       
   132   }
       
   133 
       
   134   HBufC8* buf = HBufC8::NewL(amt) ;
       
   135   TPtr8 ptr = buf->Des();
       
   136 
       
   137   if (pFile->file.Read(ptr, amt) != KErrNone)
       
   138 	  {
       
   139 	    delete buf;
       
   140 	    return SQLITE_IOERR_READ;
       
   141 	  }
       
   142 
       
   143   got = buf->Length();
       
   144 
       
   145   if( got == 0 ){
       
   146 	  delete buf;
       
   147 	  TInt size = 0;
       
   148 	  if (pFile->file.Size(size) != KErrNone) 
       
   149 	  {
       
   150 		  return SQLITE_IOERR_READ;
       
   151 	  }
       
   152 	  if (size == 0)
       
   153 	  {
       
   154 		  return SQLITE_IOERR_SHORT_READ;
       
   155 	  }
       
   156     return SQLITE_IOERR_READ;
       
   157  }
       
   158   memcpy(pBuf, ptr.Ptr(), got);
       
   159   delete buf;
       
   160  if( got == amt ){
       
   161     return SQLITE_OK;
       
   162   }else{
       
   163     memset(&((char*)pBuf)[got], 0, amt-got);
       
   164     return SQLITE_IOERR_SHORT_READ;
       
   165   }
       
   166 }
       
   167 
       
   168 /*
       
   169 ** Write data from a buffer into a file.  Return SQLITE_OK on success
       
   170 ** or some other error code on failure.
       
   171 */
       
   172 int winWrite(
       
   173   sqlite3_file *id,         /* File to write into */
       
   174   const void *pBuf,         /* The bytes to be written */
       
   175   int amt,                  /* Number of bytes to write */
       
   176   sqlite3_int64 offset      /* Offset into the file to begin writing at */
       
   177 ){
       
   178   int rc;
       
   179   symbianFile *pFile = (symbianFile*)id;
       
   180   assert( id!=0 );
       
   181   SimulateIOError(return SQLITE_IOERR_WRITE);
       
   182   SimulateDiskfullError(return SQLITE_FULL);
       
   183   TInt tOffset = (TInt)offset;
       
   184   rc = pFile->file.Seek(ESeekStart, tOffset);
       
   185   if( rc!= KErrNone){
       
   186     return SQLITE_FULL;
       
   187   }
       
   188 
       
   189   assert( amt>0 );
       
   190   
       
   191   rc = SQLITE_OK;
       
   192   TPtrC8 ptr((TUint8 *)pBuf,amt);
       
   193 
       
   194   if (pFile->file.Write(ptr, amt) != KErrNone) rc = SQLITE_FULL;
       
   195 
       
   196   return rc;
       
   197 }
       
   198 
       
   199 /*
       
   200 ** Truncate an open file to a specified size
       
   201 */
       
   202 int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
       
   203   symbianFile *pFile = (symbianFile*)id;
       
   204 
       
   205   if (pFile->file.SetSize(nByte) != KErrNone)
       
   206   {
       
   207 	  return SQLITE_IOERR; 
       
   208   }
       
   209 
       
   210   return SQLITE_OK;
       
   211 }
       
   212 
       
   213 #ifdef SQLITE_TEST
       
   214 /*
       
   215 ** Count the number of fullsyncs and normal syncs.  This is used to test
       
   216 ** that syncs and fullsyncs are occuring at the right times.
       
   217 */
       
   218 int sqlite3_sync_count = 0;
       
   219 int sqlite3_fullsync_count = 0;
       
   220 #endif
       
   221 
       
   222 /*
       
   223 ** Make sure all writes to a particular file are committed to disk.
       
   224 */
       
   225 int winSync(sqlite3_file *id, int flags){
       
   226   symbianFile *pFile = (symbianFile*)id;
       
   227   OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
       
   228 #ifdef SQLITE_TEST
       
   229   if( flags & SQLITE_SYNC_FULL ){
       
   230     sqlite3_fullsync_count++;
       
   231   }
       
   232   sqlite3_sync_count++;
       
   233 #endif
       
   234   TInt error = pFile->file.Flush();
       
   235   if (error != KErrNone)
       
   236   {
       
   237     return SQLITE_IOERR;
       
   238   }else{
       
   239     return SQLITE_OK;
       
   240   }
       
   241 }
       
   242 
       
   243 /*
       
   244 ** Determine the current size of a file in bytes
       
   245 */
       
   246 int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
       
   247   symbianFile *pFile = (symbianFile*)id;
       
   248 
       
   249   TInt size = 0;
       
   250   if (pFile->file.Size(size) != KErrNone)
       
   251   {
       
   252 	  return SQLITE_IOERR;
       
   253   }
       
   254 
       
   255   *pSize = size;
       
   256 
       
   257   return SQLITE_OK;
       
   258 }
       
   259 
       
   260 
       
   261 /*
       
   262 ** Lock the file with the lock specified by parameter locktype - one
       
   263 ** of the following:
       
   264 **
       
   265 **     (1) SHARED_LOCK
       
   266 **     (2) RESERVED_LOCK
       
   267 **     (3) PENDING_LOCK
       
   268 **     (4) EXCLUSIVE_LOCK
       
   269 **
       
   270 ** Sometimes when requesting one lock state, additional lock states
       
   271 ** are inserted in between.  The locking might fail on one of the later
       
   272 ** transitions leaving the lock state different from what it started but
       
   273 ** still short of its goal.  The following chart shows the allowed
       
   274 ** transitions and the inserted intermediate states:
       
   275 **
       
   276 **    UNLOCKED -> SHARED
       
   277 **    SHARED -> RESERVED
       
   278 **    SHARED -> (PENDING) -> EXCLUSIVE
       
   279 **    RESERVED -> (PENDING) -> EXCLUSIVE
       
   280 **    PENDING -> EXCLUSIVE
       
   281 **
       
   282 ** This routine will only increase a lock.  The winUnlock() routine
       
   283 ** erases all locks at once and returns us immediately to locking level 0.
       
   284 ** It is not possible to lower the locking level one step at a time.  You
       
   285 ** must go straight to locking level 0.
       
   286 */
       
   287 int winLock(sqlite3_file *id, int locktype){
       
   288   int rc = SQLITE_OK;    /* Return code from subroutines */
       
   289   int res = 1;           /* Result of a windows lock call */
       
   290   int newLocktype;       /* Set pFile->locktype to this value before exiting */
       
   291   int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
       
   292   symbianFile *pFile = (symbianFile*)id;
       
   293 
       
   294   assert( pFile!=0 );
       
   295   OSTRACE5("LOCK %d %d was %d(%d)\n",
       
   296           pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
       
   297 
       
   298   // one smartphone only one application can control the database
       
   299 
       
   300   TInt size = 0;
       
   301   if (pFile->file.Size(size) == KErrNone) return SQLITE_OK;
       
   302 
       
   303   return SQLITE_BUSY;
       
   304 }
       
   305 
       
   306 /*
       
   307 ** This routine checks if there is a RESERVED lock held on the specified
       
   308 ** file by this or any other process. If such a lock is held, return
       
   309 ** non-zero, otherwise zero.
       
   310 */
       
   311 int winCheckReservedLock(sqlite3_file *id){
       
   312   int rc;
       
   313   symbianFile *pFile = (symbianFile*)id;
       
   314   assert( pFile!=0 );
       
   315   if( pFile->locktype>=RESERVED_LOCK ){
       
   316     rc = 1;
       
   317     OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
       
   318   }else{
       
   319 	  TInt size = 0;
       
   320 	  if (pFile->file.Size(size) == KErrNone) rc = 1;
       
   321     OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
       
   322   }
       
   323   return rc;
       
   324 }
       
   325 
       
   326 /*
       
   327 ** Lower the locking level on file descriptor id to locktype.  locktype
       
   328 ** must be either NO_LOCK or SHARED_LOCK.
       
   329 **
       
   330 ** If the locking level of the file descriptor is already at or below
       
   331 ** the requested locking level, this routine is a no-op.
       
   332 **
       
   333 ** It is not possible for this routine to fail if the second argument
       
   334 ** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
       
   335 ** might return SQLITE_IOERR;
       
   336 */
       
   337 int winUnlock(sqlite3_file *id, int locktype){
       
   338   int type;
       
   339   symbianFile *pFile = (symbianFile*)id;
       
   340   int rc = SQLITE_OK;
       
   341   assert( pFile!=0 );
       
   342   return rc;
       
   343 }
       
   344 
       
   345 /*
       
   346 ** Control and query of the open file handle.
       
   347 */
       
   348 int winFileControl(sqlite3_file *id, int op, void *pArg){
       
   349   switch( op ){
       
   350     case SQLITE_FCNTL_LOCKSTATE: {
       
   351       *(int*)pArg = ((symbianFile*)id)->locktype;
       
   352       return SQLITE_OK;
       
   353     }
       
   354   }
       
   355   return SQLITE_ERROR;
       
   356 }
       
   357 
       
   358 /*
       
   359 ** Return the sector size in bytes of the underlying block device for
       
   360 ** the specified file. This is almost always 512 bytes, but may be
       
   361 ** larger for some devices.
       
   362 **
       
   363 ** SQLite code assumes this function cannot fail. It also assumes that
       
   364 ** if two files are created in the same file-system directory (i.e.
       
   365 ** a database and its journal file) that the sector size will be the
       
   366 ** same for both.
       
   367 */
       
   368 int winSectorSize(sqlite3_file *id){
       
   369   return SQLITE_DEFAULT_SECTOR_SIZE;
       
   370 }
       
   371 
       
   372 /*
       
   373 ** Return a vector of device characteristics.
       
   374 */
       
   375 int winDeviceCharacteristics(sqlite3_file *id){
       
   376   return 0;
       
   377 }
       
   378 
       
   379 
       
   380 /***************************************************************************
       
   381 ** Here ends the I/O methods that form the sqlite3_io_methods object.
       
   382 **
       
   383 ** The next block of code implements the VFS methods.
       
   384 ****************************************************************************/
       
   385 
       
   386 void ConvertToUnicode(RFs session, TDes16& aUnicode, const char *str)
       
   387 {
       
   388   CCnvCharacterSetConverter *converter = CCnvCharacterSetConverter::NewL();
       
   389   converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierUtf8, session);
       
   390   
       
   391   TPtrC8 ptr((const unsigned char*)str);
       
   392 
       
   393   int state = CCnvCharacterSetConverter::KStateDefault;
       
   394   converter->ConvertToUnicode(aUnicode, ptr, state);
       
   395   delete converter;
       
   396 }
       
   397 
       
   398 /*
       
   399 ** Open a file.
       
   400 */
       
   401 int winOpen(
       
   402   sqlite3_vfs *pVfs,        /* Not used */
       
   403   const char *zName,        /* Name of the file (UTF-8) */
       
   404   sqlite3_file *id,         /* Write the SQLite file handle here */
       
   405   int flags,                /* Open mode flags */
       
   406   int *pOutFlags            /* Status return flags */
       
   407 ){
       
   408   symbianFile *pFile = (symbianFile*)id;
       
   409   TBuf16<MAX_PATH> filename;
       
   410 
       
   411   pFile->isOpen = 0;
       
   412   memset(pFile, 0, sizeof(*pFile));
       
   413   strcpy(pFile->fileName, zName);
       
   414   pFile->session.Connect();
       
   415 
       
   416   ConvertToUnicode(pFile->session, filename, zName);
       
   417 
       
   418   int ret = 0;
       
   419   if( flags & SQLITE_OPEN_CREATE ){
       
   420     if (BaflUtils::FileExists(pFile->session, filename) == 1)
       
   421     	{
       
   422   	  ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileWrite);
       
   423     	}
       
   424     else
       
   425     	{
       
   426     	ret = pFile->file.Create(pFile->session, filename, EFileStream | EFileWrite);
       
   427     	}
       
   428   }
       
   429   else
       
   430   if( flags & SQLITE_OPEN_READWRITE ){
       
   431 	  ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileWrite);
       
   432   }else{
       
   433 	ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileRead);
       
   434   }
       
   435 
       
   436   OpenCounter(+1);
       
   437 
       
   438   if (ret != KErrNone)
       
   439   {
       
   440 	  return SQLITE_IOERR;
       
   441   }
       
   442 
       
   443   pFile->isOpen = 1;
       
   444   return SQLITE_OK;
       
   445 }
       
   446 
       
   447 /*
       
   448 ** Delete the named file.
       
   449 **
       
   450 ** Note that windows does not allow a file to be deleted if some other
       
   451 ** process has it open.  Sometimes a virus scanner or indexing program
       
   452 ** will open a journal file shortly after it is created in order to do
       
   453 ** whatever does.  While this other process is holding the
       
   454 ** file open, we will be unable to delete it.  To work around this
       
   455 ** problem, we delay 100 milliseconds and try to delete again.  Up
       
   456 ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
       
   457 ** up and returning an error.
       
   458 */
       
   459 #define MX_DELETION_ATTEMPTS 5
       
   460 int winDelete(
       
   461   sqlite3_vfs *pVfs,          /* Not used on win32 */
       
   462   const char *zFilename,      /* Name of file to delete */
       
   463   int syncDir                 /* Not used on win32 */
       
   464 ){
       
   465   SimulateIOError(return SQLITE_IOERR_DELETE);
       
   466   TBuf16<MAX_PATH> filename;
       
   467 
       
   468   RFs session;
       
   469   session.Connect();
       
   470   ConvertToUnicode(session, filename, zFilename);
       
   471   BaflUtils::DeleteFile(session, filename);
       
   472   OSTRACE2("DELETE \"%s\"\n", zFilename);
       
   473   session.Close();
       
   474   return SQLITE_OK;
       
   475 }
       
   476 
       
   477 /*
       
   478 ** Check the existance and status of a file.
       
   479 */
       
   480 int winAccess(
       
   481   sqlite3_vfs *pVfs,         /* Not used on win32 */
       
   482   const char *zFilename,     /* Name of file to check */
       
   483   int flags                  /* Type of test to make on this file */
       
   484 ){
       
   485   TBuf16<MAX_PATH> filename;
       
   486 
       
   487   RFs session;
       
   488   session.Connect();
       
   489   ConvertToUnicode(session, filename, zFilename);
       
   490   int ret = BaflUtils::FileExists(session, filename);
       
   491   session.Close();
       
   492 
       
   493   return ret;
       
   494 }
       
   495 
       
   496 
       
   497 /*
       
   498 ** Create a temporary file name in zBuf.  zBuf must be big enough to
       
   499 ** hold at pVfs->mxPathname characters.
       
   500 */
       
   501 int winGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
       
   502   static char zChars[] =
       
   503     "abcdefghijklmnopqrstuvwxyz"
       
   504     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
       
   505     "0123456789";
       
   506   int i, j;
       
   507   char zTempPath[MAX_PATH+1];
       
   508   if( sqlite3_temp_directory ){
       
   509     sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
       
   510   }
       
   511   else
       
   512   {
       
   513   }
       
   514   
       
   515   for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
       
   516   zTempPath[i] = 0;
       
   517   sqlite3_snprintf(nBuf-30, zBuf,
       
   518                    "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
       
   519   j = strlen(zBuf);
       
   520   sqlite3Randomness(20, &zBuf[j]);
       
   521   for(i=0; i<20; i++, j++){
       
   522     zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
       
   523   }
       
   524   zBuf[j] = 0;
       
   525   OSTRACE2("TEMP FILENAME: %s\n", zBuf);
       
   526   return SQLITE_OK; 
       
   527 }
       
   528 
       
   529 /*
       
   530 ** Turn a relative pathname into a full pathname.  Write the full
       
   531 ** pathname into zOut[].  zOut[] will be at least pVfs->mxPathname
       
   532 ** bytes in size.
       
   533 */
       
   534 int winFullPathname(
       
   535   sqlite3_vfs *pVfs,            /* Pointer to vfs object */
       
   536   const char *zRelative,        /* Possibly relative input path */
       
   537   int nFull,                    /* Size of output buffer in bytes */
       
   538   char *zFull                   /* Output buffer */
       
   539 ){
       
   540 
       
   541   /* WinCE has no concept of a relative pathname, or so I am told. */
       
   542   sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
       
   543   return SQLITE_OK;
       
   544 }
       
   545 
       
   546   #define winDlOpen  0
       
   547   #define winDlError 0
       
   548   #define winDlSym   0
       
   549   #define winDlClose 0
       
   550 
       
   551 
       
   552 /*
       
   553 ** Write up to nBuf bytes of randomness into zBuf.
       
   554 */
       
   555 int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
       
   556 
       
   557 	int i;
       
   558 	for (i=0; i<nBuf; ++i)
       
   559 	{
       
   560 		zBuf[i] = rand() % 255;
       
   561 	}
       
   562 	return nBuf;
       
   563 }
       
   564 
       
   565 
       
   566 /*
       
   567 ** Sleep for a little while.  Return the amount of time slept.
       
   568 */
       
   569 int winSleep(sqlite3_vfs *pVfs, int microsec){
       
   570 	return sleep(microsec / 1000);
       
   571 }
       
   572 
       
   573 /*
       
   574 ** The following variable, if set to a non-zero value, becomes the result
       
   575 ** returned from sqlite3OsCurrentTime().  This is used for testing.
       
   576 */
       
   577 #ifdef SQLITE_TEST
       
   578 int sqlite3_current_time = 0;
       
   579 #endif
       
   580 
       
   581 /*
       
   582 ** Find the current time (in Universal Coordinated Time).  Write the
       
   583 ** current time and date as a Julian Day number into *prNow and
       
   584 ** return 0.  Return 1 if the time and date cannot be found.
       
   585 */
       
   586 int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
       
   587   double now;
       
   588 
       
   589   now = time(NULL);
       
   590   *prNow = now;
       
   591 
       
   592   return 0;
       
   593 }
       
   594 
       
   595 
       
   596 /*
       
   597 ** Return a pointer to the sqlite3DefaultVfs structure.   We use
       
   598 ** a function rather than give the structure global scope because
       
   599 ** some compilers (MSVC) do not allow forward declarations of
       
   600 ** initialized structures.
       
   601 */
       
   602 sqlite3_vfs *sqlite3OsDefaultVfs(void){
       
   603   static sqlite3_vfs winVfs = {
       
   604     1,                 /* iVersion */
       
   605     -1,   /* szOsFile */
       
   606     MAX_PATH,          /* mxPathname */
       
   607     0,                 /* pNext */
       
   608     "symbian",           /* zName */
       
   609     0,                 /* pAppData */
       
   610     };
       
   611   
       
   612   winVfs.szOsFile = sizeof(symbianFile);
       
   613   return &winVfs;
       
   614 }
       
   615 
       
   616 #endif /* OS_SYMBIAN */