persistentstorage/sql/SQLite/os_os2.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 /*
       
     2 ** 2006 Feb 14
       
     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 OS/2.
       
    14 **
       
    15 ** $Id: os_os2.c,v 1.55 2008/07/29 18:49:29 pweilbacher Exp $
       
    16 */
       
    17 
       
    18 #include "sqliteInt.h"
       
    19 
       
    20 #if SQLITE_OS_OS2
       
    21 
       
    22 /*
       
    23 ** A Note About Memory Allocation:
       
    24 **
       
    25 ** This driver uses malloc()/free() directly rather than going through
       
    26 ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free().  Those wrappers
       
    27 ** are designed for use on embedded systems where memory is scarce and
       
    28 ** malloc failures happen frequently.  OS/2 does not typically run on
       
    29 ** embedded systems, and when it does the developers normally have bigger
       
    30 ** problems to worry about than running out of memory.  So there is not
       
    31 ** a compelling need to use the wrappers.
       
    32 **
       
    33 ** But there is a good reason to not use the wrappers.  If we use the
       
    34 ** wrappers then we will get simulated malloc() failures within this
       
    35 ** driver.  And that causes all kinds of problems for our tests.  We
       
    36 ** could enhance SQLite to deal with simulated malloc failures within
       
    37 ** the OS driver, but the code to deal with those failure would not
       
    38 ** be exercised on Linux (which does not need to malloc() in the driver)
       
    39 ** and so we would have difficulty writing coverage tests for that
       
    40 ** code.  Better to leave the code out, we think.
       
    41 **
       
    42 ** The point of this discussion is as follows:  When creating a new
       
    43 ** OS layer for an embedded system, if you use this file as an example,
       
    44 ** avoid the use of malloc()/free().  Those routines work ok on OS/2
       
    45 ** desktops but not so well in embedded systems.
       
    46 */
       
    47 
       
    48 /*
       
    49 ** Macros used to determine whether or not to use threads.
       
    50 */
       
    51 #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE
       
    52 # define SQLITE_OS2_THREADS 1
       
    53 #endif
       
    54 
       
    55 /*
       
    56 ** Include code that is common to all os_*.c files
       
    57 */
       
    58 #include "os_common.h"
       
    59 
       
    60 /*
       
    61 ** The os2File structure is subclass of sqlite3_file specific for the OS/2
       
    62 ** protability layer.
       
    63 */
       
    64 typedef struct os2File os2File;
       
    65 struct os2File {
       
    66   const sqlite3_io_methods *pMethod;  /* Always the first entry */
       
    67   HFILE h;                  /* Handle for accessing the file */
       
    68   char* pathToDel;          /* Name of file to delete on close, NULL if not */
       
    69   unsigned char locktype;   /* Type of lock currently held on this file */
       
    70 };
       
    71 
       
    72 #define LOCK_TIMEOUT 10L /* the default locking timeout */
       
    73 
       
    74 /*****************************************************************************
       
    75 ** The next group of routines implement the I/O methods specified
       
    76 ** by the sqlite3_io_methods object.
       
    77 ******************************************************************************/
       
    78 
       
    79 /*
       
    80 ** Close a file.
       
    81 */
       
    82 static int os2Close( sqlite3_file *id ){
       
    83   APIRET rc = NO_ERROR;
       
    84   os2File *pFile;
       
    85   if( id && (pFile = (os2File*)id) != 0 ){
       
    86     OSTRACE2( "CLOSE %d\n", pFile->h );
       
    87     rc = DosClose( pFile->h );
       
    88     pFile->locktype = NO_LOCK;
       
    89     if( pFile->pathToDel != NULL ){
       
    90       rc = DosForceDelete( (PSZ)pFile->pathToDel );
       
    91       free( pFile->pathToDel );
       
    92       pFile->pathToDel = NULL;
       
    93     }
       
    94     id = 0;
       
    95     OpenCounter( -1 );
       
    96   }
       
    97 
       
    98   return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
       
    99 }
       
   100 
       
   101 /*
       
   102 ** Read data from a file into a buffer.  Return SQLITE_OK if all
       
   103 ** bytes were read successfully and SQLITE_IOERR if anything goes
       
   104 ** wrong.
       
   105 */
       
   106 static int os2Read(
       
   107   sqlite3_file *id,               /* File to read from */
       
   108   void *pBuf,                     /* Write content into this buffer */
       
   109   int amt,                        /* Number of bytes to read */
       
   110   sqlite3_int64 offset            /* Begin reading at this offset */
       
   111 ){
       
   112   ULONG fileLocation = 0L;
       
   113   ULONG got;
       
   114   os2File *pFile = (os2File*)id;
       
   115   assert( id!=0 );
       
   116   SimulateIOError( return SQLITE_IOERR_READ );
       
   117   OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype );
       
   118   if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
       
   119     return SQLITE_IOERR;
       
   120   }
       
   121   if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){
       
   122     return SQLITE_IOERR_READ;
       
   123   }
       
   124   if( got == (ULONG)amt )
       
   125     return SQLITE_OK;
       
   126   else {
       
   127     memset(&((char*)pBuf)[got], 0, amt-got);
       
   128     return SQLITE_IOERR_SHORT_READ;
       
   129   }
       
   130 }
       
   131 
       
   132 /*
       
   133 ** Write data from a buffer into a file.  Return SQLITE_OK on success
       
   134 ** or some other error code on failure.
       
   135 */
       
   136 static int os2Write(
       
   137   sqlite3_file *id,               /* File to write into */
       
   138   const void *pBuf,               /* The bytes to be written */
       
   139   int amt,                        /* Number of bytes to write */
       
   140   sqlite3_int64 offset            /* Offset into the file to begin writing at */
       
   141 ){
       
   142   ULONG fileLocation = 0L;
       
   143   APIRET rc = NO_ERROR;
       
   144   ULONG wrote;
       
   145   os2File *pFile = (os2File*)id;
       
   146   assert( id!=0 );
       
   147   SimulateIOError( return SQLITE_IOERR_WRITE );
       
   148   SimulateDiskfullError( return SQLITE_FULL );
       
   149   OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype );
       
   150   if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
       
   151     return SQLITE_IOERR;
       
   152   }
       
   153   assert( amt>0 );
       
   154   while( amt > 0 &&
       
   155          ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR &&
       
   156          wrote > 0
       
   157   ){
       
   158     amt -= wrote;
       
   159     pBuf = &((char*)pBuf)[wrote];
       
   160   }
       
   161 
       
   162   return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
       
   163 }
       
   164 
       
   165 /*
       
   166 ** Truncate an open file to a specified size
       
   167 */
       
   168 static int os2Truncate( sqlite3_file *id, i64 nByte ){
       
   169   APIRET rc = NO_ERROR;
       
   170   os2File *pFile = (os2File*)id;
       
   171   OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte );
       
   172   SimulateIOError( return SQLITE_IOERR_TRUNCATE );
       
   173   rc = DosSetFileSize( pFile->h, nByte );
       
   174   return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
       
   175 }
       
   176 
       
   177 #ifdef SQLITE_TEST
       
   178 /*
       
   179 ** Count the number of fullsyncs and normal syncs.  This is used to test
       
   180 ** that syncs and fullsyncs are occuring at the right times.
       
   181 */
       
   182 int sqlite3_sync_count = 0;
       
   183 int sqlite3_fullsync_count = 0;
       
   184 #endif
       
   185 
       
   186 /*
       
   187 ** Make sure all writes to a particular file are committed to disk.
       
   188 */
       
   189 static int os2Sync( sqlite3_file *id, int flags ){
       
   190   os2File *pFile = (os2File*)id;
       
   191   OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );
       
   192 #ifdef SQLITE_TEST
       
   193   if( flags & SQLITE_SYNC_FULL){
       
   194     sqlite3_fullsync_count++;
       
   195   }
       
   196   sqlite3_sync_count++;
       
   197 #endif
       
   198   return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
       
   199 }
       
   200 
       
   201 /*
       
   202 ** Determine the current size of a file in bytes
       
   203 */
       
   204 static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){
       
   205   APIRET rc = NO_ERROR;
       
   206   FILESTATUS3 fsts3FileInfo;
       
   207   memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo));
       
   208   assert( id!=0 );
       
   209   SimulateIOError( return SQLITE_IOERR );
       
   210   rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) );
       
   211   if( rc == NO_ERROR ){
       
   212     *pSize = fsts3FileInfo.cbFile;
       
   213     return SQLITE_OK;
       
   214   }else{
       
   215     return SQLITE_IOERR;
       
   216   }
       
   217 }
       
   218 
       
   219 /*
       
   220 ** Acquire a reader lock.
       
   221 */
       
   222 static int getReadLock( os2File *pFile ){
       
   223   FILELOCK  LockArea,
       
   224             UnlockArea;
       
   225   APIRET res;
       
   226   memset(&LockArea, 0, sizeof(LockArea));
       
   227   memset(&UnlockArea, 0, sizeof(UnlockArea));
       
   228   LockArea.lOffset = SHARED_FIRST;
       
   229   LockArea.lRange = SHARED_SIZE;
       
   230   UnlockArea.lOffset = 0L;
       
   231   UnlockArea.lRange = 0L;
       
   232   res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
       
   233   OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
       
   234   return res;
       
   235 }
       
   236 
       
   237 /*
       
   238 ** Undo a readlock
       
   239 */
       
   240 static int unlockReadLock( os2File *id ){
       
   241   FILELOCK  LockArea,
       
   242             UnlockArea;
       
   243   APIRET res;
       
   244   memset(&LockArea, 0, sizeof(LockArea));
       
   245   memset(&UnlockArea, 0, sizeof(UnlockArea));
       
   246   LockArea.lOffset = 0L;
       
   247   LockArea.lRange = 0L;
       
   248   UnlockArea.lOffset = SHARED_FIRST;
       
   249   UnlockArea.lRange = SHARED_SIZE;
       
   250   res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
       
   251   OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
       
   252   return res;
       
   253 }
       
   254 
       
   255 /*
       
   256 ** Lock the file with the lock specified by parameter locktype - one
       
   257 ** of the following:
       
   258 **
       
   259 **     (1) SHARED_LOCK
       
   260 **     (2) RESERVED_LOCK
       
   261 **     (3) PENDING_LOCK
       
   262 **     (4) EXCLUSIVE_LOCK
       
   263 **
       
   264 ** Sometimes when requesting one lock state, additional lock states
       
   265 ** are inserted in between.  The locking might fail on one of the later
       
   266 ** transitions leaving the lock state different from what it started but
       
   267 ** still short of its goal.  The following chart shows the allowed
       
   268 ** transitions and the inserted intermediate states:
       
   269 **
       
   270 **    UNLOCKED -> SHARED
       
   271 **    SHARED -> RESERVED
       
   272 **    SHARED -> (PENDING) -> EXCLUSIVE
       
   273 **    RESERVED -> (PENDING) -> EXCLUSIVE
       
   274 **    PENDING -> EXCLUSIVE
       
   275 **
       
   276 ** This routine will only increase a lock.  The os2Unlock() routine
       
   277 ** erases all locks at once and returns us immediately to locking level 0.
       
   278 ** It is not possible to lower the locking level one step at a time.  You
       
   279 ** must go straight to locking level 0.
       
   280 */
       
   281 static int os2Lock( sqlite3_file *id, int locktype ){
       
   282   int rc = SQLITE_OK;       /* Return code from subroutines */
       
   283   APIRET res = NO_ERROR;    /* Result of an OS/2 lock call */
       
   284   int newLocktype;       /* Set pFile->locktype to this value before exiting */
       
   285   int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
       
   286   FILELOCK  LockArea,
       
   287             UnlockArea;
       
   288   os2File *pFile = (os2File*)id;
       
   289   memset(&LockArea, 0, sizeof(LockArea));
       
   290   memset(&UnlockArea, 0, sizeof(UnlockArea));
       
   291   assert( pFile!=0 );
       
   292   OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
       
   293 
       
   294   /* If there is already a lock of this type or more restrictive on the
       
   295   ** os2File, do nothing. Don't use the end_lock: exit path, as
       
   296   ** sqlite3_mutex_enter() hasn't been called yet.
       
   297   */
       
   298   if( pFile->locktype>=locktype ){
       
   299     OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
       
   300     return SQLITE_OK;
       
   301   }
       
   302 
       
   303   /* Make sure the locking sequence is correct
       
   304   */
       
   305   assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
       
   306   assert( locktype!=PENDING_LOCK );
       
   307   assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
       
   308 
       
   309   /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
       
   310   ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
       
   311   ** the PENDING_LOCK byte is temporary.
       
   312   */
       
   313   newLocktype = pFile->locktype;
       
   314   if( pFile->locktype==NO_LOCK
       
   315       || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
       
   316   ){
       
   317     LockArea.lOffset = PENDING_BYTE;
       
   318     LockArea.lRange = 1L;
       
   319     UnlockArea.lOffset = 0L;
       
   320     UnlockArea.lRange = 0L;
       
   321 
       
   322     /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */
       
   323     res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
       
   324     if( res == NO_ERROR ){
       
   325       gotPendingLock = 1;
       
   326       OSTRACE3( "LOCK %d pending lock boolean set.  res=%d\n", pFile->h, res );
       
   327     }
       
   328   }
       
   329 
       
   330   /* Acquire a shared lock
       
   331   */
       
   332   if( locktype==SHARED_LOCK && res == NO_ERROR ){
       
   333     assert( pFile->locktype==NO_LOCK );
       
   334     res = getReadLock(pFile);
       
   335     if( res == NO_ERROR ){
       
   336       newLocktype = SHARED_LOCK;
       
   337     }
       
   338     OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
       
   339   }
       
   340 
       
   341   /* Acquire a RESERVED lock
       
   342   */
       
   343   if( locktype==RESERVED_LOCK && res == NO_ERROR ){
       
   344     assert( pFile->locktype==SHARED_LOCK );
       
   345     LockArea.lOffset = RESERVED_BYTE;
       
   346     LockArea.lRange = 1L;
       
   347     UnlockArea.lOffset = 0L;
       
   348     UnlockArea.lRange = 0L;
       
   349     res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   350     if( res == NO_ERROR ){
       
   351       newLocktype = RESERVED_LOCK;
       
   352     }
       
   353     OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
       
   354   }
       
   355 
       
   356   /* Acquire a PENDING lock
       
   357   */
       
   358   if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
       
   359     newLocktype = PENDING_LOCK;
       
   360     gotPendingLock = 0;
       
   361     OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
       
   362   }
       
   363 
       
   364   /* Acquire an EXCLUSIVE lock
       
   365   */
       
   366   if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
       
   367     assert( pFile->locktype>=SHARED_LOCK );
       
   368     res = unlockReadLock(pFile);
       
   369     OSTRACE2( "unreadlock = %d\n", res );
       
   370     LockArea.lOffset = SHARED_FIRST;
       
   371     LockArea.lRange = SHARED_SIZE;
       
   372     UnlockArea.lOffset = 0L;
       
   373     UnlockArea.lRange = 0L;
       
   374     res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   375     if( res == NO_ERROR ){
       
   376       newLocktype = EXCLUSIVE_LOCK;
       
   377     }else{
       
   378       OSTRACE2( "OS/2 error-code = %d\n", res );
       
   379       getReadLock(pFile);
       
   380     }
       
   381     OSTRACE3( "LOCK %d acquire exclusive lock.  res=%d\n", pFile->h, res );
       
   382   }
       
   383 
       
   384   /* If we are holding a PENDING lock that ought to be released, then
       
   385   ** release it now.
       
   386   */
       
   387   if( gotPendingLock && locktype==SHARED_LOCK ){
       
   388     int r;
       
   389     LockArea.lOffset = 0L;
       
   390     LockArea.lRange = 0L;
       
   391     UnlockArea.lOffset = PENDING_BYTE;
       
   392     UnlockArea.lRange = 1L;
       
   393     r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   394     OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
       
   395   }
       
   396 
       
   397   /* Update the state of the lock has held in the file descriptor then
       
   398   ** return the appropriate result code.
       
   399   */
       
   400   if( res == NO_ERROR ){
       
   401     rc = SQLITE_OK;
       
   402   }else{
       
   403     OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
       
   404               locktype, newLocktype );
       
   405     rc = SQLITE_BUSY;
       
   406   }
       
   407   pFile->locktype = newLocktype;
       
   408   OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
       
   409   return rc;
       
   410 }
       
   411 
       
   412 /*
       
   413 ** This routine checks if there is a RESERVED lock held on the specified
       
   414 ** file by this or any other process. If such a lock is held, return
       
   415 ** non-zero, otherwise zero.
       
   416 */
       
   417 static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
       
   418   int r = 0;
       
   419   os2File *pFile = (os2File*)id;
       
   420   assert( pFile!=0 );
       
   421   if( pFile->locktype>=RESERVED_LOCK ){
       
   422     r = 1;
       
   423     OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
       
   424   }else{
       
   425     FILELOCK  LockArea,
       
   426               UnlockArea;
       
   427     APIRET rc = NO_ERROR;
       
   428     memset(&LockArea, 0, sizeof(LockArea));
       
   429     memset(&UnlockArea, 0, sizeof(UnlockArea));
       
   430     LockArea.lOffset = RESERVED_BYTE;
       
   431     LockArea.lRange = 1L;
       
   432     UnlockArea.lOffset = 0L;
       
   433     UnlockArea.lRange = 0L;
       
   434     rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   435     OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
       
   436     if( rc == NO_ERROR ){
       
   437       APIRET rcu = NO_ERROR; /* return code for unlocking */
       
   438       LockArea.lOffset = 0L;
       
   439       LockArea.lRange = 0L;
       
   440       UnlockArea.lOffset = RESERVED_BYTE;
       
   441       UnlockArea.lRange = 1L;
       
   442       rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   443       OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
       
   444     }
       
   445     r = !(rc == NO_ERROR);
       
   446     OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
       
   447   }
       
   448   *pOut = r;
       
   449   return SQLITE_OK;
       
   450 }
       
   451 
       
   452 /*
       
   453 ** Lower the locking level on file descriptor id to locktype.  locktype
       
   454 ** must be either NO_LOCK or SHARED_LOCK.
       
   455 **
       
   456 ** If the locking level of the file descriptor is already at or below
       
   457 ** the requested locking level, this routine is a no-op.
       
   458 **
       
   459 ** It is not possible for this routine to fail if the second argument
       
   460 ** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
       
   461 ** might return SQLITE_IOERR;
       
   462 */
       
   463 static int os2Unlock( sqlite3_file *id, int locktype ){
       
   464   int type;
       
   465   os2File *pFile = (os2File*)id;
       
   466   APIRET rc = SQLITE_OK;
       
   467   APIRET res = NO_ERROR;
       
   468   FILELOCK  LockArea,
       
   469             UnlockArea;
       
   470   memset(&LockArea, 0, sizeof(LockArea));
       
   471   memset(&UnlockArea, 0, sizeof(UnlockArea));
       
   472   assert( pFile!=0 );
       
   473   assert( locktype<=SHARED_LOCK );
       
   474   OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
       
   475   type = pFile->locktype;
       
   476   if( type>=EXCLUSIVE_LOCK ){
       
   477     LockArea.lOffset = 0L;
       
   478     LockArea.lRange = 0L;
       
   479     UnlockArea.lOffset = SHARED_FIRST;
       
   480     UnlockArea.lRange = SHARED_SIZE;
       
   481     res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   482     OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
       
   483     if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
       
   484       /* This should never happen.  We should always be able to
       
   485       ** reacquire the read lock */
       
   486       OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
       
   487       rc = SQLITE_IOERR_UNLOCK;
       
   488     }
       
   489   }
       
   490   if( type>=RESERVED_LOCK ){
       
   491     LockArea.lOffset = 0L;
       
   492     LockArea.lRange = 0L;
       
   493     UnlockArea.lOffset = RESERVED_BYTE;
       
   494     UnlockArea.lRange = 1L;
       
   495     res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   496     OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
       
   497   }
       
   498   if( locktype==NO_LOCK && type>=SHARED_LOCK ){
       
   499     res = unlockReadLock(pFile);
       
   500     OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
       
   501   }
       
   502   if( type>=PENDING_LOCK ){
       
   503     LockArea.lOffset = 0L;
       
   504     LockArea.lRange = 0L;
       
   505     UnlockArea.lOffset = PENDING_BYTE;
       
   506     UnlockArea.lRange = 1L;
       
   507     res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
       
   508     OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
       
   509   }
       
   510   pFile->locktype = locktype;
       
   511   OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
       
   512   return rc;
       
   513 }
       
   514 
       
   515 /*
       
   516 ** Control and query of the open file handle.
       
   517 */
       
   518 static int os2FileControl(sqlite3_file *id, int op, void *pArg){
       
   519   switch( op ){
       
   520     case SQLITE_FCNTL_LOCKSTATE: {
       
   521       *(int*)pArg = ((os2File*)id)->locktype;
       
   522       OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
       
   523       return SQLITE_OK;
       
   524     }
       
   525   }
       
   526   return SQLITE_ERROR;
       
   527 }
       
   528 
       
   529 /*
       
   530 ** Return the sector size in bytes of the underlying block device for
       
   531 ** the specified file. This is almost always 512 bytes, but may be
       
   532 ** larger for some devices.
       
   533 **
       
   534 ** SQLite code assumes this function cannot fail. It also assumes that
       
   535 ** if two files are created in the same file-system directory (i.e.
       
   536 ** a database and its journal file) that the sector size will be the
       
   537 ** same for both.
       
   538 */
       
   539 static int os2SectorSize(sqlite3_file *id){
       
   540   return SQLITE_DEFAULT_SECTOR_SIZE;
       
   541 }
       
   542 
       
   543 /*
       
   544 ** Return a vector of device characteristics.
       
   545 */
       
   546 static int os2DeviceCharacteristics(sqlite3_file *id){
       
   547   return 0;
       
   548 }
       
   549 
       
   550 
       
   551 /*
       
   552 ** Character set conversion objects used by conversion routines.
       
   553 */
       
   554 static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
       
   555 static UconvObject uclCp = NULL;  /* convert between local codepage and UCS-2 */
       
   556 
       
   557 /*
       
   558 ** Helper function to initialize the conversion objects from and to UTF-8.
       
   559 */
       
   560 static void initUconvObjects( void ){
       
   561   if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS )
       
   562     ucUtf8 = NULL;
       
   563   if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS )
       
   564     uclCp = NULL;
       
   565 }
       
   566 
       
   567 /*
       
   568 ** Helper function to free the conversion objects from and to UTF-8.
       
   569 */
       
   570 static void freeUconvObjects( void ){
       
   571   if ( ucUtf8 )
       
   572     UniFreeUconvObject( ucUtf8 );
       
   573   if ( uclCp )
       
   574     UniFreeUconvObject( uclCp );
       
   575   ucUtf8 = NULL;
       
   576   uclCp = NULL;
       
   577 }
       
   578 
       
   579 /*
       
   580 ** Helper function to convert UTF-8 filenames to local OS/2 codepage.
       
   581 ** The two-step process: first convert the incoming UTF-8 string
       
   582 ** into UCS-2 and then from UCS-2 to the current codepage.
       
   583 ** The returned char pointer has to be freed.
       
   584 */
       
   585 static char *convertUtf8PathToCp( const char *in ){
       
   586   UniChar tempPath[CCHMAXPATH];
       
   587   char *out = (char *)calloc( CCHMAXPATH, 1 );
       
   588 
       
   589   if( !out )
       
   590     return NULL;
       
   591 
       
   592   if( !ucUtf8 || !uclCp )
       
   593     initUconvObjects();
       
   594 
       
   595   /* determine string for the conversion of UTF-8 which is CP1208 */
       
   596   if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
       
   597     return out; /* if conversion fails, return the empty string */
       
   598 
       
   599   /* conversion for current codepage which can be used for paths */
       
   600   UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH );
       
   601 
       
   602   return out;
       
   603 }
       
   604 
       
   605 /*
       
   606 ** Helper function to convert filenames from local codepage to UTF-8.
       
   607 ** The two-step process: first convert the incoming codepage-specific
       
   608 ** string into UCS-2 and then from UCS-2 to the codepage of UTF-8.
       
   609 ** The returned char pointer has to be freed.
       
   610 **
       
   611 ** This function is non-static to be able to use this in shell.c and
       
   612 ** similar applications that take command line arguments.
       
   613 */
       
   614 char *convertCpPathToUtf8( const char *in ){
       
   615   UniChar tempPath[CCHMAXPATH];
       
   616   char *out = (char *)calloc( CCHMAXPATH, 1 );
       
   617 
       
   618   if( !out )
       
   619     return NULL;
       
   620 
       
   621   if( !ucUtf8 || !uclCp )
       
   622     initUconvObjects();
       
   623 
       
   624   /* conversion for current codepage which can be used for paths */
       
   625   if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
       
   626     return out; /* if conversion fails, return the empty string */
       
   627 
       
   628   /* determine string for the conversion of UTF-8 which is CP1208 */
       
   629   UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );
       
   630 
       
   631   return out;
       
   632 }
       
   633 
       
   634 /*
       
   635 ** This vector defines all the methods that can operate on an
       
   636 ** sqlite3_file for os2.
       
   637 */
       
   638 static const sqlite3_io_methods os2IoMethod = {
       
   639   1,                        /* iVersion */
       
   640   os2Close,
       
   641   os2Read,
       
   642   os2Write,
       
   643   os2Truncate,
       
   644   os2Sync,
       
   645   os2FileSize,
       
   646   os2Lock,
       
   647   os2Unlock,
       
   648   os2CheckReservedLock,
       
   649   os2FileControl,
       
   650   os2SectorSize,
       
   651   os2DeviceCharacteristics
       
   652 };
       
   653 
       
   654 /***************************************************************************
       
   655 ** Here ends the I/O methods that form the sqlite3_io_methods object.
       
   656 **
       
   657 ** The next block of code implements the VFS methods.
       
   658 ****************************************************************************/
       
   659 
       
   660 /*
       
   661 ** Create a temporary file name in zBuf.  zBuf must be big enough to
       
   662 ** hold at pVfs->mxPathname characters.
       
   663 */
       
   664 static int getTempname(int nBuf, char *zBuf ){
       
   665   static const unsigned char zChars[] =
       
   666     "abcdefghijklmnopqrstuvwxyz"
       
   667     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
       
   668     "0123456789";
       
   669   int i, j;
       
   670   char zTempPathBuf[3];
       
   671   PSZ zTempPath = (PSZ)&zTempPathBuf;
       
   672   if( sqlite3_temp_directory ){
       
   673     zTempPath = sqlite3_temp_directory;
       
   674   }else{
       
   675     if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){
       
   676       if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){
       
   677         if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){
       
   678            ULONG ulDriveNum = 0, ulDriveMap = 0;
       
   679            DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
       
   680            sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) );
       
   681         }
       
   682       }
       
   683     }
       
   684   }
       
   685   /* Strip off a trailing slashes or backslashes, otherwise we would get *
       
   686    * multiple (back)slashes which causes DosOpen() to fail.              *
       
   687    * Trailing spaces are not allowed, either.                            */
       
   688   j = strlen(zTempPath);
       
   689   while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/'
       
   690                     || zTempPath[j-1] == ' ' ) ){
       
   691     j--;
       
   692   }
       
   693   zTempPath[j] = '\0';
       
   694   if( !sqlite3_temp_directory ){
       
   695     char *zTempPathUTF = convertCpPathToUtf8( zTempPath );
       
   696     sqlite3_snprintf( nBuf-30, zBuf,
       
   697                       "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF );
       
   698     free( zTempPathUTF );
       
   699   }else{
       
   700     sqlite3_snprintf( nBuf-30, zBuf,
       
   701                       "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath );
       
   702   }
       
   703   j = strlen( zBuf );
       
   704   sqlite3_randomness( 20, &zBuf[j] );
       
   705   for( i = 0; i < 20; i++, j++ ){
       
   706     zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
       
   707   }
       
   708   zBuf[j] = 0;
       
   709   OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
       
   710   return SQLITE_OK;
       
   711 }
       
   712 
       
   713 
       
   714 /*
       
   715 ** Turn a relative pathname into a full pathname.  Write the full
       
   716 ** pathname into zFull[].  zFull[] will be at least pVfs->mxPathname
       
   717 ** bytes in size.
       
   718 */
       
   719 static int os2FullPathname(
       
   720   sqlite3_vfs *pVfs,          /* Pointer to vfs object */
       
   721   const char *zRelative,      /* Possibly relative input path */
       
   722   int nFull,                  /* Size of output buffer in bytes */
       
   723   char *zFull                 /* Output buffer */
       
   724 ){
       
   725   char *zRelativeCp = convertUtf8PathToCp( zRelative );
       
   726   char zFullCp[CCHMAXPATH] = "\0";
       
   727   char *zFullUTF;
       
   728   APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
       
   729                                 CCHMAXPATH );
       
   730   free( zRelativeCp );
       
   731   zFullUTF = convertCpPathToUtf8( zFullCp );
       
   732   sqlite3_snprintf( nFull, zFull, zFullUTF );
       
   733   free( zFullUTF );
       
   734   return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
       
   735 }
       
   736 
       
   737 
       
   738 /*
       
   739 ** Open a file.
       
   740 */
       
   741 static int os2Open(
       
   742   sqlite3_vfs *pVfs,            /* Not used */
       
   743   const char *zName,            /* Name of the file */
       
   744   sqlite3_file *id,             /* Write the SQLite file handle here */
       
   745   int flags,                    /* Open mode flags */
       
   746   int *pOutFlags                /* Status return flags */
       
   747 ){
       
   748   HFILE h;
       
   749   ULONG ulFileAttribute = 0;
       
   750   ULONG ulOpenFlags = 0;
       
   751   ULONG ulOpenMode = 0;
       
   752   os2File *pFile = (os2File*)id;
       
   753   APIRET rc = NO_ERROR;
       
   754   ULONG ulAction;
       
   755   char *zNameCp;
       
   756   char zTmpname[CCHMAXPATH+1];    /* Buffer to hold name of temp file */
       
   757 
       
   758   /* If the second argument to this function is NULL, generate a 
       
   759   ** temporary file name to use 
       
   760   */
       
   761   if( !zName ){
       
   762     int rc = getTempname(CCHMAXPATH+1, zTmpname);
       
   763     if( rc!=SQLITE_OK ){
       
   764       return rc;
       
   765     }
       
   766     zName = zTmpname;
       
   767   }
       
   768 
       
   769 
       
   770   memset( pFile, 0, sizeof(*pFile) );
       
   771 
       
   772   OSTRACE2( "OPEN want %d\n", flags );
       
   773 
       
   774   /*ulOpenMode = flags & SQLITE_OPEN_READWRITE ? OPEN_ACCESS_READWRITE : OPEN_ACCESS_READONLY;*/
       
   775   if( flags & SQLITE_OPEN_READWRITE ){
       
   776     ulOpenMode |= OPEN_ACCESS_READWRITE;
       
   777     OSTRACE1( "OPEN read/write\n" );
       
   778   }else{
       
   779     ulOpenMode |= OPEN_ACCESS_READONLY;
       
   780     OSTRACE1( "OPEN read only\n" );
       
   781   }
       
   782 
       
   783   /*ulOpenFlags = flags & SQLITE_OPEN_CREATE ? OPEN_ACTION_CREATE_IF_NEW : OPEN_ACTION_FAIL_IF_NEW;*/
       
   784   if( flags & SQLITE_OPEN_CREATE ){
       
   785     ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
       
   786     OSTRACE1( "OPEN open new/create\n" );
       
   787   }else{
       
   788     ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
       
   789     OSTRACE1( "OPEN open existing\n" );
       
   790   }
       
   791 
       
   792   /*ulOpenMode |= flags & SQLITE_OPEN_MAIN_DB ? OPEN_SHARE_DENYNONE : OPEN_SHARE_DENYWRITE;*/
       
   793   if( flags & SQLITE_OPEN_MAIN_DB ){
       
   794     ulOpenMode |= OPEN_SHARE_DENYNONE;
       
   795     OSTRACE1( "OPEN share read/write\n" );
       
   796   }else{
       
   797     ulOpenMode |= OPEN_SHARE_DENYWRITE;
       
   798     OSTRACE1( "OPEN share read only\n" );
       
   799   }
       
   800 
       
   801   if( flags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TEMP_JOURNAL
       
   802                | SQLITE_OPEN_SUBJOURNAL) ){
       
   803     char pathUtf8[CCHMAXPATH];
       
   804 #ifdef NDEBUG /* when debugging we want to make sure it is deleted */
       
   805     ulFileAttribute = FILE_HIDDEN;
       
   806 #endif
       
   807     ulFileAttribute = FILE_NORMAL;
       
   808     os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
       
   809     pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
       
   810     OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
       
   811   }else{
       
   812     ulFileAttribute = FILE_ARCHIVED | FILE_NORMAL;
       
   813     pFile->pathToDel = NULL;
       
   814     OSTRACE1( "OPEN normal file attribute\n" );
       
   815   }
       
   816 
       
   817   /* always open in random access mode for possibly better speed */
       
   818   ulOpenMode |= OPEN_FLAGS_RANDOM;
       
   819   ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
       
   820   ulOpenMode |= OPEN_FLAGS_NOINHERIT;
       
   821 
       
   822   zNameCp = convertUtf8PathToCp( zName );
       
   823   rc = DosOpen( (PSZ)zNameCp,
       
   824                 &h,
       
   825                 &ulAction,
       
   826                 0L,
       
   827                 ulFileAttribute,
       
   828                 ulOpenFlags,
       
   829                 ulOpenMode,
       
   830                 (PEAOP2)NULL );
       
   831   free( zNameCp );
       
   832   if( rc != NO_ERROR ){
       
   833     OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
       
   834               rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
       
   835     if( pFile->pathToDel )
       
   836       free( pFile->pathToDel );
       
   837     pFile->pathToDel = NULL;
       
   838     if( flags & SQLITE_OPEN_READWRITE ){
       
   839       OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
       
   840       return os2Open( pVfs, zName, id,
       
   841                       ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
       
   842                       pOutFlags );
       
   843     }else{
       
   844       return SQLITE_CANTOPEN;
       
   845     }
       
   846   }
       
   847 
       
   848   if( pOutFlags ){
       
   849     *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
       
   850   }
       
   851 
       
   852   pFile->pMethod = &os2IoMethod;
       
   853   pFile->h = h;
       
   854   OpenCounter(+1);
       
   855   OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
       
   856   return SQLITE_OK;
       
   857 }
       
   858 
       
   859 /*
       
   860 ** Delete the named file.
       
   861 */
       
   862 static int os2Delete(
       
   863   sqlite3_vfs *pVfs,                     /* Not used on os2 */
       
   864   const char *zFilename,                 /* Name of file to delete */
       
   865   int syncDir                            /* Not used on os2 */
       
   866 ){
       
   867   APIRET rc = NO_ERROR;
       
   868   char *zFilenameCp = convertUtf8PathToCp( zFilename );
       
   869   SimulateIOError( return SQLITE_IOERR_DELETE );
       
   870   rc = DosDelete( (PSZ)zFilenameCp );
       
   871   free( zFilenameCp );
       
   872   OSTRACE2( "DELETE \"%s\"\n", zFilename );
       
   873   return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
       
   874 }
       
   875 
       
   876 /*
       
   877 ** Check the existance and status of a file.
       
   878 */
       
   879 static int os2Access(
       
   880   sqlite3_vfs *pVfs,        /* Not used on os2 */
       
   881   const char *zFilename,    /* Name of file to check */
       
   882   int flags,                /* Type of test to make on this file */
       
   883   int *pOut                 /* Write results here */
       
   884 ){
       
   885   FILESTATUS3 fsts3ConfigInfo;
       
   886   APIRET rc = NO_ERROR;
       
   887   char *zFilenameCp = convertUtf8PathToCp( zFilename );
       
   888 
       
   889   memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) );
       
   890   rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
       
   891                          &fsts3ConfigInfo, sizeof(FILESTATUS3) );
       
   892   free( zFilenameCp );
       
   893   OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
       
   894             fsts3ConfigInfo.attrFile, flags, rc );
       
   895   switch( flags ){
       
   896     case SQLITE_ACCESS_READ:
       
   897     case SQLITE_ACCESS_EXISTS:
       
   898       rc = (rc == NO_ERROR);
       
   899       OSTRACE3( "ACCESS %s access of read and exists  rc=%d\n", zFilename, rc );
       
   900       break;
       
   901     case SQLITE_ACCESS_READWRITE:
       
   902       rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
       
   903       OSTRACE3( "ACCESS %s access of read/write  rc=%d\n", zFilename, rc );
       
   904       break;
       
   905     default:
       
   906       assert( !"Invalid flags argument" );
       
   907   }
       
   908   *pOut = rc;
       
   909   return SQLITE_OK;
       
   910 }
       
   911 
       
   912 
       
   913 #ifndef SQLITE_OMIT_LOAD_EXTENSION
       
   914 /*
       
   915 ** Interfaces for opening a shared library, finding entry points
       
   916 ** within the shared library, and closing the shared library.
       
   917 */
       
   918 /*
       
   919 ** Interfaces for opening a shared library, finding entry points
       
   920 ** within the shared library, and closing the shared library.
       
   921 */
       
   922 static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
       
   923   UCHAR loadErr[256];
       
   924   HMODULE hmod;
       
   925   APIRET rc;
       
   926   char *zFilenameCp = convertUtf8PathToCp(zFilename);
       
   927   rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod);
       
   928   free(zFilenameCp);
       
   929   return rc != NO_ERROR ? 0 : (void*)hmod;
       
   930 }
       
   931 /*
       
   932 ** A no-op since the error code is returned on the DosLoadModule call.
       
   933 ** os2Dlopen returns zero if DosLoadModule is not successful.
       
   934 */
       
   935 static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
       
   936 /* no-op */
       
   937 }
       
   938 static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
       
   939   PFN pfn;
       
   940   APIRET rc;
       
   941   rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
       
   942   if( rc != NO_ERROR ){
       
   943     /* if the symbol itself was not found, search again for the same
       
   944      * symbol with an extra underscore, that might be needed depending
       
   945      * on the calling convention */
       
   946     char _zSymbol[256] = "_";
       
   947     strncat(_zSymbol, zSymbol, 255);
       
   948     rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
       
   949   }
       
   950   return rc != NO_ERROR ? 0 : (void*)pfn;
       
   951 }
       
   952 static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
       
   953   DosFreeModule((HMODULE)pHandle);
       
   954 }
       
   955 #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
       
   956   #define os2DlOpen 0
       
   957   #define os2DlError 0
       
   958   #define os2DlSym 0
       
   959   #define os2DlClose 0
       
   960 #endif
       
   961 
       
   962 
       
   963 /*
       
   964 ** Write up to nBuf bytes of randomness into zBuf.
       
   965 */
       
   966 static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
       
   967   ULONG sizeofULong = sizeof(ULONG);
       
   968   int n = 0;
       
   969   if( sizeof(DATETIME) <= nBuf - n ){
       
   970     DATETIME x;
       
   971     DosGetDateTime(&x);
       
   972     memcpy(&zBuf[n], &x, sizeof(x));
       
   973     n += sizeof(x);
       
   974   }
       
   975 
       
   976   if( sizeofULong <= nBuf - n ){
       
   977     PPIB ppib;
       
   978     DosGetInfoBlocks(NULL, &ppib);
       
   979     memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong);
       
   980     n += sizeofULong;
       
   981   }
       
   982 
       
   983   if( sizeofULong <= nBuf - n ){
       
   984     PTIB ptib;
       
   985     DosGetInfoBlocks(&ptib, NULL);
       
   986     memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong);
       
   987     n += sizeofULong;
       
   988   }
       
   989 
       
   990   /* if we still haven't filled the buffer yet the following will */
       
   991   /* grab everything once instead of making several calls for a single item */
       
   992   if( sizeofULong <= nBuf - n ){
       
   993     ULONG ulSysInfo[QSV_MAX];
       
   994     DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX);
       
   995 
       
   996     memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong);
       
   997     n += sizeofULong;
       
   998 
       
   999     if( sizeofULong <= nBuf - n ){
       
  1000       memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong);
       
  1001       n += sizeofULong;
       
  1002     }
       
  1003     if( sizeofULong <= nBuf - n ){
       
  1004       memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong);
       
  1005       n += sizeofULong;
       
  1006     }
       
  1007     if( sizeofULong <= nBuf - n ){
       
  1008       memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong);
       
  1009       n += sizeofULong;
       
  1010     }
       
  1011     if( sizeofULong <= nBuf - n ){
       
  1012       memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong);
       
  1013       n += sizeofULong;
       
  1014     }
       
  1015   }
       
  1016 
       
  1017   return n;
       
  1018 }
       
  1019 
       
  1020 /*
       
  1021 ** Sleep for a little while.  Return the amount of time slept.
       
  1022 ** The argument is the number of microseconds we want to sleep.
       
  1023 ** The return value is the number of microseconds of sleep actually
       
  1024 ** requested from the underlying operating system, a number which
       
  1025 ** might be greater than or equal to the argument, but not less
       
  1026 ** than the argument.
       
  1027 */
       
  1028 static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){
       
  1029   DosSleep( (microsec/1000) );
       
  1030   return microsec;
       
  1031 }
       
  1032 
       
  1033 /*
       
  1034 ** The following variable, if set to a non-zero value, becomes the result
       
  1035 ** returned from sqlite3OsCurrentTime().  This is used for testing.
       
  1036 */
       
  1037 #ifdef SQLITE_TEST
       
  1038 int sqlite3_current_time = 0;
       
  1039 #endif
       
  1040 
       
  1041 /*
       
  1042 ** Find the current time (in Universal Coordinated Time).  Write the
       
  1043 ** current time and date as a Julian Day number into *prNow and
       
  1044 ** return 0.  Return 1 if the time and date cannot be found.
       
  1045 */
       
  1046 int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
       
  1047   double now;
       
  1048   SHORT minute; /* needs to be able to cope with negative timezone offset */
       
  1049   USHORT second, hour,
       
  1050          day, month, year;
       
  1051   DATETIME dt;
       
  1052   DosGetDateTime( &dt );
       
  1053   second = (USHORT)dt.seconds;
       
  1054   minute = (SHORT)dt.minutes + dt.timezone;
       
  1055   hour = (USHORT)dt.hours;
       
  1056   day = (USHORT)dt.day;
       
  1057   month = (USHORT)dt.month;
       
  1058   year = (USHORT)dt.year;
       
  1059 
       
  1060   /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
       
  1061      http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
       
  1062   /* Calculate the Julian days */
       
  1063   now = day - 32076 +
       
  1064     1461*(year + 4800 + (month - 14)/12)/4 +
       
  1065     367*(month - 2 - (month - 14)/12*12)/12 -
       
  1066     3*((year + 4900 + (month - 14)/12)/100)/4;
       
  1067 
       
  1068   /* Add the fractional hours, mins and seconds */
       
  1069   now += (hour + 12.0)/24.0;
       
  1070   now += minute/1440.0;
       
  1071   now += second/86400.0;
       
  1072   *prNow = now;
       
  1073 #ifdef SQLITE_TEST
       
  1074   if( sqlite3_current_time ){
       
  1075     *prNow = sqlite3_current_time/86400.0 + 2440587.5;
       
  1076   }
       
  1077 #endif
       
  1078   return 0;
       
  1079 }
       
  1080 
       
  1081 static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
       
  1082   return 0;
       
  1083 }
       
  1084 
       
  1085 /*
       
  1086 ** Initialize and deinitialize the operating system interface.
       
  1087 */
       
  1088 int sqlite3_os_init(void){
       
  1089   static sqlite3_vfs os2Vfs = {
       
  1090     1,                 /* iVersion */
       
  1091     sizeof(os2File),   /* szOsFile */
       
  1092     CCHMAXPATH,        /* mxPathname */
       
  1093     0,                 /* pNext */
       
  1094     "os2",             /* zName */
       
  1095     0,                 /* pAppData */
       
  1096 
       
  1097     os2Open,           /* xOpen */
       
  1098     os2Delete,         /* xDelete */
       
  1099     os2Access,         /* xAccess */
       
  1100     os2FullPathname,   /* xFullPathname */
       
  1101     os2DlOpen,         /* xDlOpen */
       
  1102     os2DlError,        /* xDlError */
       
  1103     os2DlSym,          /* xDlSym */
       
  1104     os2DlClose,        /* xDlClose */
       
  1105     os2Randomness,     /* xRandomness */
       
  1106     os2Sleep,          /* xSleep */
       
  1107     os2CurrentTime,    /* xCurrentTime */
       
  1108     os2GetLastError    /* xGetLastError */
       
  1109   };
       
  1110   sqlite3_vfs_register(&os2Vfs, 1);
       
  1111   initUconvObjects();
       
  1112   return SQLITE_OK;
       
  1113 }
       
  1114 int sqlite3_os_end(void){
       
  1115   freeUconvObjects();
       
  1116   return SQLITE_OK;
       
  1117 }
       
  1118 
       
  1119 #endif /* SQLITE_OS_OS2 */