Annotation of embedaddon/sqlite3/src/os_os2.c, revision 1.1
1.1 ! misho 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:
! 16: #include "sqliteInt.h"
! 17:
! 18: #if SQLITE_OS_OS2
! 19:
! 20: /*
! 21: ** A Note About Memory Allocation:
! 22: **
! 23: ** This driver uses malloc()/free() directly rather than going through
! 24: ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers
! 25: ** are designed for use on embedded systems where memory is scarce and
! 26: ** malloc failures happen frequently. OS/2 does not typically run on
! 27: ** embedded systems, and when it does the developers normally have bigger
! 28: ** problems to worry about than running out of memory. So there is not
! 29: ** a compelling need to use the wrappers.
! 30: **
! 31: ** But there is a good reason to not use the wrappers. If we use the
! 32: ** wrappers then we will get simulated malloc() failures within this
! 33: ** driver. And that causes all kinds of problems for our tests. We
! 34: ** could enhance SQLite to deal with simulated malloc failures within
! 35: ** the OS driver, but the code to deal with those failure would not
! 36: ** be exercised on Linux (which does not need to malloc() in the driver)
! 37: ** and so we would have difficulty writing coverage tests for that
! 38: ** code. Better to leave the code out, we think.
! 39: **
! 40: ** The point of this discussion is as follows: When creating a new
! 41: ** OS layer for an embedded system, if you use this file as an example,
! 42: ** avoid the use of malloc()/free(). Those routines work ok on OS/2
! 43: ** desktops but not so well in embedded systems.
! 44: */
! 45:
! 46: /*
! 47: ** Macros used to determine whether or not to use threads.
! 48: */
! 49: #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE
! 50: # define SQLITE_OS2_THREADS 1
! 51: #endif
! 52:
! 53: /*
! 54: ** Include code that is common to all os_*.c files
! 55: */
! 56: #include "os_common.h"
! 57:
! 58: /* Forward references */
! 59: typedef struct os2File os2File; /* The file structure */
! 60: typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */
! 61: typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */
! 62:
! 63: /*
! 64: ** The os2File structure is subclass of sqlite3_file specific for the OS/2
! 65: ** protability layer.
! 66: */
! 67: struct os2File {
! 68: const sqlite3_io_methods *pMethod; /* Always the first entry */
! 69: HFILE h; /* Handle for accessing the file */
! 70: int flags; /* Flags provided to os2Open() */
! 71: int locktype; /* Type of lock currently held on this file */
! 72: int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
! 73: char *zFullPathCp; /* Full path name of this file */
! 74: os2ShmLink *pShmLink; /* Instance of shared memory on this file */
! 75: };
! 76:
! 77: #define LOCK_TIMEOUT 10L /* the default locking timeout */
! 78:
! 79: /*
! 80: ** Missing from some versions of the OS/2 toolkit -
! 81: ** used to allocate from high memory if possible
! 82: */
! 83: #ifndef OBJ_ANY
! 84: # define OBJ_ANY 0x00000400
! 85: #endif
! 86:
! 87: /*****************************************************************************
! 88: ** The next group of routines implement the I/O methods specified
! 89: ** by the sqlite3_io_methods object.
! 90: ******************************************************************************/
! 91:
! 92: /*
! 93: ** Close a file.
! 94: */
! 95: static int os2Close( sqlite3_file *id ){
! 96: APIRET rc;
! 97: os2File *pFile = (os2File*)id;
! 98:
! 99: assert( id!=0 );
! 100: OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp ));
! 101:
! 102: rc = DosClose( pFile->h );
! 103:
! 104: if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE )
! 105: DosForceDelete( (PSZ)pFile->zFullPathCp );
! 106:
! 107: free( pFile->zFullPathCp );
! 108: pFile->zFullPathCp = NULL;
! 109: pFile->locktype = NO_LOCK;
! 110: pFile->h = (HFILE)-1;
! 111: pFile->flags = 0;
! 112:
! 113: OpenCounter( -1 );
! 114: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
! 115: }
! 116:
! 117: /*
! 118: ** Read data from a file into a buffer. Return SQLITE_OK if all
! 119: ** bytes were read successfully and SQLITE_IOERR if anything goes
! 120: ** wrong.
! 121: */
! 122: static int os2Read(
! 123: sqlite3_file *id, /* File to read from */
! 124: void *pBuf, /* Write content into this buffer */
! 125: int amt, /* Number of bytes to read */
! 126: sqlite3_int64 offset /* Begin reading at this offset */
! 127: ){
! 128: ULONG fileLocation = 0L;
! 129: ULONG got;
! 130: os2File *pFile = (os2File*)id;
! 131: assert( id!=0 );
! 132: SimulateIOError( return SQLITE_IOERR_READ );
! 133: OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype ));
! 134: if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
! 135: return SQLITE_IOERR;
! 136: }
! 137: if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){
! 138: return SQLITE_IOERR_READ;
! 139: }
! 140: if( got == (ULONG)amt )
! 141: return SQLITE_OK;
! 142: else {
! 143: /* Unread portions of the input buffer must be zero-filled */
! 144: memset(&((char*)pBuf)[got], 0, amt-got);
! 145: return SQLITE_IOERR_SHORT_READ;
! 146: }
! 147: }
! 148:
! 149: /*
! 150: ** Write data from a buffer into a file. Return SQLITE_OK on success
! 151: ** or some other error code on failure.
! 152: */
! 153: static int os2Write(
! 154: sqlite3_file *id, /* File to write into */
! 155: const void *pBuf, /* The bytes to be written */
! 156: int amt, /* Number of bytes to write */
! 157: sqlite3_int64 offset /* Offset into the file to begin writing at */
! 158: ){
! 159: ULONG fileLocation = 0L;
! 160: APIRET rc = NO_ERROR;
! 161: ULONG wrote;
! 162: os2File *pFile = (os2File*)id;
! 163: assert( id!=0 );
! 164: SimulateIOError( return SQLITE_IOERR_WRITE );
! 165: SimulateDiskfullError( return SQLITE_FULL );
! 166: OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ));
! 167: if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
! 168: return SQLITE_IOERR;
! 169: }
! 170: assert( amt>0 );
! 171: while( amt > 0 &&
! 172: ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR &&
! 173: wrote > 0
! 174: ){
! 175: amt -= wrote;
! 176: pBuf = &((char*)pBuf)[wrote];
! 177: }
! 178:
! 179: return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
! 180: }
! 181:
! 182: /*
! 183: ** Truncate an open file to a specified size
! 184: */
! 185: static int os2Truncate( sqlite3_file *id, i64 nByte ){
! 186: APIRET rc;
! 187: os2File *pFile = (os2File*)id;
! 188: assert( id!=0 );
! 189: OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
! 190: SimulateIOError( return SQLITE_IOERR_TRUNCATE );
! 191:
! 192: /* If the user has configured a chunk-size for this file, truncate the
! 193: ** file so that it consists of an integer number of chunks (i.e. the
! 194: ** actual file size after the operation may be larger than the requested
! 195: ** size).
! 196: */
! 197: if( pFile->szChunk ){
! 198: nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
! 199: }
! 200:
! 201: rc = DosSetFileSize( pFile->h, nByte );
! 202: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
! 203: }
! 204:
! 205: #ifdef SQLITE_TEST
! 206: /*
! 207: ** Count the number of fullsyncs and normal syncs. This is used to test
! 208: ** that syncs and fullsyncs are occuring at the right times.
! 209: */
! 210: int sqlite3_sync_count = 0;
! 211: int sqlite3_fullsync_count = 0;
! 212: #endif
! 213:
! 214: /*
! 215: ** Make sure all writes to a particular file are committed to disk.
! 216: */
! 217: static int os2Sync( sqlite3_file *id, int flags ){
! 218: os2File *pFile = (os2File*)id;
! 219: OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ));
! 220: #ifdef SQLITE_TEST
! 221: if( flags & SQLITE_SYNC_FULL){
! 222: sqlite3_fullsync_count++;
! 223: }
! 224: sqlite3_sync_count++;
! 225: #endif
! 226: /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
! 227: ** no-op
! 228: */
! 229: #ifdef SQLITE_NO_SYNC
! 230: UNUSED_PARAMETER(pFile);
! 231: return SQLITE_OK;
! 232: #else
! 233: return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
! 234: #endif
! 235: }
! 236:
! 237: /*
! 238: ** Determine the current size of a file in bytes
! 239: */
! 240: static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){
! 241: APIRET rc = NO_ERROR;
! 242: FILESTATUS3 fsts3FileInfo;
! 243: memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo));
! 244: assert( id!=0 );
! 245: SimulateIOError( return SQLITE_IOERR_FSTAT );
! 246: rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) );
! 247: if( rc == NO_ERROR ){
! 248: *pSize = fsts3FileInfo.cbFile;
! 249: return SQLITE_OK;
! 250: }else{
! 251: return SQLITE_IOERR_FSTAT;
! 252: }
! 253: }
! 254:
! 255: /*
! 256: ** Acquire a reader lock.
! 257: */
! 258: static int getReadLock( os2File *pFile ){
! 259: FILELOCK LockArea,
! 260: UnlockArea;
! 261: APIRET res;
! 262: memset(&LockArea, 0, sizeof(LockArea));
! 263: memset(&UnlockArea, 0, sizeof(UnlockArea));
! 264: LockArea.lOffset = SHARED_FIRST;
! 265: LockArea.lRange = SHARED_SIZE;
! 266: UnlockArea.lOffset = 0L;
! 267: UnlockArea.lRange = 0L;
! 268: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
! 269: OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res ));
! 270: return res;
! 271: }
! 272:
! 273: /*
! 274: ** Undo a readlock
! 275: */
! 276: static int unlockReadLock( os2File *id ){
! 277: FILELOCK LockArea,
! 278: UnlockArea;
! 279: APIRET res;
! 280: memset(&LockArea, 0, sizeof(LockArea));
! 281: memset(&UnlockArea, 0, sizeof(UnlockArea));
! 282: LockArea.lOffset = 0L;
! 283: LockArea.lRange = 0L;
! 284: UnlockArea.lOffset = SHARED_FIRST;
! 285: UnlockArea.lRange = SHARED_SIZE;
! 286: res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
! 287: OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ));
! 288: return res;
! 289: }
! 290:
! 291: /*
! 292: ** Lock the file with the lock specified by parameter locktype - one
! 293: ** of the following:
! 294: **
! 295: ** (1) SHARED_LOCK
! 296: ** (2) RESERVED_LOCK
! 297: ** (3) PENDING_LOCK
! 298: ** (4) EXCLUSIVE_LOCK
! 299: **
! 300: ** Sometimes when requesting one lock state, additional lock states
! 301: ** are inserted in between. The locking might fail on one of the later
! 302: ** transitions leaving the lock state different from what it started but
! 303: ** still short of its goal. The following chart shows the allowed
! 304: ** transitions and the inserted intermediate states:
! 305: **
! 306: ** UNLOCKED -> SHARED
! 307: ** SHARED -> RESERVED
! 308: ** SHARED -> (PENDING) -> EXCLUSIVE
! 309: ** RESERVED -> (PENDING) -> EXCLUSIVE
! 310: ** PENDING -> EXCLUSIVE
! 311: **
! 312: ** This routine will only increase a lock. The os2Unlock() routine
! 313: ** erases all locks at once and returns us immediately to locking level 0.
! 314: ** It is not possible to lower the locking level one step at a time. You
! 315: ** must go straight to locking level 0.
! 316: */
! 317: static int os2Lock( sqlite3_file *id, int locktype ){
! 318: int rc = SQLITE_OK; /* Return code from subroutines */
! 319: APIRET res = NO_ERROR; /* Result of an OS/2 lock call */
! 320: int newLocktype; /* Set pFile->locktype to this value before exiting */
! 321: int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
! 322: FILELOCK LockArea,
! 323: UnlockArea;
! 324: os2File *pFile = (os2File*)id;
! 325: memset(&LockArea, 0, sizeof(LockArea));
! 326: memset(&UnlockArea, 0, sizeof(UnlockArea));
! 327: assert( pFile!=0 );
! 328: OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ));
! 329:
! 330: /* If there is already a lock of this type or more restrictive on the
! 331: ** os2File, do nothing. Don't use the end_lock: exit path, as
! 332: ** sqlite3_mutex_enter() hasn't been called yet.
! 333: */
! 334: if( pFile->locktype>=locktype ){
! 335: OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype ));
! 336: return SQLITE_OK;
! 337: }
! 338:
! 339: /* Make sure the locking sequence is correct
! 340: */
! 341: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
! 342: assert( locktype!=PENDING_LOCK );
! 343: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
! 344:
! 345: /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
! 346: ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
! 347: ** the PENDING_LOCK byte is temporary.
! 348: */
! 349: newLocktype = pFile->locktype;
! 350: if( pFile->locktype==NO_LOCK
! 351: || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
! 352: ){
! 353: LockArea.lOffset = PENDING_BYTE;
! 354: LockArea.lRange = 1L;
! 355: UnlockArea.lOffset = 0L;
! 356: UnlockArea.lRange = 0L;
! 357:
! 358: /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */
! 359: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
! 360: if( res == NO_ERROR ){
! 361: gotPendingLock = 1;
! 362: OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ));
! 363: }
! 364: }
! 365:
! 366: /* Acquire a shared lock
! 367: */
! 368: if( locktype==SHARED_LOCK && res == NO_ERROR ){
! 369: assert( pFile->locktype==NO_LOCK );
! 370: res = getReadLock(pFile);
! 371: if( res == NO_ERROR ){
! 372: newLocktype = SHARED_LOCK;
! 373: }
! 374: OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ));
! 375: }
! 376:
! 377: /* Acquire a RESERVED lock
! 378: */
! 379: if( locktype==RESERVED_LOCK && res == NO_ERROR ){
! 380: assert( pFile->locktype==SHARED_LOCK );
! 381: LockArea.lOffset = RESERVED_BYTE;
! 382: LockArea.lRange = 1L;
! 383: UnlockArea.lOffset = 0L;
! 384: UnlockArea.lRange = 0L;
! 385: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 386: if( res == NO_ERROR ){
! 387: newLocktype = RESERVED_LOCK;
! 388: }
! 389: OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ));
! 390: }
! 391:
! 392: /* Acquire a PENDING lock
! 393: */
! 394: if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
! 395: newLocktype = PENDING_LOCK;
! 396: gotPendingLock = 0;
! 397: OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n",
! 398: pFile->h ));
! 399: }
! 400:
! 401: /* Acquire an EXCLUSIVE lock
! 402: */
! 403: if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
! 404: assert( pFile->locktype>=SHARED_LOCK );
! 405: res = unlockReadLock(pFile);
! 406: OSTRACE(( "unreadlock = %d\n", res ));
! 407: LockArea.lOffset = SHARED_FIRST;
! 408: LockArea.lRange = SHARED_SIZE;
! 409: UnlockArea.lOffset = 0L;
! 410: UnlockArea.lRange = 0L;
! 411: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 412: if( res == NO_ERROR ){
! 413: newLocktype = EXCLUSIVE_LOCK;
! 414: }else{
! 415: OSTRACE(( "OS/2 error-code = %d\n", res ));
! 416: getReadLock(pFile);
! 417: }
! 418: OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ));
! 419: }
! 420:
! 421: /* If we are holding a PENDING lock that ought to be released, then
! 422: ** release it now.
! 423: */
! 424: if( gotPendingLock && locktype==SHARED_LOCK ){
! 425: int r;
! 426: LockArea.lOffset = 0L;
! 427: LockArea.lRange = 0L;
! 428: UnlockArea.lOffset = PENDING_BYTE;
! 429: UnlockArea.lRange = 1L;
! 430: r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 431: OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ));
! 432: }
! 433:
! 434: /* Update the state of the lock has held in the file descriptor then
! 435: ** return the appropriate result code.
! 436: */
! 437: if( res == NO_ERROR ){
! 438: rc = SQLITE_OK;
! 439: }else{
! 440: OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
! 441: locktype, newLocktype ));
! 442: rc = SQLITE_BUSY;
! 443: }
! 444: pFile->locktype = newLocktype;
! 445: OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype ));
! 446: return rc;
! 447: }
! 448:
! 449: /*
! 450: ** This routine checks if there is a RESERVED lock held on the specified
! 451: ** file by this or any other process. If such a lock is held, return
! 452: ** non-zero, otherwise zero.
! 453: */
! 454: static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
! 455: int r = 0;
! 456: os2File *pFile = (os2File*)id;
! 457: assert( pFile!=0 );
! 458: if( pFile->locktype>=RESERVED_LOCK ){
! 459: r = 1;
! 460: OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ));
! 461: }else{
! 462: FILELOCK LockArea,
! 463: UnlockArea;
! 464: APIRET rc = NO_ERROR;
! 465: memset(&LockArea, 0, sizeof(LockArea));
! 466: memset(&UnlockArea, 0, sizeof(UnlockArea));
! 467: LockArea.lOffset = RESERVED_BYTE;
! 468: LockArea.lRange = 1L;
! 469: UnlockArea.lOffset = 0L;
! 470: UnlockArea.lRange = 0L;
! 471: rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 472: OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ));
! 473: if( rc == NO_ERROR ){
! 474: APIRET rcu = NO_ERROR; /* return code for unlocking */
! 475: LockArea.lOffset = 0L;
! 476: LockArea.lRange = 0L;
! 477: UnlockArea.lOffset = RESERVED_BYTE;
! 478: UnlockArea.lRange = 1L;
! 479: rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 480: OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ));
! 481: }
! 482: r = !(rc == NO_ERROR);
! 483: OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ));
! 484: }
! 485: *pOut = r;
! 486: return SQLITE_OK;
! 487: }
! 488:
! 489: /*
! 490: ** Lower the locking level on file descriptor id to locktype. locktype
! 491: ** must be either NO_LOCK or SHARED_LOCK.
! 492: **
! 493: ** If the locking level of the file descriptor is already at or below
! 494: ** the requested locking level, this routine is a no-op.
! 495: **
! 496: ** It is not possible for this routine to fail if the second argument
! 497: ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
! 498: ** might return SQLITE_IOERR;
! 499: */
! 500: static int os2Unlock( sqlite3_file *id, int locktype ){
! 501: int type;
! 502: os2File *pFile = (os2File*)id;
! 503: APIRET rc = SQLITE_OK;
! 504: APIRET res = NO_ERROR;
! 505: FILELOCK LockArea,
! 506: UnlockArea;
! 507: memset(&LockArea, 0, sizeof(LockArea));
! 508: memset(&UnlockArea, 0, sizeof(UnlockArea));
! 509: assert( pFile!=0 );
! 510: assert( locktype<=SHARED_LOCK );
! 511: OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ));
! 512: type = pFile->locktype;
! 513: if( type>=EXCLUSIVE_LOCK ){
! 514: LockArea.lOffset = 0L;
! 515: LockArea.lRange = 0L;
! 516: UnlockArea.lOffset = SHARED_FIRST;
! 517: UnlockArea.lRange = SHARED_SIZE;
! 518: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 519: OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ));
! 520: if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
! 521: /* This should never happen. We should always be able to
! 522: ** reacquire the read lock */
! 523: OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ));
! 524: rc = SQLITE_IOERR_UNLOCK;
! 525: }
! 526: }
! 527: if( type>=RESERVED_LOCK ){
! 528: LockArea.lOffset = 0L;
! 529: LockArea.lRange = 0L;
! 530: UnlockArea.lOffset = RESERVED_BYTE;
! 531: UnlockArea.lRange = 1L;
! 532: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 533: OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res ));
! 534: }
! 535: if( locktype==NO_LOCK && type>=SHARED_LOCK ){
! 536: res = unlockReadLock(pFile);
! 537: OSTRACE(( "UNLOCK %d is %d want %d res=%d\n",
! 538: pFile->h, type, locktype, res ));
! 539: }
! 540: if( type>=PENDING_LOCK ){
! 541: LockArea.lOffset = 0L;
! 542: LockArea.lRange = 0L;
! 543: UnlockArea.lOffset = PENDING_BYTE;
! 544: UnlockArea.lRange = 1L;
! 545: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
! 546: OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res ));
! 547: }
! 548: pFile->locktype = locktype;
! 549: OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ));
! 550: return rc;
! 551: }
! 552:
! 553: /*
! 554: ** Control and query of the open file handle.
! 555: */
! 556: static int os2FileControl(sqlite3_file *id, int op, void *pArg){
! 557: switch( op ){
! 558: case SQLITE_FCNTL_LOCKSTATE: {
! 559: *(int*)pArg = ((os2File*)id)->locktype;
! 560: OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
! 561: ((os2File*)id)->h, ((os2File*)id)->locktype ));
! 562: return SQLITE_OK;
! 563: }
! 564: case SQLITE_FCNTL_CHUNK_SIZE: {
! 565: ((os2File*)id)->szChunk = *(int*)pArg;
! 566: return SQLITE_OK;
! 567: }
! 568: case SQLITE_FCNTL_SIZE_HINT: {
! 569: sqlite3_int64 sz = *(sqlite3_int64*)pArg;
! 570: SimulateIOErrorBenign(1);
! 571: os2Truncate(id, sz);
! 572: SimulateIOErrorBenign(0);
! 573: return SQLITE_OK;
! 574: }
! 575: case SQLITE_FCNTL_SYNC_OMITTED: {
! 576: return SQLITE_OK;
! 577: }
! 578: }
! 579: return SQLITE_NOTFOUND;
! 580: }
! 581:
! 582: /*
! 583: ** Return the sector size in bytes of the underlying block device for
! 584: ** the specified file. This is almost always 512 bytes, but may be
! 585: ** larger for some devices.
! 586: **
! 587: ** SQLite code assumes this function cannot fail. It also assumes that
! 588: ** if two files are created in the same file-system directory (i.e.
! 589: ** a database and its journal file) that the sector size will be the
! 590: ** same for both.
! 591: */
! 592: static int os2SectorSize(sqlite3_file *id){
! 593: UNUSED_PARAMETER(id);
! 594: return SQLITE_DEFAULT_SECTOR_SIZE;
! 595: }
! 596:
! 597: /*
! 598: ** Return a vector of device characteristics.
! 599: */
! 600: static int os2DeviceCharacteristics(sqlite3_file *id){
! 601: UNUSED_PARAMETER(id);
! 602: return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
! 603: }
! 604:
! 605:
! 606: /*
! 607: ** Character set conversion objects used by conversion routines.
! 608: */
! 609: static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
! 610: static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */
! 611:
! 612: /*
! 613: ** Helper function to initialize the conversion objects from and to UTF-8.
! 614: */
! 615: static void initUconvObjects( void ){
! 616: if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS )
! 617: ucUtf8 = NULL;
! 618: if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS )
! 619: uclCp = NULL;
! 620: }
! 621:
! 622: /*
! 623: ** Helper function to free the conversion objects from and to UTF-8.
! 624: */
! 625: static void freeUconvObjects( void ){
! 626: if ( ucUtf8 )
! 627: UniFreeUconvObject( ucUtf8 );
! 628: if ( uclCp )
! 629: UniFreeUconvObject( uclCp );
! 630: ucUtf8 = NULL;
! 631: uclCp = NULL;
! 632: }
! 633:
! 634: /*
! 635: ** Helper function to convert UTF-8 filenames to local OS/2 codepage.
! 636: ** The two-step process: first convert the incoming UTF-8 string
! 637: ** into UCS-2 and then from UCS-2 to the current codepage.
! 638: ** The returned char pointer has to be freed.
! 639: */
! 640: static char *convertUtf8PathToCp( const char *in ){
! 641: UniChar tempPath[CCHMAXPATH];
! 642: char *out = (char *)calloc( CCHMAXPATH, 1 );
! 643:
! 644: if( !out )
! 645: return NULL;
! 646:
! 647: if( !ucUtf8 || !uclCp )
! 648: initUconvObjects();
! 649:
! 650: /* determine string for the conversion of UTF-8 which is CP1208 */
! 651: if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
! 652: return out; /* if conversion fails, return the empty string */
! 653:
! 654: /* conversion for current codepage which can be used for paths */
! 655: UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH );
! 656:
! 657: return out;
! 658: }
! 659:
! 660: /*
! 661: ** Helper function to convert filenames from local codepage to UTF-8.
! 662: ** The two-step process: first convert the incoming codepage-specific
! 663: ** string into UCS-2 and then from UCS-2 to the codepage of UTF-8.
! 664: ** The returned char pointer has to be freed.
! 665: **
! 666: ** This function is non-static to be able to use this in shell.c and
! 667: ** similar applications that take command line arguments.
! 668: */
! 669: char *convertCpPathToUtf8( const char *in ){
! 670: UniChar tempPath[CCHMAXPATH];
! 671: char *out = (char *)calloc( CCHMAXPATH, 1 );
! 672:
! 673: if( !out )
! 674: return NULL;
! 675:
! 676: if( !ucUtf8 || !uclCp )
! 677: initUconvObjects();
! 678:
! 679: /* conversion for current codepage which can be used for paths */
! 680: if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
! 681: return out; /* if conversion fails, return the empty string */
! 682:
! 683: /* determine string for the conversion of UTF-8 which is CP1208 */
! 684: UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );
! 685:
! 686: return out;
! 687: }
! 688:
! 689:
! 690: #ifndef SQLITE_OMIT_WAL
! 691:
! 692: /*
! 693: ** Use main database file for interprocess locking. If un-defined
! 694: ** a separate file is created for this purpose. The file will be
! 695: ** used only to set file locks. There will be no data written to it.
! 696: */
! 697: #define SQLITE_OS2_NO_WAL_LOCK_FILE
! 698:
! 699: #if 0
! 700: static void _ERR_TRACE( const char *fmt, ... ) {
! 701: va_list ap;
! 702: va_start(ap, fmt);
! 703: vfprintf(stderr, fmt, ap);
! 704: fflush(stderr);
! 705: }
! 706: #define ERR_TRACE(rc, msg) \
! 707: if( (rc) != SQLITE_OK ) _ERR_TRACE msg;
! 708: #else
! 709: #define ERR_TRACE(rc, msg)
! 710: #endif
! 711:
! 712: /*
! 713: ** Helper functions to obtain and relinquish the global mutex. The
! 714: ** global mutex is used to protect os2ShmNodeList.
! 715: **
! 716: ** Function os2ShmMutexHeld() is used to assert() that the global mutex
! 717: ** is held when required. This function is only used as part of assert()
! 718: ** statements. e.g.
! 719: **
! 720: ** os2ShmEnterMutex()
! 721: ** assert( os2ShmMutexHeld() );
! 722: ** os2ShmLeaveMutex()
! 723: */
! 724: static void os2ShmEnterMutex(void){
! 725: sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
! 726: }
! 727: static void os2ShmLeaveMutex(void){
! 728: sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
! 729: }
! 730: #ifdef SQLITE_DEBUG
! 731: static int os2ShmMutexHeld(void) {
! 732: return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
! 733: }
! 734: int GetCurrentProcessId(void) {
! 735: PPIB pib;
! 736: DosGetInfoBlocks(NULL, &pib);
! 737: return (int)pib->pib_ulpid;
! 738: }
! 739: #endif
! 740:
! 741: /*
! 742: ** Object used to represent a the shared memory area for a single log file.
! 743: ** When multiple threads all reference the same log-summary, each thread has
! 744: ** its own os2File object, but they all point to a single instance of this
! 745: ** object. In other words, each log-summary is opened only once per process.
! 746: **
! 747: ** os2ShmMutexHeld() must be true when creating or destroying
! 748: ** this object or while reading or writing the following fields:
! 749: **
! 750: ** nRef
! 751: ** pNext
! 752: **
! 753: ** The following fields are read-only after the object is created:
! 754: **
! 755: ** szRegion
! 756: ** hLockFile
! 757: ** shmBaseName
! 758: **
! 759: ** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and
! 760: ** os2ShmMutexHeld() is true when reading or writing any other field
! 761: ** in this structure.
! 762: **
! 763: */
! 764: struct os2ShmNode {
! 765: sqlite3_mutex *mutex; /* Mutex to access this object */
! 766: os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */
! 767:
! 768: int szRegion; /* Size of shared-memory regions */
! 769:
! 770: int nRegion; /* Size of array apRegion */
! 771: void **apRegion; /* Array of pointers to shared-memory regions */
! 772:
! 773: int nRef; /* Number of os2ShmLink objects pointing to this */
! 774: os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */
! 775:
! 776: HFILE hLockFile; /* File used for inter-process memory locking */
! 777: char shmBaseName[1]; /* Name of the memory object !!! must last !!! */
! 778: };
! 779:
! 780:
! 781: /*
! 782: ** Structure used internally by this VFS to record the state of an
! 783: ** open shared memory connection.
! 784: **
! 785: ** The following fields are initialized when this object is created and
! 786: ** are read-only thereafter:
! 787: **
! 788: ** os2Shm.pShmNode
! 789: ** os2Shm.id
! 790: **
! 791: ** All other fields are read/write. The os2Shm.pShmNode->mutex must be held
! 792: ** while accessing any read/write fields.
! 793: */
! 794: struct os2ShmLink {
! 795: os2ShmNode *pShmNode; /* The underlying os2ShmNode object */
! 796: os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */
! 797: u32 sharedMask; /* Mask of shared locks held */
! 798: u32 exclMask; /* Mask of exclusive locks held */
! 799: #ifdef SQLITE_DEBUG
! 800: u8 id; /* Id of this connection with its os2ShmNode */
! 801: #endif
! 802: };
! 803:
! 804:
! 805: /*
! 806: ** A global list of all os2ShmNode objects.
! 807: **
! 808: ** The os2ShmMutexHeld() must be true while reading or writing this list.
! 809: */
! 810: static os2ShmNode *os2ShmNodeList = NULL;
! 811:
! 812: /*
! 813: ** Constants used for locking
! 814: */
! 815: #ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
! 816: #define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */
! 817: #else
! 818: #define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
! 819: #endif
! 820:
! 821: #define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
! 822:
! 823: /*
! 824: ** Apply advisory locks for all n bytes beginning at ofst.
! 825: */
! 826: #define _SHM_UNLCK 1 /* no lock */
! 827: #define _SHM_RDLCK 2 /* shared lock, no wait */
! 828: #define _SHM_WRLCK 3 /* exlusive lock, no wait */
! 829: #define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */
! 830: static int os2ShmSystemLock(
! 831: os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */
! 832: int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */
! 833: int ofst, /* Offset to first byte to be locked/unlocked */
! 834: int nByte /* Number of bytes to lock or unlock */
! 835: ){
! 836: APIRET rc;
! 837: FILELOCK area;
! 838: ULONG mode, timeout;
! 839:
! 840: /* Access to the os2ShmNode object is serialized by the caller */
! 841: assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 );
! 842:
! 843: mode = 1; /* shared lock */
! 844: timeout = 0; /* no wait */
! 845: area.lOffset = ofst;
! 846: area.lRange = nByte;
! 847:
! 848: switch( lockType ) {
! 849: case _SHM_WRLCK_WAIT:
! 850: timeout = (ULONG)-1; /* wait forever */
! 851: case _SHM_WRLCK:
! 852: mode = 0; /* exclusive lock */
! 853: case _SHM_RDLCK:
! 854: rc = DosSetFileLocks(pNode->hLockFile,
! 855: NULL, &area, timeout, mode);
! 856: break;
! 857: /* case _SHM_UNLCK: */
! 858: default:
! 859: rc = DosSetFileLocks(pNode->hLockFile,
! 860: &area, NULL, 0, 0);
! 861: break;
! 862: }
! 863:
! 864: OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
! 865: pNode->hLockFile,
! 866: rc==SQLITE_OK ? "ok" : "failed",
! 867: lockType==_SHM_UNLCK ? "Unlock" : "Lock",
! 868: rc));
! 869:
! 870: ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName))
! 871:
! 872: return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY;
! 873: }
! 874:
! 875: /*
! 876: ** Find an os2ShmNode in global list or allocate a new one, if not found.
! 877: **
! 878: ** This is not a VFS shared-memory method; it is a utility function called
! 879: ** by VFS shared-memory methods.
! 880: */
! 881: static int os2OpenSharedMemory( os2File *fd, int szRegion ) {
! 882: os2ShmLink *pLink;
! 883: os2ShmNode *pNode;
! 884: int cbShmName, rc = SQLITE_OK;
! 885: char shmName[CCHMAXPATH + 30];
! 886: #ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
! 887: ULONG action;
! 888: #endif
! 889:
! 890: /* We need some additional space at the end to append the region number */
! 891: cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp );
! 892: if( cbShmName >= CCHMAXPATH-8 )
! 893: return SQLITE_IOERR_SHMOPEN;
! 894:
! 895: /* Replace colon in file name to form a valid shared memory name */
! 896: shmName[10+1] = '!';
! 897:
! 898: /* Allocate link object (we free it later in case of failure) */
! 899: pLink = sqlite3_malloc( sizeof(*pLink) );
! 900: if( !pLink )
! 901: return SQLITE_NOMEM;
! 902:
! 903: /* Access node list */
! 904: os2ShmEnterMutex();
! 905:
! 906: /* Find node by it's shared memory base name */
! 907: for( pNode = os2ShmNodeList;
! 908: pNode && stricmp(shmName, pNode->shmBaseName) != 0;
! 909: pNode = pNode->pNext ) ;
! 910:
! 911: /* Not found: allocate a new node */
! 912: if( !pNode ) {
! 913: pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName );
! 914: if( pNode ) {
! 915: memset(pNode, 0, sizeof(*pNode) );
! 916: pNode->szRegion = szRegion;
! 917: pNode->hLockFile = (HFILE)-1;
! 918: strcpy(pNode->shmBaseName, shmName);
! 919:
! 920: #ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
! 921: if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) {
! 922: #else
! 923: sprintf(shmName, "%s-lck", fd->zFullPathCp);
! 924: if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL,
! 925: OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
! 926: OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE |
! 927: OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR,
! 928: NULL) != 0 ) {
! 929: #endif
! 930: sqlite3_free(pNode);
! 931: rc = SQLITE_IOERR;
! 932: } else {
! 933: pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
! 934: if( !pNode->mutex ) {
! 935: sqlite3_free(pNode);
! 936: rc = SQLITE_NOMEM;
! 937: }
! 938: }
! 939: } else {
! 940: rc = SQLITE_NOMEM;
! 941: }
! 942:
! 943: if( rc == SQLITE_OK ) {
! 944: pNode->pNext = os2ShmNodeList;
! 945: os2ShmNodeList = pNode;
! 946: } else {
! 947: pNode = NULL;
! 948: }
! 949: } else if( pNode->szRegion != szRegion ) {
! 950: rc = SQLITE_IOERR_SHMSIZE;
! 951: pNode = NULL;
! 952: }
! 953:
! 954: if( pNode ) {
! 955: sqlite3_mutex_enter(pNode->mutex);
! 956:
! 957: memset(pLink, 0, sizeof(*pLink));
! 958:
! 959: pLink->pShmNode = pNode;
! 960: pLink->pNext = pNode->pFirst;
! 961: pNode->pFirst = pLink;
! 962: pNode->nRef++;
! 963:
! 964: fd->pShmLink = pLink;
! 965:
! 966: sqlite3_mutex_leave(pNode->mutex);
! 967:
! 968: } else {
! 969: /* Error occured. Free our link object. */
! 970: sqlite3_free(pLink);
! 971: }
! 972:
! 973: os2ShmLeaveMutex();
! 974:
! 975: ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp))
! 976:
! 977: return rc;
! 978: }
! 979:
! 980: /*
! 981: ** Purge the os2ShmNodeList list of all entries with nRef==0.
! 982: **
! 983: ** This is not a VFS shared-memory method; it is a utility function called
! 984: ** by VFS shared-memory methods.
! 985: */
! 986: static void os2PurgeShmNodes( int deleteFlag ) {
! 987: os2ShmNode *pNode;
! 988: os2ShmNode **ppNode;
! 989:
! 990: os2ShmEnterMutex();
! 991:
! 992: ppNode = &os2ShmNodeList;
! 993:
! 994: while( *ppNode ) {
! 995: pNode = *ppNode;
! 996:
! 997: if( pNode->nRef == 0 ) {
! 998: *ppNode = pNode->pNext;
! 999:
! 1000: if( pNode->apRegion ) {
! 1001: /* Prevent other processes from resizing the shared memory */
! 1002: os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);
! 1003:
! 1004: while( pNode->nRegion-- ) {
! 1005: #ifdef SQLITE_DEBUG
! 1006: int rc =
! 1007: #endif
! 1008: DosFreeMem(pNode->apRegion[pNode->nRegion]);
! 1009:
! 1010: OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
! 1011: (int)GetCurrentProcessId(), pNode->nRegion,
! 1012: rc == 0 ? "ok" : "failed"));
! 1013: }
! 1014:
! 1015: /* Allow other processes to resize the shared memory */
! 1016: os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
! 1017:
! 1018: sqlite3_free(pNode->apRegion);
! 1019: }
! 1020:
! 1021: DosClose(pNode->hLockFile);
! 1022:
! 1023: #ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
! 1024: if( deleteFlag ) {
! 1025: char fileName[CCHMAXPATH];
! 1026: /* Skip "\\SHAREMEM\\" */
! 1027: sprintf(fileName, "%s-lck", pNode->shmBaseName + 10);
! 1028: /* restore colon */
! 1029: fileName[1] = ':';
! 1030:
! 1031: DosForceDelete(fileName);
! 1032: }
! 1033: #endif
! 1034:
! 1035: sqlite3_mutex_free(pNode->mutex);
! 1036:
! 1037: sqlite3_free(pNode);
! 1038:
! 1039: } else {
! 1040: ppNode = &pNode->pNext;
! 1041: }
! 1042: }
! 1043:
! 1044: os2ShmLeaveMutex();
! 1045: }
! 1046:
! 1047: /*
! 1048: ** This function is called to obtain a pointer to region iRegion of the
! 1049: ** shared-memory associated with the database file id. Shared-memory regions
! 1050: ** are numbered starting from zero. Each shared-memory region is szRegion
! 1051: ** bytes in size.
! 1052: **
! 1053: ** If an error occurs, an error code is returned and *pp is set to NULL.
! 1054: **
! 1055: ** Otherwise, if the bExtend parameter is 0 and the requested shared-memory
! 1056: ** region has not been allocated (by any client, including one running in a
! 1057: ** separate process), then *pp is set to NULL and SQLITE_OK returned. If
! 1058: ** bExtend is non-zero and the requested shared-memory region has not yet
! 1059: ** been allocated, it is allocated by this function.
! 1060: **
! 1061: ** If the shared-memory region has already been allocated or is allocated by
! 1062: ** this call as described above, then it is mapped into this processes
! 1063: ** address space (if it is not already), *pp is set to point to the mapped
! 1064: ** memory and SQLITE_OK returned.
! 1065: */
! 1066: static int os2ShmMap(
! 1067: sqlite3_file *id, /* Handle open on database file */
! 1068: int iRegion, /* Region to retrieve */
! 1069: int szRegion, /* Size of regions */
! 1070: int bExtend, /* True to extend block if necessary */
! 1071: void volatile **pp /* OUT: Mapped memory */
! 1072: ){
! 1073: PVOID pvTemp;
! 1074: void **apRegion;
! 1075: os2ShmNode *pNode;
! 1076: int n, rc = SQLITE_OK;
! 1077: char shmName[CCHMAXPATH];
! 1078: os2File *pFile = (os2File*)id;
! 1079:
! 1080: *pp = NULL;
! 1081:
! 1082: if( !pFile->pShmLink )
! 1083: rc = os2OpenSharedMemory( pFile, szRegion );
! 1084:
! 1085: if( rc == SQLITE_OK ) {
! 1086: pNode = pFile->pShmLink->pShmNode ;
! 1087:
! 1088: sqlite3_mutex_enter(pNode->mutex);
! 1089:
! 1090: assert( szRegion==pNode->szRegion );
! 1091:
! 1092: /* Unmapped region ? */
! 1093: if( iRegion >= pNode->nRegion ) {
! 1094: /* Prevent other processes from resizing the shared memory */
! 1095: os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);
! 1096:
! 1097: apRegion = sqlite3_realloc(
! 1098: pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0]));
! 1099:
! 1100: if( apRegion ) {
! 1101: pNode->apRegion = apRegion;
! 1102:
! 1103: while( pNode->nRegion <= iRegion ) {
! 1104: sprintf(shmName, "%s-%u",
! 1105: pNode->shmBaseName, pNode->nRegion);
! 1106:
! 1107: if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName,
! 1108: PAG_READ | PAG_WRITE) != NO_ERROR ) {
! 1109: if( !bExtend )
! 1110: break;
! 1111:
! 1112: if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
! 1113: PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR &&
! 1114: DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
! 1115: PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) {
! 1116: rc = SQLITE_NOMEM;
! 1117: break;
! 1118: }
! 1119: }
! 1120:
! 1121: apRegion[pNode->nRegion++] = pvTemp;
! 1122: }
! 1123:
! 1124: /* zero out remaining entries */
! 1125: for( n = pNode->nRegion; n <= iRegion; n++ )
! 1126: pNode->apRegion[n] = NULL;
! 1127:
! 1128: /* Return this region (maybe zero) */
! 1129: *pp = pNode->apRegion[iRegion];
! 1130: } else {
! 1131: rc = SQLITE_NOMEM;
! 1132: }
! 1133:
! 1134: /* Allow other processes to resize the shared memory */
! 1135: os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
! 1136:
! 1137: } else {
! 1138: /* Region has been mapped previously */
! 1139: *pp = pNode->apRegion[iRegion];
! 1140: }
! 1141:
! 1142: sqlite3_mutex_leave(pNode->mutex);
! 1143: }
! 1144:
! 1145: ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n",
! 1146: pFile->zFullPathCp, iRegion, szRegion, bExtend, rc))
! 1147:
! 1148: return rc;
! 1149: }
! 1150:
! 1151: /*
! 1152: ** Close a connection to shared-memory. Delete the underlying
! 1153: ** storage if deleteFlag is true.
! 1154: **
! 1155: ** If there is no shared memory associated with the connection then this
! 1156: ** routine is a harmless no-op.
! 1157: */
! 1158: static int os2ShmUnmap(
! 1159: sqlite3_file *id, /* The underlying database file */
! 1160: int deleteFlag /* Delete shared-memory if true */
! 1161: ){
! 1162: os2File *pFile = (os2File*)id;
! 1163: os2ShmLink *pLink = pFile->pShmLink;
! 1164:
! 1165: if( pLink ) {
! 1166: int nRef = -1;
! 1167: os2ShmLink **ppLink;
! 1168: os2ShmNode *pNode = pLink->pShmNode;
! 1169:
! 1170: sqlite3_mutex_enter(pNode->mutex);
! 1171:
! 1172: for( ppLink = &pNode->pFirst;
! 1173: *ppLink && *ppLink != pLink;
! 1174: ppLink = &(*ppLink)->pNext ) ;
! 1175:
! 1176: assert(*ppLink);
! 1177:
! 1178: if( *ppLink ) {
! 1179: *ppLink = pLink->pNext;
! 1180: nRef = --pNode->nRef;
! 1181: } else {
! 1182: ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n",
! 1183: pNode->shmBaseName))
! 1184: }
! 1185:
! 1186: pFile->pShmLink = NULL;
! 1187: sqlite3_free(pLink);
! 1188:
! 1189: sqlite3_mutex_leave(pNode->mutex);
! 1190:
! 1191: if( nRef == 0 )
! 1192: os2PurgeShmNodes( deleteFlag );
! 1193: }
! 1194:
! 1195: return SQLITE_OK;
! 1196: }
! 1197:
! 1198: /*
! 1199: ** Change the lock state for a shared-memory segment.
! 1200: **
! 1201: ** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
! 1202: ** different here than in posix. In xShmLock(), one can go from unlocked
! 1203: ** to shared and back or from unlocked to exclusive and back. But one may
! 1204: ** not go from shared to exclusive or from exclusive to shared.
! 1205: */
! 1206: static int os2ShmLock(
! 1207: sqlite3_file *id, /* Database file holding the shared memory */
! 1208: int ofst, /* First lock to acquire or release */
! 1209: int n, /* Number of locks to acquire or release */
! 1210: int flags /* What to do with the lock */
! 1211: ){
! 1212: u32 mask; /* Mask of locks to take or release */
! 1213: int rc = SQLITE_OK; /* Result code */
! 1214: os2File *pFile = (os2File*)id;
! 1215: os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */
! 1216: os2ShmLink *pX; /* For looping over all siblings */
! 1217: os2ShmNode *pShmNode = p->pShmNode; /* Our node */
! 1218:
! 1219: assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
! 1220: assert( n>=1 );
! 1221: assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
! 1222: || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
! 1223: || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
! 1224: || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
! 1225: assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
! 1226:
! 1227: mask = (u32)((1U<<(ofst+n)) - (1U<<ofst));
! 1228: assert( n>1 || mask==(1<<ofst) );
! 1229:
! 1230:
! 1231: sqlite3_mutex_enter(pShmNode->mutex);
! 1232:
! 1233: if( flags & SQLITE_SHM_UNLOCK ){
! 1234: u32 allMask = 0; /* Mask of locks held by siblings */
! 1235:
! 1236: /* See if any siblings hold this same lock */
! 1237: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
! 1238: if( pX==p ) continue;
! 1239: assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
! 1240: allMask |= pX->sharedMask;
! 1241: }
! 1242:
! 1243: /* Unlock the system-level locks */
! 1244: if( (mask & allMask)==0 ){
! 1245: rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n);
! 1246: }else{
! 1247: rc = SQLITE_OK;
! 1248: }
! 1249:
! 1250: /* Undo the local locks */
! 1251: if( rc==SQLITE_OK ){
! 1252: p->exclMask &= ~mask;
! 1253: p->sharedMask &= ~mask;
! 1254: }
! 1255: }else if( flags & SQLITE_SHM_SHARED ){
! 1256: u32 allShared = 0; /* Union of locks held by connections other than "p" */
! 1257:
! 1258: /* Find out which shared locks are already held by sibling connections.
! 1259: ** If any sibling already holds an exclusive lock, go ahead and return
! 1260: ** SQLITE_BUSY.
! 1261: */
! 1262: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
! 1263: if( (pX->exclMask & mask)!=0 ){
! 1264: rc = SQLITE_BUSY;
! 1265: break;
! 1266: }
! 1267: allShared |= pX->sharedMask;
! 1268: }
! 1269:
! 1270: /* Get shared locks at the system level, if necessary */
! 1271: if( rc==SQLITE_OK ){
! 1272: if( (allShared & mask)==0 ){
! 1273: rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n);
! 1274: }else{
! 1275: rc = SQLITE_OK;
! 1276: }
! 1277: }
! 1278:
! 1279: /* Get the local shared locks */
! 1280: if( rc==SQLITE_OK ){
! 1281: p->sharedMask |= mask;
! 1282: }
! 1283: }else{
! 1284: /* Make sure no sibling connections hold locks that will block this
! 1285: ** lock. If any do, return SQLITE_BUSY right away.
! 1286: */
! 1287: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
! 1288: if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
! 1289: rc = SQLITE_BUSY;
! 1290: break;
! 1291: }
! 1292: }
! 1293:
! 1294: /* Get the exclusive locks at the system level. Then if successful
! 1295: ** also mark the local connection as being locked.
! 1296: */
! 1297: if( rc==SQLITE_OK ){
! 1298: rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n);
! 1299: if( rc==SQLITE_OK ){
! 1300: assert( (p->sharedMask & mask)==0 );
! 1301: p->exclMask |= mask;
! 1302: }
! 1303: }
! 1304: }
! 1305:
! 1306: sqlite3_mutex_leave(pShmNode->mutex);
! 1307:
! 1308: OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
! 1309: p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
! 1310: rc ? "failed" : "ok"));
! 1311:
! 1312: ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n",
! 1313: ofst, n, flags, rc))
! 1314:
! 1315: return rc;
! 1316: }
! 1317:
! 1318: /*
! 1319: ** Implement a memory barrier or memory fence on shared memory.
! 1320: **
! 1321: ** All loads and stores begun before the barrier must complete before
! 1322: ** any load or store begun after the barrier.
! 1323: */
! 1324: static void os2ShmBarrier(
! 1325: sqlite3_file *id /* Database file holding the shared memory */
! 1326: ){
! 1327: UNUSED_PARAMETER(id);
! 1328: os2ShmEnterMutex();
! 1329: os2ShmLeaveMutex();
! 1330: }
! 1331:
! 1332: #else
! 1333: # define os2ShmMap 0
! 1334: # define os2ShmLock 0
! 1335: # define os2ShmBarrier 0
! 1336: # define os2ShmUnmap 0
! 1337: #endif /* #ifndef SQLITE_OMIT_WAL */
! 1338:
! 1339:
! 1340: /*
! 1341: ** This vector defines all the methods that can operate on an
! 1342: ** sqlite3_file for os2.
! 1343: */
! 1344: static const sqlite3_io_methods os2IoMethod = {
! 1345: 2, /* iVersion */
! 1346: os2Close, /* xClose */
! 1347: os2Read, /* xRead */
! 1348: os2Write, /* xWrite */
! 1349: os2Truncate, /* xTruncate */
! 1350: os2Sync, /* xSync */
! 1351: os2FileSize, /* xFileSize */
! 1352: os2Lock, /* xLock */
! 1353: os2Unlock, /* xUnlock */
! 1354: os2CheckReservedLock, /* xCheckReservedLock */
! 1355: os2FileControl, /* xFileControl */
! 1356: os2SectorSize, /* xSectorSize */
! 1357: os2DeviceCharacteristics, /* xDeviceCharacteristics */
! 1358: os2ShmMap, /* xShmMap */
! 1359: os2ShmLock, /* xShmLock */
! 1360: os2ShmBarrier, /* xShmBarrier */
! 1361: os2ShmUnmap /* xShmUnmap */
! 1362: };
! 1363:
! 1364:
! 1365: /***************************************************************************
! 1366: ** Here ends the I/O methods that form the sqlite3_io_methods object.
! 1367: **
! 1368: ** The next block of code implements the VFS methods.
! 1369: ****************************************************************************/
! 1370:
! 1371: /*
! 1372: ** Create a temporary file name in zBuf. zBuf must be big enough to
! 1373: ** hold at pVfs->mxPathname characters.
! 1374: */
! 1375: static int getTempname(int nBuf, char *zBuf ){
! 1376: static const char zChars[] =
! 1377: "abcdefghijklmnopqrstuvwxyz"
! 1378: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
! 1379: "0123456789";
! 1380: int i, j;
! 1381: PSZ zTempPathCp;
! 1382: char zTempPath[CCHMAXPATH];
! 1383: ULONG ulDriveNum, ulDriveMap;
! 1384:
! 1385: /* It's odd to simulate an io-error here, but really this is just
! 1386: ** using the io-error infrastructure to test that SQLite handles this
! 1387: ** function failing.
! 1388: */
! 1389: SimulateIOError( return SQLITE_IOERR );
! 1390:
! 1391: if( sqlite3_temp_directory ) {
! 1392: sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory);
! 1393: } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR ||
! 1394: DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR ||
! 1395: DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) {
! 1396: char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp );
! 1397: sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF);
! 1398: free( zTempPathUTF );
! 1399: } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) {
! 1400: zTempPath[0] = (char)('A' + ulDriveNum - 1);
! 1401: zTempPath[1] = ':';
! 1402: zTempPath[2] = '\0';
! 1403: } else {
! 1404: zTempPath[0] = '\0';
! 1405: }
! 1406:
! 1407: /* Strip off a trailing slashes or backslashes, otherwise we would get *
! 1408: * multiple (back)slashes which causes DosOpen() to fail. *
! 1409: * Trailing spaces are not allowed, either. */
! 1410: j = sqlite3Strlen30(zTempPath);
! 1411: while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' ||
! 1412: zTempPath[j-1] == ' ' ) ){
! 1413: j--;
! 1414: }
! 1415: zTempPath[j] = '\0';
! 1416:
! 1417: /* We use 20 bytes to randomize the name */
! 1418: sqlite3_snprintf(nBuf-22, zBuf,
! 1419: "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
! 1420: j = sqlite3Strlen30(zBuf);
! 1421: sqlite3_randomness( 20, &zBuf[j] );
! 1422: for( i = 0; i < 20; i++, j++ ){
! 1423: zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
! 1424: }
! 1425: zBuf[j] = 0;
! 1426:
! 1427: OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
! 1428: return SQLITE_OK;
! 1429: }
! 1430:
! 1431:
! 1432: /*
! 1433: ** Turn a relative pathname into a full pathname. Write the full
! 1434: ** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname
! 1435: ** bytes in size.
! 1436: */
! 1437: static int os2FullPathname(
! 1438: sqlite3_vfs *pVfs, /* Pointer to vfs object */
! 1439: const char *zRelative, /* Possibly relative input path */
! 1440: int nFull, /* Size of output buffer in bytes */
! 1441: char *zFull /* Output buffer */
! 1442: ){
! 1443: char *zRelativeCp = convertUtf8PathToCp( zRelative );
! 1444: char zFullCp[CCHMAXPATH] = "\0";
! 1445: char *zFullUTF;
! 1446: APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME,
! 1447: zFullCp, CCHMAXPATH );
! 1448: free( zRelativeCp );
! 1449: zFullUTF = convertCpPathToUtf8( zFullCp );
! 1450: sqlite3_snprintf( nFull, zFull, zFullUTF );
! 1451: free( zFullUTF );
! 1452: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
! 1453: }
! 1454:
! 1455:
! 1456: /*
! 1457: ** Open a file.
! 1458: */
! 1459: static int os2Open(
! 1460: sqlite3_vfs *pVfs, /* Not used */
! 1461: const char *zName, /* Name of the file (UTF-8) */
! 1462: sqlite3_file *id, /* Write the SQLite file handle here */
! 1463: int flags, /* Open mode flags */
! 1464: int *pOutFlags /* Status return flags */
! 1465: ){
! 1466: HFILE h;
! 1467: ULONG ulOpenFlags = 0;
! 1468: ULONG ulOpenMode = 0;
! 1469: ULONG ulAction = 0;
! 1470: ULONG rc;
! 1471: os2File *pFile = (os2File*)id;
! 1472: const char *zUtf8Name = zName;
! 1473: char *zNameCp;
! 1474: char zTmpname[CCHMAXPATH];
! 1475:
! 1476: int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
! 1477: int isCreate = (flags & SQLITE_OPEN_CREATE);
! 1478: int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
! 1479: #ifndef NDEBUG
! 1480: int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
! 1481: int isReadonly = (flags & SQLITE_OPEN_READONLY);
! 1482: int eType = (flags & 0xFFFFFF00);
! 1483: int isOpenJournal = (isCreate && (
! 1484: eType==SQLITE_OPEN_MASTER_JOURNAL
! 1485: || eType==SQLITE_OPEN_MAIN_JOURNAL
! 1486: || eType==SQLITE_OPEN_WAL
! 1487: ));
! 1488: #endif
! 1489:
! 1490: UNUSED_PARAMETER(pVfs);
! 1491: assert( id!=0 );
! 1492:
! 1493: /* Check the following statements are true:
! 1494: **
! 1495: ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
! 1496: ** (b) if CREATE is set, then READWRITE must also be set, and
! 1497: ** (c) if EXCLUSIVE is set, then CREATE must also be set.
! 1498: ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
! 1499: */
! 1500: assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
! 1501: assert(isCreate==0 || isReadWrite);
! 1502: assert(isExclusive==0 || isCreate);
! 1503: assert(isDelete==0 || isCreate);
! 1504:
! 1505: /* The main DB, main journal, WAL file and master journal are never
! 1506: ** automatically deleted. Nor are they ever temporary files. */
! 1507: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
! 1508: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
! 1509: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
! 1510: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
! 1511:
! 1512: /* Assert that the upper layer has set one of the "file-type" flags. */
! 1513: assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
! 1514: || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
! 1515: || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
! 1516: || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
! 1517: );
! 1518:
! 1519: memset( pFile, 0, sizeof(*pFile) );
! 1520: pFile->h = (HFILE)-1;
! 1521:
! 1522: /* If the second argument to this function is NULL, generate a
! 1523: ** temporary file name to use
! 1524: */
! 1525: if( !zUtf8Name ){
! 1526: assert(isDelete && !isOpenJournal);
! 1527: rc = getTempname(CCHMAXPATH, zTmpname);
! 1528: if( rc!=SQLITE_OK ){
! 1529: return rc;
! 1530: }
! 1531: zUtf8Name = zTmpname;
! 1532: }
! 1533:
! 1534: if( isReadWrite ){
! 1535: ulOpenMode |= OPEN_ACCESS_READWRITE;
! 1536: }else{
! 1537: ulOpenMode |= OPEN_ACCESS_READONLY;
! 1538: }
! 1539:
! 1540: /* Open in random access mode for possibly better speed. Allow full
! 1541: ** sharing because file locks will provide exclusive access when needed.
! 1542: ** The handle should not be inherited by child processes and we don't
! 1543: ** want popups from the critical error handler.
! 1544: */
! 1545: ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE |
! 1546: OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR;
! 1547:
! 1548: /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
! 1549: ** created. SQLite doesn't use it to indicate "exclusive access"
! 1550: ** as it is usually understood.
! 1551: */
! 1552: if( isExclusive ){
! 1553: /* Creates a new file, only if it does not already exist. */
! 1554: /* If the file exists, it fails. */
! 1555: ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
! 1556: }else if( isCreate ){
! 1557: /* Open existing file, or create if it doesn't exist */
! 1558: ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
! 1559: }else{
! 1560: /* Opens a file, only if it exists. */
! 1561: ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
! 1562: }
! 1563:
! 1564: zNameCp = convertUtf8PathToCp( zUtf8Name );
! 1565: rc = DosOpen( (PSZ)zNameCp,
! 1566: &h,
! 1567: &ulAction,
! 1568: 0L,
! 1569: FILE_NORMAL,
! 1570: ulOpenFlags,
! 1571: ulOpenMode,
! 1572: (PEAOP2)NULL );
! 1573: free( zNameCp );
! 1574:
! 1575: if( rc != NO_ERROR ){
! 1576: OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
! 1577: rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
! 1578:
! 1579: if( isReadWrite ){
! 1580: return os2Open( pVfs, zName, id,
! 1581: ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
! 1582: pOutFlags );
! 1583: }else{
! 1584: return SQLITE_CANTOPEN;
! 1585: }
! 1586: }
! 1587:
! 1588: if( pOutFlags ){
! 1589: *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
! 1590: }
! 1591:
! 1592: os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname );
! 1593: pFile->zFullPathCp = convertUtf8PathToCp( zTmpname );
! 1594: pFile->pMethod = &os2IoMethod;
! 1595: pFile->flags = flags;
! 1596: pFile->h = h;
! 1597:
! 1598: OpenCounter(+1);
! 1599: OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
! 1600: return SQLITE_OK;
! 1601: }
! 1602:
! 1603: /*
! 1604: ** Delete the named file.
! 1605: */
! 1606: static int os2Delete(
! 1607: sqlite3_vfs *pVfs, /* Not used on os2 */
! 1608: const char *zFilename, /* Name of file to delete */
! 1609: int syncDir /* Not used on os2 */
! 1610: ){
! 1611: APIRET rc;
! 1612: char *zFilenameCp;
! 1613: SimulateIOError( return SQLITE_IOERR_DELETE );
! 1614: zFilenameCp = convertUtf8PathToCp( zFilename );
! 1615: rc = DosDelete( (PSZ)zFilenameCp );
! 1616: free( zFilenameCp );
! 1617: OSTRACE(( "DELETE \"%s\"\n", zFilename ));
! 1618: return (rc == NO_ERROR ||
! 1619: rc == ERROR_FILE_NOT_FOUND ||
! 1620: rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
! 1621: }
! 1622:
! 1623: /*
! 1624: ** Check the existance and status of a file.
! 1625: */
! 1626: static int os2Access(
! 1627: sqlite3_vfs *pVfs, /* Not used on os2 */
! 1628: const char *zFilename, /* Name of file to check */
! 1629: int flags, /* Type of test to make on this file */
! 1630: int *pOut /* Write results here */
! 1631: ){
! 1632: APIRET rc;
! 1633: FILESTATUS3 fsts3ConfigInfo;
! 1634: char *zFilenameCp;
! 1635:
! 1636: UNUSED_PARAMETER(pVfs);
! 1637: SimulateIOError( return SQLITE_IOERR_ACCESS; );
! 1638:
! 1639: zFilenameCp = convertUtf8PathToCp( zFilename );
! 1640: rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
! 1641: &fsts3ConfigInfo, sizeof(FILESTATUS3) );
! 1642: free( zFilenameCp );
! 1643: OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
! 1644: fsts3ConfigInfo.attrFile, flags, rc ));
! 1645:
! 1646: switch( flags ){
! 1647: case SQLITE_ACCESS_EXISTS:
! 1648: /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
! 1649: ** as if it does not exist.
! 1650: */
! 1651: if( fsts3ConfigInfo.cbFile == 0 )
! 1652: rc = ERROR_FILE_NOT_FOUND;
! 1653: break;
! 1654: case SQLITE_ACCESS_READ:
! 1655: break;
! 1656: case SQLITE_ACCESS_READWRITE:
! 1657: if( fsts3ConfigInfo.attrFile & FILE_READONLY )
! 1658: rc = ERROR_ACCESS_DENIED;
! 1659: break;
! 1660: default:
! 1661: rc = ERROR_FILE_NOT_FOUND;
! 1662: assert( !"Invalid flags argument" );
! 1663: }
! 1664:
! 1665: *pOut = (rc == NO_ERROR);
! 1666: OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut ));
! 1667:
! 1668: return SQLITE_OK;
! 1669: }
! 1670:
! 1671:
! 1672: #ifndef SQLITE_OMIT_LOAD_EXTENSION
! 1673: /*
! 1674: ** Interfaces for opening a shared library, finding entry points
! 1675: ** within the shared library, and closing the shared library.
! 1676: */
! 1677: /*
! 1678: ** Interfaces for opening a shared library, finding entry points
! 1679: ** within the shared library, and closing the shared library.
! 1680: */
! 1681: static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
! 1682: HMODULE hmod;
! 1683: APIRET rc;
! 1684: char *zFilenameCp = convertUtf8PathToCp(zFilename);
! 1685: rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod);
! 1686: free(zFilenameCp);
! 1687: return rc != NO_ERROR ? 0 : (void*)hmod;
! 1688: }
! 1689: /*
! 1690: ** A no-op since the error code is returned on the DosLoadModule call.
! 1691: ** os2Dlopen returns zero if DosLoadModule is not successful.
! 1692: */
! 1693: static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
! 1694: /* no-op */
! 1695: }
! 1696: static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
! 1697: PFN pfn;
! 1698: APIRET rc;
! 1699: rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn);
! 1700: if( rc != NO_ERROR ){
! 1701: /* if the symbol itself was not found, search again for the same
! 1702: * symbol with an extra underscore, that might be needed depending
! 1703: * on the calling convention */
! 1704: char _zSymbol[256] = "_";
! 1705: strncat(_zSymbol, zSymbol, 254);
! 1706: rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn);
! 1707: }
! 1708: return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
! 1709: }
! 1710: static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
! 1711: DosFreeModule((HMODULE)pHandle);
! 1712: }
! 1713: #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
! 1714: #define os2DlOpen 0
! 1715: #define os2DlError 0
! 1716: #define os2DlSym 0
! 1717: #define os2DlClose 0
! 1718: #endif
! 1719:
! 1720:
! 1721: /*
! 1722: ** Write up to nBuf bytes of randomness into zBuf.
! 1723: */
! 1724: static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
! 1725: int n = 0;
! 1726: #if defined(SQLITE_TEST)
! 1727: n = nBuf;
! 1728: memset(zBuf, 0, nBuf);
! 1729: #else
! 1730: int i;
! 1731: PPIB ppib;
! 1732: PTIB ptib;
! 1733: DATETIME dt;
! 1734: static unsigned c = 0;
! 1735: /* Ordered by variation probability */
! 1736: static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW,
! 1737: QSV_MAXPRMEM, QSV_MAXSHMEM,
! 1738: QSV_TOTAVAILMEM, QSV_TOTRESMEM };
! 1739:
! 1740: /* 8 bytes; timezone and weekday don't increase the randomness much */
! 1741: if( (int)sizeof(dt)-3 <= nBuf - n ){
! 1742: c += 0x0100;
! 1743: DosGetDateTime(&dt);
! 1744: dt.year = (USHORT)((dt.year - 1900) | c);
! 1745: memcpy(&zBuf[n], &dt, sizeof(dt)-3);
! 1746: n += sizeof(dt)-3;
! 1747: }
! 1748:
! 1749: /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */
! 1750: if( (int)sizeof(ULONG) <= nBuf - n ){
! 1751: DosGetInfoBlocks(&ptib, &ppib);
! 1752: *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid,
! 1753: ptib->tib_ptib2->tib2_ultid);
! 1754: n += sizeof(ULONG);
! 1755: }
! 1756:
! 1757: /* Up to 6 * 4 bytes; variables depend on the system state */
! 1758: for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){
! 1759: DosQuerySysInfo(svIdx[i], svIdx[i],
! 1760: (PULONG)&zBuf[n], sizeof(ULONG));
! 1761: n += sizeof(ULONG);
! 1762: }
! 1763: #endif
! 1764:
! 1765: return n;
! 1766: }
! 1767:
! 1768: /*
! 1769: ** Sleep for a little while. Return the amount of time slept.
! 1770: ** The argument is the number of microseconds we want to sleep.
! 1771: ** The return value is the number of microseconds of sleep actually
! 1772: ** requested from the underlying operating system, a number which
! 1773: ** might be greater than or equal to the argument, but not less
! 1774: ** than the argument.
! 1775: */
! 1776: static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){
! 1777: DosSleep( (microsec/1000) );
! 1778: return microsec;
! 1779: }
! 1780:
! 1781: /*
! 1782: ** The following variable, if set to a non-zero value, becomes the result
! 1783: ** returned from sqlite3OsCurrentTime(). This is used for testing.
! 1784: */
! 1785: #ifdef SQLITE_TEST
! 1786: int sqlite3_current_time = 0;
! 1787: #endif
! 1788:
! 1789: /*
! 1790: ** Find the current time (in Universal Coordinated Time). Write into *piNow
! 1791: ** the current time and date as a Julian Day number times 86_400_000. In
! 1792: ** other words, write into *piNow the number of milliseconds since the Julian
! 1793: ** epoch of noon in Greenwich on November 24, 4714 B.C according to the
! 1794: ** proleptic Gregorian calendar.
! 1795: **
! 1796: ** On success, return 0. Return 1 if the time and date cannot be found.
! 1797: */
! 1798: static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
! 1799: #ifdef SQLITE_TEST
! 1800: static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
! 1801: #endif
! 1802: int year, month, datepart, timepart;
! 1803:
! 1804: DATETIME dt;
! 1805: DosGetDateTime( &dt );
! 1806:
! 1807: year = dt.year;
! 1808: month = dt.month;
! 1809:
! 1810: /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
! 1811: ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c
! 1812: ** Calculate the Julian days
! 1813: */
! 1814: datepart = (int)dt.day - 32076 +
! 1815: 1461*(year + 4800 + (month - 14)/12)/4 +
! 1816: 367*(month - 2 - (month - 14)/12*12)/12 -
! 1817: 3*((year + 4900 + (month - 14)/12)/100)/4;
! 1818:
! 1819: /* Time in milliseconds, hours to noon added */
! 1820: timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 +
! 1821: ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000;
! 1822:
! 1823: *piNow = (sqlite3_int64)datepart*86400*1000 + timepart;
! 1824:
! 1825: #ifdef SQLITE_TEST
! 1826: if( sqlite3_current_time ){
! 1827: *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
! 1828: }
! 1829: #endif
! 1830:
! 1831: UNUSED_PARAMETER(pVfs);
! 1832: return 0;
! 1833: }
! 1834:
! 1835: /*
! 1836: ** Find the current time (in Universal Coordinated Time). Write the
! 1837: ** current time and date as a Julian Day number into *prNow and
! 1838: ** return 0. Return 1 if the time and date cannot be found.
! 1839: */
! 1840: static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
! 1841: int rc;
! 1842: sqlite3_int64 i;
! 1843: rc = os2CurrentTimeInt64(pVfs, &i);
! 1844: if( !rc ){
! 1845: *prNow = i/86400000.0;
! 1846: }
! 1847: return rc;
! 1848: }
! 1849:
! 1850: /*
! 1851: ** The idea is that this function works like a combination of
! 1852: ** GetLastError() and FormatMessage() on windows (or errno and
! 1853: ** strerror_r() on unix). After an error is returned by an OS
! 1854: ** function, SQLite calls this function with zBuf pointing to
! 1855: ** a buffer of nBuf bytes. The OS layer should populate the
! 1856: ** buffer with a nul-terminated UTF-8 encoded error message
! 1857: ** describing the last IO error to have occurred within the calling
! 1858: ** thread.
! 1859: **
! 1860: ** If the error message is too large for the supplied buffer,
! 1861: ** it should be truncated. The return value of xGetLastError
! 1862: ** is zero if the error message fits in the buffer, or non-zero
! 1863: ** otherwise (if the message was truncated). If non-zero is returned,
! 1864: ** then it is not necessary to include the nul-terminator character
! 1865: ** in the output buffer.
! 1866: **
! 1867: ** Not supplying an error message will have no adverse effect
! 1868: ** on SQLite. It is fine to have an implementation that never
! 1869: ** returns an error message:
! 1870: **
! 1871: ** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
! 1872: ** assert(zBuf[0]=='\0');
! 1873: ** return 0;
! 1874: ** }
! 1875: **
! 1876: ** However if an error message is supplied, it will be incorporated
! 1877: ** by sqlite into the error message available to the user using
! 1878: ** sqlite3_errmsg(), possibly making IO errors easier to debug.
! 1879: */
! 1880: static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
! 1881: assert(zBuf[0]=='\0');
! 1882: return 0;
! 1883: }
! 1884:
! 1885: /*
! 1886: ** Initialize and deinitialize the operating system interface.
! 1887: */
! 1888: int sqlite3_os_init(void){
! 1889: static sqlite3_vfs os2Vfs = {
! 1890: 3, /* iVersion */
! 1891: sizeof(os2File), /* szOsFile */
! 1892: CCHMAXPATH, /* mxPathname */
! 1893: 0, /* pNext */
! 1894: "os2", /* zName */
! 1895: 0, /* pAppData */
! 1896:
! 1897: os2Open, /* xOpen */
! 1898: os2Delete, /* xDelete */
! 1899: os2Access, /* xAccess */
! 1900: os2FullPathname, /* xFullPathname */
! 1901: os2DlOpen, /* xDlOpen */
! 1902: os2DlError, /* xDlError */
! 1903: os2DlSym, /* xDlSym */
! 1904: os2DlClose, /* xDlClose */
! 1905: os2Randomness, /* xRandomness */
! 1906: os2Sleep, /* xSleep */
! 1907: os2CurrentTime, /* xCurrentTime */
! 1908: os2GetLastError, /* xGetLastError */
! 1909: os2CurrentTimeInt64, /* xCurrentTimeInt64 */
! 1910: 0, /* xSetSystemCall */
! 1911: 0, /* xGetSystemCall */
! 1912: 0 /* xNextSystemCall */
! 1913: };
! 1914: sqlite3_vfs_register(&os2Vfs, 1);
! 1915: initUconvObjects();
! 1916: /* sqlite3OSTrace = 1; */
! 1917: return SQLITE_OK;
! 1918: }
! 1919: int sqlite3_os_end(void){
! 1920: freeUconvObjects();
! 1921: return SQLITE_OK;
! 1922: }
! 1923:
! 1924: #endif /* SQLITE_OS_OS2 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>