| 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 |