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>