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