00001 /* 00002 ** 2006 Feb 14 00003 ** 00004 ** The author disclaims copyright to this source code. In place of 00005 ** a legal notice, here is a blessing: 00006 ** 00007 ** May you do good and not evil. 00008 ** May you find forgiveness for yourself and forgive others. 00009 ** May you share freely, never taking more than you give. 00010 ** 00011 ****************************************************************************** 00012 ** 00013 ** This file contains code that is specific to OS/2. 00014 ** 00015 ** $Id: os_os2.c,v 1.58 2008/11/07 00:06:18 drh Exp $ 00016 */ 00017 00018 #include "sqliteInt.h" 00019 00020 #if SQLITE_OS_OS2 00021 00022 /* 00023 ** A Note About Memory Allocation: 00024 ** 00025 ** This driver uses malloc()/free() directly rather than going through 00026 ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers 00027 ** are designed for use on embedded systems where memory is scarce and 00028 ** malloc failures happen frequently. OS/2 does not typically run on 00029 ** embedded systems, and when it does the developers normally have bigger 00030 ** problems to worry about than running out of memory. So there is not 00031 ** a compelling need to use the wrappers. 00032 ** 00033 ** But there is a good reason to not use the wrappers. If we use the 00034 ** wrappers then we will get simulated malloc() failures within this 00035 ** driver. And that causes all kinds of problems for our tests. We 00036 ** could enhance SQLite to deal with simulated malloc failures within 00037 ** the OS driver, but the code to deal with those failure would not 00038 ** be exercised on Linux (which does not need to malloc() in the driver) 00039 ** and so we would have difficulty writing coverage tests for that 00040 ** code. Better to leave the code out, we think. 00041 ** 00042 ** The point of this discussion is as follows: When creating a new 00043 ** OS layer for an embedded system, if you use this file as an example, 00044 ** avoid the use of malloc()/free(). Those routines work ok on OS/2 00045 ** desktops but not so well in embedded systems. 00046 */ 00047 00048 /* 00049 ** Macros used to determine whether or not to use threads. 00050 */ 00051 #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE 00052 # define SQLITE_OS2_THREADS 1 00053 #endif 00054 00055 /* 00056 ** Include code that is common to all os_*.c files 00057 */ 00058 #include "os_common.h" 00059 00060 /* 00061 ** The os2File structure is subclass of sqlite3_file specific for the OS/2 00062 ** protability layer. 00063 */ 00064 typedef struct os2File os2File; 00065 struct os2File { 00066 const sqlite3_io_methods *pMethod; /* Always the first entry */ 00067 HFILE h; /* Handle for accessing the file */ 00068 char* pathToDel; /* Name of file to delete on close, NULL if not */ 00069 unsigned char locktype; /* Type of lock currently held on this file */ 00070 }; 00071 00072 #define LOCK_TIMEOUT 10L /* the default locking timeout */ 00073 00074 /***************************************************************************** 00075 ** The next group of routines implement the I/O methods specified 00076 ** by the sqlite3_io_methods object. 00077 ******************************************************************************/ 00078 00079 /* 00080 ** Close a file. 00081 */ 00082 static int os2Close( sqlite3_file *id ){ 00083 APIRET rc = NO_ERROR; 00084 os2File *pFile; 00085 if( id && (pFile = (os2File*)id) != 0 ){ 00086 OSTRACE2( "CLOSE %d\n", pFile->h ); 00087 rc = DosClose( pFile->h ); 00088 pFile->locktype = NO_LOCK; 00089 if( pFile->pathToDel != NULL ){ 00090 rc = DosForceDelete( (PSZ)pFile->pathToDel ); 00091 free( pFile->pathToDel ); 00092 pFile->pathToDel = NULL; 00093 } 00094 id = 0; 00095 OpenCounter( -1 ); 00096 } 00097 00098 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; 00099 } 00100 00101 /* 00102 ** Read data from a file into a buffer. Return SQLITE_OK if all 00103 ** bytes were read successfully and SQLITE_IOERR if anything goes 00104 ** wrong. 00105 */ 00106 static int os2Read( 00107 sqlite3_file *id, /* File to read from */ 00108 void *pBuf, /* Write content into this buffer */ 00109 int amt, /* Number of bytes to read */ 00110 sqlite3_int64 offset /* Begin reading at this offset */ 00111 ){ 00112 ULONG fileLocation = 0L; 00113 ULONG got; 00114 os2File *pFile = (os2File*)id; 00115 assert( id!=0 ); 00116 SimulateIOError( return SQLITE_IOERR_READ ); 00117 OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype ); 00118 if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ 00119 return SQLITE_IOERR; 00120 } 00121 if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){ 00122 return SQLITE_IOERR_READ; 00123 } 00124 if( got == (ULONG)amt ) 00125 return SQLITE_OK; 00126 else { 00127 /* Unread portions of the input buffer must be zero-filled */ 00128 memset(&((char*)pBuf)[got], 0, amt-got); 00129 return SQLITE_IOERR_SHORT_READ; 00130 } 00131 } 00132 00133 /* 00134 ** Write data from a buffer into a file. Return SQLITE_OK on success 00135 ** or some other error code on failure. 00136 */ 00137 static int os2Write( 00138 sqlite3_file *id, /* File to write into */ 00139 const void *pBuf, /* The bytes to be written */ 00140 int amt, /* Number of bytes to write */ 00141 sqlite3_int64 offset /* Offset into the file to begin writing at */ 00142 ){ 00143 ULONG fileLocation = 0L; 00144 APIRET rc = NO_ERROR; 00145 ULONG wrote; 00146 os2File *pFile = (os2File*)id; 00147 assert( id!=0 ); 00148 SimulateIOError( return SQLITE_IOERR_WRITE ); 00149 SimulateDiskfullError( return SQLITE_FULL ); 00150 OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ); 00151 if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ 00152 return SQLITE_IOERR; 00153 } 00154 assert( amt>0 ); 00155 while( amt > 0 && 00156 ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR && 00157 wrote > 0 00158 ){ 00159 amt -= wrote; 00160 pBuf = &((char*)pBuf)[wrote]; 00161 } 00162 00163 return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; 00164 } 00165 00166 /* 00167 ** Truncate an open file to a specified size 00168 */ 00169 static int os2Truncate( sqlite3_file *id, i64 nByte ){ 00170 APIRET rc = NO_ERROR; 00171 os2File *pFile = (os2File*)id; 00172 OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte ); 00173 SimulateIOError( return SQLITE_IOERR_TRUNCATE ); 00174 rc = DosSetFileSize( pFile->h, nByte ); 00175 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; 00176 } 00177 00178 #ifdef SQLITE_TEST 00179 /* 00180 ** Count the number of fullsyncs and normal syncs. This is used to test 00181 ** that syncs and fullsyncs are occuring at the right times. 00182 */ 00183 int sqlite3_sync_count = 0; 00184 int sqlite3_fullsync_count = 0; 00185 #endif 00186 00187 /* 00188 ** Make sure all writes to a particular file are committed to disk. 00189 */ 00190 static int os2Sync( sqlite3_file *id, int flags ){ 00191 os2File *pFile = (os2File*)id; 00192 OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ); 00193 #ifdef SQLITE_TEST 00194 if( flags & SQLITE_SYNC_FULL){ 00195 sqlite3_fullsync_count++; 00196 } 00197 sqlite3_sync_count++; 00198 #endif 00199 return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; 00200 } 00201 00202 /* 00203 ** Determine the current size of a file in bytes 00204 */ 00205 static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){ 00206 APIRET rc = NO_ERROR; 00207 FILESTATUS3 fsts3FileInfo; 00208 memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); 00209 assert( id!=0 ); 00210 SimulateIOError( return SQLITE_IOERR_FSTAT ); 00211 rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); 00212 if( rc == NO_ERROR ){ 00213 *pSize = fsts3FileInfo.cbFile; 00214 return SQLITE_OK; 00215 }else{ 00216 return SQLITE_IOERR_FSTAT; 00217 } 00218 } 00219 00220 /* 00221 ** Acquire a reader lock. 00222 */ 00223 static int getReadLock( os2File *pFile ){ 00224 FILELOCK LockArea, 00225 UnlockArea; 00226 APIRET res; 00227 memset(&LockArea, 0, sizeof(LockArea)); 00228 memset(&UnlockArea, 0, sizeof(UnlockArea)); 00229 LockArea.lOffset = SHARED_FIRST; 00230 LockArea.lRange = SHARED_SIZE; 00231 UnlockArea.lOffset = 0L; 00232 UnlockArea.lRange = 0L; 00233 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); 00234 OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res ); 00235 return res; 00236 } 00237 00238 /* 00239 ** Undo a readlock 00240 */ 00241 static int unlockReadLock( os2File *id ){ 00242 FILELOCK LockArea, 00243 UnlockArea; 00244 APIRET res; 00245 memset(&LockArea, 0, sizeof(LockArea)); 00246 memset(&UnlockArea, 0, sizeof(UnlockArea)); 00247 LockArea.lOffset = 0L; 00248 LockArea.lRange = 0L; 00249 UnlockArea.lOffset = SHARED_FIRST; 00250 UnlockArea.lRange = SHARED_SIZE; 00251 res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); 00252 OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ); 00253 return res; 00254 } 00255 00256 /* 00257 ** Lock the file with the lock specified by parameter locktype - one 00258 ** of the following: 00259 ** 00260 ** (1) SHARED_LOCK 00261 ** (2) RESERVED_LOCK 00262 ** (3) PENDING_LOCK 00263 ** (4) EXCLUSIVE_LOCK 00264 ** 00265 ** Sometimes when requesting one lock state, additional lock states 00266 ** are inserted in between. The locking might fail on one of the later 00267 ** transitions leaving the lock state different from what it started but 00268 ** still short of its goal. The following chart shows the allowed 00269 ** transitions and the inserted intermediate states: 00270 ** 00271 ** UNLOCKED -> SHARED 00272 ** SHARED -> RESERVED 00273 ** SHARED -> (PENDING) -> EXCLUSIVE 00274 ** RESERVED -> (PENDING) -> EXCLUSIVE 00275 ** PENDING -> EXCLUSIVE 00276 ** 00277 ** This routine will only increase a lock. The os2Unlock() routine 00278 ** erases all locks at once and returns us immediately to locking level 0. 00279 ** It is not possible to lower the locking level one step at a time. You 00280 ** must go straight to locking level 0. 00281 */ 00282 static int os2Lock( sqlite3_file *id, int locktype ){ 00283 int rc = SQLITE_OK; /* Return code from subroutines */ 00284 APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ 00285 int newLocktype; /* Set pFile->locktype to this value before exiting */ 00286 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ 00287 FILELOCK LockArea, 00288 UnlockArea; 00289 os2File *pFile = (os2File*)id; 00290 memset(&LockArea, 0, sizeof(LockArea)); 00291 memset(&UnlockArea, 0, sizeof(UnlockArea)); 00292 assert( pFile!=0 ); 00293 OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); 00294 00295 /* If there is already a lock of this type or more restrictive on the 00296 ** os2File, do nothing. Don't use the end_lock: exit path, as 00297 ** sqlite3_mutex_enter() hasn't been called yet. 00298 */ 00299 if( pFile->locktype>=locktype ){ 00300 OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype ); 00301 return SQLITE_OK; 00302 } 00303 00304 /* Make sure the locking sequence is correct 00305 */ 00306 assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); 00307 assert( locktype!=PENDING_LOCK ); 00308 assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); 00309 00310 /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or 00311 ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of 00312 ** the PENDING_LOCK byte is temporary. 00313 */ 00314 newLocktype = pFile->locktype; 00315 if( pFile->locktype==NO_LOCK 00316 || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) 00317 ){ 00318 LockArea.lOffset = PENDING_BYTE; 00319 LockArea.lRange = 1L; 00320 UnlockArea.lOffset = 0L; 00321 UnlockArea.lRange = 0L; 00322 00323 /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */ 00324 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L ); 00325 if( res == NO_ERROR ){ 00326 gotPendingLock = 1; 00327 OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ); 00328 } 00329 } 00330 00331 /* Acquire a shared lock 00332 */ 00333 if( locktype==SHARED_LOCK && res == NO_ERROR ){ 00334 assert( pFile->locktype==NO_LOCK ); 00335 res = getReadLock(pFile); 00336 if( res == NO_ERROR ){ 00337 newLocktype = SHARED_LOCK; 00338 } 00339 OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ); 00340 } 00341 00342 /* Acquire a RESERVED lock 00343 */ 00344 if( locktype==RESERVED_LOCK && res == NO_ERROR ){ 00345 assert( pFile->locktype==SHARED_LOCK ); 00346 LockArea.lOffset = RESERVED_BYTE; 00347 LockArea.lRange = 1L; 00348 UnlockArea.lOffset = 0L; 00349 UnlockArea.lRange = 0L; 00350 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00351 if( res == NO_ERROR ){ 00352 newLocktype = RESERVED_LOCK; 00353 } 00354 OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ); 00355 } 00356 00357 /* Acquire a PENDING lock 00358 */ 00359 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ 00360 newLocktype = PENDING_LOCK; 00361 gotPendingLock = 0; 00362 OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h ); 00363 } 00364 00365 /* Acquire an EXCLUSIVE lock 00366 */ 00367 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ 00368 assert( pFile->locktype>=SHARED_LOCK ); 00369 res = unlockReadLock(pFile); 00370 OSTRACE2( "unreadlock = %d\n", res ); 00371 LockArea.lOffset = SHARED_FIRST; 00372 LockArea.lRange = SHARED_SIZE; 00373 UnlockArea.lOffset = 0L; 00374 UnlockArea.lRange = 0L; 00375 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00376 if( res == NO_ERROR ){ 00377 newLocktype = EXCLUSIVE_LOCK; 00378 }else{ 00379 OSTRACE2( "OS/2 error-code = %d\n", res ); 00380 getReadLock(pFile); 00381 } 00382 OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ); 00383 } 00384 00385 /* If we are holding a PENDING lock that ought to be released, then 00386 ** release it now. 00387 */ 00388 if( gotPendingLock && locktype==SHARED_LOCK ){ 00389 int r; 00390 LockArea.lOffset = 0L; 00391 LockArea.lRange = 0L; 00392 UnlockArea.lOffset = PENDING_BYTE; 00393 UnlockArea.lRange = 1L; 00394 r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00395 OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ); 00396 } 00397 00398 /* Update the state of the lock has held in the file descriptor then 00399 ** return the appropriate result code. 00400 */ 00401 if( res == NO_ERROR ){ 00402 rc = SQLITE_OK; 00403 }else{ 00404 OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, 00405 locktype, newLocktype ); 00406 rc = SQLITE_BUSY; 00407 } 00408 pFile->locktype = newLocktype; 00409 OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype ); 00410 return rc; 00411 } 00412 00413 /* 00414 ** This routine checks if there is a RESERVED lock held on the specified 00415 ** file by this or any other process. If such a lock is held, return 00416 ** non-zero, otherwise zero. 00417 */ 00418 static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){ 00419 int r = 0; 00420 os2File *pFile = (os2File*)id; 00421 assert( pFile!=0 ); 00422 if( pFile->locktype>=RESERVED_LOCK ){ 00423 r = 1; 00424 OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ); 00425 }else{ 00426 FILELOCK LockArea, 00427 UnlockArea; 00428 APIRET rc = NO_ERROR; 00429 memset(&LockArea, 0, sizeof(LockArea)); 00430 memset(&UnlockArea, 0, sizeof(UnlockArea)); 00431 LockArea.lOffset = RESERVED_BYTE; 00432 LockArea.lRange = 1L; 00433 UnlockArea.lOffset = 0L; 00434 UnlockArea.lRange = 0L; 00435 rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00436 OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ); 00437 if( rc == NO_ERROR ){ 00438 APIRET rcu = NO_ERROR; /* return code for unlocking */ 00439 LockArea.lOffset = 0L; 00440 LockArea.lRange = 0L; 00441 UnlockArea.lOffset = RESERVED_BYTE; 00442 UnlockArea.lRange = 1L; 00443 rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00444 OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ); 00445 } 00446 r = !(rc == NO_ERROR); 00447 OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ); 00448 } 00449 *pOut = r; 00450 return SQLITE_OK; 00451 } 00452 00453 /* 00454 ** Lower the locking level on file descriptor id to locktype. locktype 00455 ** must be either NO_LOCK or SHARED_LOCK. 00456 ** 00457 ** If the locking level of the file descriptor is already at or below 00458 ** the requested locking level, this routine is a no-op. 00459 ** 00460 ** It is not possible for this routine to fail if the second argument 00461 ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine 00462 ** might return SQLITE_IOERR; 00463 */ 00464 static int os2Unlock( sqlite3_file *id, int locktype ){ 00465 int type; 00466 os2File *pFile = (os2File*)id; 00467 APIRET rc = SQLITE_OK; 00468 APIRET res = NO_ERROR; 00469 FILELOCK LockArea, 00470 UnlockArea; 00471 memset(&LockArea, 0, sizeof(LockArea)); 00472 memset(&UnlockArea, 0, sizeof(UnlockArea)); 00473 assert( pFile!=0 ); 00474 assert( locktype<=SHARED_LOCK ); 00475 OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ); 00476 type = pFile->locktype; 00477 if( type>=EXCLUSIVE_LOCK ){ 00478 LockArea.lOffset = 0L; 00479 LockArea.lRange = 0L; 00480 UnlockArea.lOffset = SHARED_FIRST; 00481 UnlockArea.lRange = SHARED_SIZE; 00482 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00483 OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ); 00484 if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ 00485 /* This should never happen. We should always be able to 00486 ** reacquire the read lock */ 00487 OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ); 00488 rc = SQLITE_IOERR_UNLOCK; 00489 } 00490 } 00491 if( type>=RESERVED_LOCK ){ 00492 LockArea.lOffset = 0L; 00493 LockArea.lRange = 0L; 00494 UnlockArea.lOffset = RESERVED_BYTE; 00495 UnlockArea.lRange = 1L; 00496 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00497 OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res ); 00498 } 00499 if( locktype==NO_LOCK && type>=SHARED_LOCK ){ 00500 res = unlockReadLock(pFile); 00501 OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res ); 00502 } 00503 if( type>=PENDING_LOCK ){ 00504 LockArea.lOffset = 0L; 00505 LockArea.lRange = 0L; 00506 UnlockArea.lOffset = PENDING_BYTE; 00507 UnlockArea.lRange = 1L; 00508 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); 00509 OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res ); 00510 } 00511 pFile->locktype = locktype; 00512 OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ); 00513 return rc; 00514 } 00515 00516 /* 00517 ** Control and query of the open file handle. 00518 */ 00519 static int os2FileControl(sqlite3_file *id, int op, void *pArg){ 00520 switch( op ){ 00521 case SQLITE_FCNTL_LOCKSTATE: { 00522 *(int*)pArg = ((os2File*)id)->locktype; 00523 OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); 00524 return SQLITE_OK; 00525 } 00526 } 00527 return SQLITE_ERROR; 00528 } 00529 00530 /* 00531 ** Return the sector size in bytes of the underlying block device for 00532 ** the specified file. This is almost always 512 bytes, but may be 00533 ** larger for some devices. 00534 ** 00535 ** SQLite code assumes this function cannot fail. It also assumes that 00536 ** if two files are created in the same file-system directory (i.e. 00537 ** a database and its journal file) that the sector size will be the 00538 ** same for both. 00539 */ 00540 static int os2SectorSize(sqlite3_file *id){ 00541 return SQLITE_DEFAULT_SECTOR_SIZE; 00542 } 00543 00544 /* 00545 ** Return a vector of device characteristics. 00546 */ 00547 static int os2DeviceCharacteristics(sqlite3_file *id){ 00548 return 0; 00549 } 00550 00551 00552 /* 00553 ** Character set conversion objects used by conversion routines. 00554 */ 00555 static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */ 00556 static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */ 00557 00558 /* 00559 ** Helper function to initialize the conversion objects from and to UTF-8. 00560 */ 00561 static void initUconvObjects( void ){ 00562 if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS ) 00563 ucUtf8 = NULL; 00564 if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS ) 00565 uclCp = NULL; 00566 } 00567 00568 /* 00569 ** Helper function to free the conversion objects from and to UTF-8. 00570 */ 00571 static void freeUconvObjects( void ){ 00572 if ( ucUtf8 ) 00573 UniFreeUconvObject( ucUtf8 ); 00574 if ( uclCp ) 00575 UniFreeUconvObject( uclCp ); 00576 ucUtf8 = NULL; 00577 uclCp = NULL; 00578 } 00579 00580 /* 00581 ** Helper function to convert UTF-8 filenames to local OS/2 codepage. 00582 ** The two-step process: first convert the incoming UTF-8 string 00583 ** into UCS-2 and then from UCS-2 to the current codepage. 00584 ** The returned char pointer has to be freed. 00585 */ 00586 static char *convertUtf8PathToCp( const char *in ){ 00587 UniChar tempPath[CCHMAXPATH]; 00588 char *out = (char *)calloc( CCHMAXPATH, 1 ); 00589 00590 if( !out ) 00591 return NULL; 00592 00593 if( !ucUtf8 || !uclCp ) 00594 initUconvObjects(); 00595 00596 /* determine string for the conversion of UTF-8 which is CP1208 */ 00597 if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS ) 00598 return out; /* if conversion fails, return the empty string */ 00599 00600 /* conversion for current codepage which can be used for paths */ 00601 UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH ); 00602 00603 return out; 00604 } 00605 00606 /* 00607 ** Helper function to convert filenames from local codepage to UTF-8. 00608 ** The two-step process: first convert the incoming codepage-specific 00609 ** string into UCS-2 and then from UCS-2 to the codepage of UTF-8. 00610 ** The returned char pointer has to be freed. 00611 ** 00612 ** This function is non-static to be able to use this in shell.c and 00613 ** similar applications that take command line arguments. 00614 */ 00615 char *convertCpPathToUtf8( const char *in ){ 00616 UniChar tempPath[CCHMAXPATH]; 00617 char *out = (char *)calloc( CCHMAXPATH, 1 ); 00618 00619 if( !out ) 00620 return NULL; 00621 00622 if( !ucUtf8 || !uclCp ) 00623 initUconvObjects(); 00624 00625 /* conversion for current codepage which can be used for paths */ 00626 if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS ) 00627 return out; /* if conversion fails, return the empty string */ 00628 00629 /* determine string for the conversion of UTF-8 which is CP1208 */ 00630 UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); 00631 00632 return out; 00633 } 00634 00635 /* 00636 ** This vector defines all the methods that can operate on an 00637 ** sqlite3_file for os2. 00638 */ 00639 static const sqlite3_io_methods os2IoMethod = { 00640 1, /* iVersion */ 00641 os2Close, 00642 os2Read, 00643 os2Write, 00644 os2Truncate, 00645 os2Sync, 00646 os2FileSize, 00647 os2Lock, 00648 os2Unlock, 00649 os2CheckReservedLock, 00650 os2FileControl, 00651 os2SectorSize, 00652 os2DeviceCharacteristics 00653 }; 00654 00655 /*************************************************************************** 00656 ** Here ends the I/O methods that form the sqlite3_io_methods object. 00657 ** 00658 ** The next block of code implements the VFS methods. 00659 ****************************************************************************/ 00660 00661 /* 00662 ** Create a temporary file name in zBuf. zBuf must be big enough to 00663 ** hold at pVfs->mxPathname characters. 00664 */ 00665 static int getTempname(int nBuf, char *zBuf ){ 00666 static const unsigned char zChars[] = 00667 "abcdefghijklmnopqrstuvwxyz" 00668 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 00669 "0123456789"; 00670 int i, j; 00671 char zTempPathBuf[3]; 00672 PSZ zTempPath = (PSZ)&zTempPathBuf; 00673 if( sqlite3_temp_directory ){ 00674 zTempPath = sqlite3_temp_directory; 00675 }else{ 00676 if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ 00677 if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ 00678 if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ 00679 ULONG ulDriveNum = 0, ulDriveMap = 0; 00680 DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); 00681 sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); 00682 } 00683 } 00684 } 00685 } 00686 /* Strip off a trailing slashes or backslashes, otherwise we would get * 00687 * multiple (back)slashes which causes DosOpen() to fail. * 00688 * Trailing spaces are not allowed, either. */ 00689 j = strlen(zTempPath); 00690 while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' 00691 || zTempPath[j-1] == ' ' ) ){ 00692 j--; 00693 } 00694 zTempPath[j] = '\0'; 00695 if( !sqlite3_temp_directory ){ 00696 char *zTempPathUTF = convertCpPathToUtf8( zTempPath ); 00697 sqlite3_snprintf( nBuf-30, zBuf, 00698 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF ); 00699 free( zTempPathUTF ); 00700 }else{ 00701 sqlite3_snprintf( nBuf-30, zBuf, 00702 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath ); 00703 } 00704 j = strlen( zBuf ); 00705 sqlite3_randomness( 20, &zBuf[j] ); 00706 for( i = 0; i < 20; i++, j++ ){ 00707 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; 00708 } 00709 zBuf[j] = 0; 00710 OSTRACE2( "TEMP FILENAME: %s\n", zBuf ); 00711 return SQLITE_OK; 00712 } 00713 00714 00715 /* 00716 ** Turn a relative pathname into a full pathname. Write the full 00717 ** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname 00718 ** bytes in size. 00719 */ 00720 static int os2FullPathname( 00721 sqlite3_vfs *pVfs, /* Pointer to vfs object */ 00722 const char *zRelative, /* Possibly relative input path */ 00723 int nFull, /* Size of output buffer in bytes */ 00724 char *zFull /* Output buffer */ 00725 ){ 00726 char *zRelativeCp = convertUtf8PathToCp( zRelative ); 00727 char zFullCp[CCHMAXPATH] = "\0"; 00728 char *zFullUTF; 00729 APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp, 00730 CCHMAXPATH ); 00731 free( zRelativeCp ); 00732 zFullUTF = convertCpPathToUtf8( zFullCp ); 00733 sqlite3_snprintf( nFull, zFull, zFullUTF ); 00734 free( zFullUTF ); 00735 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; 00736 } 00737 00738 00739 /* 00740 ** Open a file. 00741 */ 00742 static int os2Open( 00743 sqlite3_vfs *pVfs, /* Not used */ 00744 const char *zName, /* Name of the file */ 00745 sqlite3_file *id, /* Write the SQLite file handle here */ 00746 int flags, /* Open mode flags */ 00747 int *pOutFlags /* Status return flags */ 00748 ){ 00749 HFILE h; 00750 ULONG ulFileAttribute = FILE_NORMAL; 00751 ULONG ulOpenFlags = 0; 00752 ULONG ulOpenMode = 0; 00753 os2File *pFile = (os2File*)id; 00754 APIRET rc = NO_ERROR; 00755 ULONG ulAction; 00756 char *zNameCp; 00757 char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */ 00758 00759 /* If the second argument to this function is NULL, generate a 00760 ** temporary file name to use 00761 */ 00762 if( !zName ){ 00763 int rc = getTempname(CCHMAXPATH+1, zTmpname); 00764 if( rc!=SQLITE_OK ){ 00765 return rc; 00766 } 00767 zName = zTmpname; 00768 } 00769 00770 00771 memset( pFile, 0, sizeof(*pFile) ); 00772 00773 OSTRACE2( "OPEN want %d\n", flags ); 00774 00775 if( flags & SQLITE_OPEN_READWRITE ){ 00776 ulOpenMode |= OPEN_ACCESS_READWRITE; 00777 OSTRACE1( "OPEN read/write\n" ); 00778 }else{ 00779 ulOpenMode |= OPEN_ACCESS_READONLY; 00780 OSTRACE1( "OPEN read only\n" ); 00781 } 00782 00783 if( flags & SQLITE_OPEN_CREATE ){ 00784 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW; 00785 OSTRACE1( "OPEN open new/create\n" ); 00786 }else{ 00787 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW; 00788 OSTRACE1( "OPEN open existing\n" ); 00789 } 00790 00791 if( flags & SQLITE_OPEN_MAIN_DB ){ 00792 ulOpenMode |= OPEN_SHARE_DENYNONE; 00793 OSTRACE1( "OPEN share read/write\n" ); 00794 }else{ 00795 ulOpenMode |= OPEN_SHARE_DENYWRITE; 00796 OSTRACE1( "OPEN share read only\n" ); 00797 } 00798 00799 if( flags & SQLITE_OPEN_DELETEONCLOSE ){ 00800 char pathUtf8[CCHMAXPATH]; 00801 #ifdef NDEBUG /* when debugging we want to make sure it is deleted */ 00802 ulFileAttribute = FILE_HIDDEN; 00803 #endif 00804 os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 ); 00805 pFile->pathToDel = convertUtf8PathToCp( pathUtf8 ); 00806 OSTRACE1( "OPEN hidden/delete on close file attributes\n" ); 00807 }else{ 00808 pFile->pathToDel = NULL; 00809 OSTRACE1( "OPEN normal file attribute\n" ); 00810 } 00811 00812 /* always open in random access mode for possibly better speed */ 00813 ulOpenMode |= OPEN_FLAGS_RANDOM; 00814 ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR; 00815 ulOpenMode |= OPEN_FLAGS_NOINHERIT; 00816 00817 zNameCp = convertUtf8PathToCp( zName ); 00818 rc = DosOpen( (PSZ)zNameCp, 00819 &h, 00820 &ulAction, 00821 0L, 00822 ulFileAttribute, 00823 ulOpenFlags, 00824 ulOpenMode, 00825 (PEAOP2)NULL ); 00826 free( zNameCp ); 00827 if( rc != NO_ERROR ){ 00828 OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n", 00829 rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ); 00830 if( pFile->pathToDel ) 00831 free( pFile->pathToDel ); 00832 pFile->pathToDel = NULL; 00833 if( flags & SQLITE_OPEN_READWRITE ){ 00834 OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ); 00835 return os2Open( pVfs, zName, id, 00836 ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE), 00837 pOutFlags ); 00838 }else{ 00839 return SQLITE_CANTOPEN; 00840 } 00841 } 00842 00843 if( pOutFlags ){ 00844 *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; 00845 } 00846 00847 pFile->pMethod = &os2IoMethod; 00848 pFile->h = h; 00849 OpenCounter(+1); 00850 OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ); 00851 return SQLITE_OK; 00852 } 00853 00854 /* 00855 ** Delete the named file. 00856 */ 00857 static int os2Delete( 00858 sqlite3_vfs *pVfs, /* Not used on os2 */ 00859 const char *zFilename, /* Name of file to delete */ 00860 int syncDir /* Not used on os2 */ 00861 ){ 00862 APIRET rc = NO_ERROR; 00863 char *zFilenameCp = convertUtf8PathToCp( zFilename ); 00864 SimulateIOError( return SQLITE_IOERR_DELETE ); 00865 rc = DosDelete( (PSZ)zFilenameCp ); 00866 free( zFilenameCp ); 00867 OSTRACE2( "DELETE \"%s\"\n", zFilename ); 00868 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE; 00869 } 00870 00871 /* 00872 ** Check the existance and status of a file. 00873 */ 00874 static int os2Access( 00875 sqlite3_vfs *pVfs, /* Not used on os2 */ 00876 const char *zFilename, /* Name of file to check */ 00877 int flags, /* Type of test to make on this file */ 00878 int *pOut /* Write results here */ 00879 ){ 00880 FILESTATUS3 fsts3ConfigInfo; 00881 APIRET rc = NO_ERROR; 00882 char *zFilenameCp = convertUtf8PathToCp( zFilename ); 00883 00884 memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) ); 00885 rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, 00886 &fsts3ConfigInfo, sizeof(FILESTATUS3) ); 00887 free( zFilenameCp ); 00888 OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", 00889 fsts3ConfigInfo.attrFile, flags, rc ); 00890 switch( flags ){ 00891 case SQLITE_ACCESS_READ: 00892 case SQLITE_ACCESS_EXISTS: 00893 rc = (rc == NO_ERROR); 00894 OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc ); 00895 break; 00896 case SQLITE_ACCESS_READWRITE: 00897 rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 ); 00898 OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc ); 00899 break; 00900 default: 00901 assert( !"Invalid flags argument" ); 00902 } 00903 *pOut = rc; 00904 return SQLITE_OK; 00905 } 00906 00907 00908 #ifndef SQLITE_OMIT_LOAD_EXTENSION 00909 /* 00910 ** Interfaces for opening a shared library, finding entry points 00911 ** within the shared library, and closing the shared library. 00912 */ 00913 /* 00914 ** Interfaces for opening a shared library, finding entry points 00915 ** within the shared library, and closing the shared library. 00916 */ 00917 static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ 00918 UCHAR loadErr[256]; 00919 HMODULE hmod; 00920 APIRET rc; 00921 char *zFilenameCp = convertUtf8PathToCp(zFilename); 00922 rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod); 00923 free(zFilenameCp); 00924 return rc != NO_ERROR ? 0 : (void*)hmod; 00925 } 00926 /* 00927 ** A no-op since the error code is returned on the DosLoadModule call. 00928 ** os2Dlopen returns zero if DosLoadModule is not successful. 00929 */ 00930 static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ 00931 /* no-op */ 00932 } 00933 static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ 00934 PFN pfn; 00935 APIRET rc; 00936 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); 00937 if( rc != NO_ERROR ){ 00938 /* if the symbol itself was not found, search again for the same 00939 * symbol with an extra underscore, that might be needed depending 00940 * on the calling convention */ 00941 char _zSymbol[256] = "_"; 00942 strncat(_zSymbol, zSymbol, 255); 00943 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); 00944 } 00945 return rc != NO_ERROR ? 0 : (void*)pfn; 00946 } 00947 static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ 00948 DosFreeModule((HMODULE)pHandle); 00949 } 00950 #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ 00951 #define os2DlOpen 0 00952 #define os2DlError 0 00953 #define os2DlSym 0 00954 #define os2DlClose 0 00955 #endif 00956 00957 00958 /* 00959 ** Write up to nBuf bytes of randomness into zBuf. 00960 */ 00961 static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){ 00962 ULONG sizeofULong = sizeof(ULONG); 00963 int n = 0; 00964 if( sizeof(DATETIME) <= nBuf - n ){ 00965 DATETIME x; 00966 DosGetDateTime(&x); 00967 memcpy(&zBuf[n], &x, sizeof(x)); 00968 n += sizeof(x); 00969 } 00970 00971 if( sizeofULong <= nBuf - n ){ 00972 PPIB ppib; 00973 DosGetInfoBlocks(NULL, &ppib); 00974 memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong); 00975 n += sizeofULong; 00976 } 00977 00978 if( sizeofULong <= nBuf - n ){ 00979 PTIB ptib; 00980 DosGetInfoBlocks(&ptib, NULL); 00981 memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong); 00982 n += sizeofULong; 00983 } 00984 00985 /* if we still haven't filled the buffer yet the following will */ 00986 /* grab everything once instead of making several calls for a single item */ 00987 if( sizeofULong <= nBuf - n ){ 00988 ULONG ulSysInfo[QSV_MAX]; 00989 DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX); 00990 00991 memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong); 00992 n += sizeofULong; 00993 00994 if( sizeofULong <= nBuf - n ){ 00995 memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong); 00996 n += sizeofULong; 00997 } 00998 if( sizeofULong <= nBuf - n ){ 00999 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong); 01000 n += sizeofULong; 01001 } 01002 if( sizeofULong <= nBuf - n ){ 01003 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong); 01004 n += sizeofULong; 01005 } 01006 if( sizeofULong <= nBuf - n ){ 01007 memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong); 01008 n += sizeofULong; 01009 } 01010 } 01011 01012 return n; 01013 } 01014 01015 /* 01016 ** Sleep for a little while. Return the amount of time slept. 01017 ** The argument is the number of microseconds we want to sleep. 01018 ** The return value is the number of microseconds of sleep actually 01019 ** requested from the underlying operating system, a number which 01020 ** might be greater than or equal to the argument, but not less 01021 ** than the argument. 01022 */ 01023 static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){ 01024 DosSleep( (microsec/1000) ); 01025 return microsec; 01026 } 01027 01028 /* 01029 ** The following variable, if set to a non-zero value, becomes the result 01030 ** returned from sqlite3OsCurrentTime(). This is used for testing. 01031 */ 01032 #ifdef SQLITE_TEST 01033 int sqlite3_current_time = 0; 01034 #endif 01035 01036 /* 01037 ** Find the current time (in Universal Coordinated Time). Write the 01038 ** current time and date as a Julian Day number into *prNow and 01039 ** return 0. Return 1 if the time and date cannot be found. 01040 */ 01041 int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ 01042 double now; 01043 SHORT minute; /* needs to be able to cope with negative timezone offset */ 01044 USHORT second, hour, 01045 day, month, year; 01046 DATETIME dt; 01047 DosGetDateTime( &dt ); 01048 second = (USHORT)dt.seconds; 01049 minute = (SHORT)dt.minutes + dt.timezone; 01050 hour = (USHORT)dt.hours; 01051 day = (USHORT)dt.day; 01052 month = (USHORT)dt.month; 01053 year = (USHORT)dt.year; 01054 01055 /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html 01056 http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ 01057 /* Calculate the Julian days */ 01058 now = day - 32076 + 01059 1461*(year + 4800 + (month - 14)/12)/4 + 01060 367*(month - 2 - (month - 14)/12*12)/12 - 01061 3*((year + 4900 + (month - 14)/12)/100)/4; 01062 01063 /* Add the fractional hours, mins and seconds */ 01064 now += (hour + 12.0)/24.0; 01065 now += minute/1440.0; 01066 now += second/86400.0; 01067 *prNow = now; 01068 #ifdef SQLITE_TEST 01069 if( sqlite3_current_time ){ 01070 *prNow = sqlite3_current_time/86400.0 + 2440587.5; 01071 } 01072 #endif 01073 return 0; 01074 } 01075 01076 static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ 01077 return 0; 01078 } 01079 01080 /* 01081 ** Initialize and deinitialize the operating system interface. 01082 */ 01083 int sqlite3_os_init(void){ 01084 static sqlite3_vfs os2Vfs = { 01085 1, /* iVersion */ 01086 sizeof(os2File), /* szOsFile */ 01087 CCHMAXPATH, /* mxPathname */ 01088 0, /* pNext */ 01089 "os2", /* zName */ 01090 0, /* pAppData */ 01091 01092 os2Open, /* xOpen */ 01093 os2Delete, /* xDelete */ 01094 os2Access, /* xAccess */ 01095 os2FullPathname, /* xFullPathname */ 01096 os2DlOpen, /* xDlOpen */ 01097 os2DlError, /* xDlError */ 01098 os2DlSym, /* xDlSym */ 01099 os2DlClose, /* xDlClose */ 01100 os2Randomness, /* xRandomness */ 01101 os2Sleep, /* xSleep */ 01102 os2CurrentTime, /* xCurrentTime */ 01103 os2GetLastError /* xGetLastError */ 01104 }; 01105 sqlite3_vfs_register(&os2Vfs, 1); 01106 initUconvObjects(); 01107 return SQLITE_OK; 01108 } 01109 int sqlite3_os_end(void){ 01110 freeUconvObjects(); 01111 return SQLITE_OK; 01112 } 01113 01114 #endif /* SQLITE_OS_OS2 */
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:55 2011 by Doxygen 1.6.1