Index: third_party/sqlite/src/src/os_os2.c |
diff --git a/third_party/sqlite/src/src/os_os2.c b/third_party/sqlite/src/src/os_os2.c |
deleted file mode 100644 |
index 487ac3c3c8130b24d93cfc8c131c5ea8772514aa..0000000000000000000000000000000000000000 |
--- a/third_party/sqlite/src/src/os_os2.c |
+++ /dev/null |
@@ -1,1924 +0,0 @@ |
-/* |
-** 2006 Feb 14 |
-** |
-** The author disclaims copyright to this source code. In place of |
-** a legal notice, here is a blessing: |
-** |
-** May you do good and not evil. |
-** May you find forgiveness for yourself and forgive others. |
-** May you share freely, never taking more than you give. |
-** |
-****************************************************************************** |
-** |
-** This file contains code that is specific to OS/2. |
-*/ |
- |
-#include "sqliteInt.h" |
- |
-#if SQLITE_OS_OS2 |
- |
-/* |
-** A Note About Memory Allocation: |
-** |
-** This driver uses malloc()/free() directly rather than going through |
-** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers |
-** are designed for use on embedded systems where memory is scarce and |
-** malloc failures happen frequently. OS/2 does not typically run on |
-** embedded systems, and when it does the developers normally have bigger |
-** problems to worry about than running out of memory. So there is not |
-** a compelling need to use the wrappers. |
-** |
-** But there is a good reason to not use the wrappers. If we use the |
-** wrappers then we will get simulated malloc() failures within this |
-** driver. And that causes all kinds of problems for our tests. We |
-** could enhance SQLite to deal with simulated malloc failures within |
-** the OS driver, but the code to deal with those failure would not |
-** be exercised on Linux (which does not need to malloc() in the driver) |
-** and so we would have difficulty writing coverage tests for that |
-** code. Better to leave the code out, we think. |
-** |
-** The point of this discussion is as follows: When creating a new |
-** OS layer for an embedded system, if you use this file as an example, |
-** avoid the use of malloc()/free(). Those routines work ok on OS/2 |
-** desktops but not so well in embedded systems. |
-*/ |
- |
-/* |
-** Macros used to determine whether or not to use threads. |
-*/ |
-#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE |
-# define SQLITE_OS2_THREADS 1 |
-#endif |
- |
-/* |
-** Include code that is common to all os_*.c files |
-*/ |
-#include "os_common.h" |
- |
-/* Forward references */ |
-typedef struct os2File os2File; /* The file structure */ |
-typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */ |
-typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */ |
- |
-/* |
-** The os2File structure is subclass of sqlite3_file specific for the OS/2 |
-** protability layer. |
-*/ |
-struct os2File { |
- const sqlite3_io_methods *pMethod; /* Always the first entry */ |
- HFILE h; /* Handle for accessing the file */ |
- int flags; /* Flags provided to os2Open() */ |
- int locktype; /* Type of lock currently held on this file */ |
- int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ |
- char *zFullPathCp; /* Full path name of this file */ |
- os2ShmLink *pShmLink; /* Instance of shared memory on this file */ |
-}; |
- |
-#define LOCK_TIMEOUT 10L /* the default locking timeout */ |
- |
-/* |
-** Missing from some versions of the OS/2 toolkit - |
-** used to allocate from high memory if possible |
-*/ |
-#ifndef OBJ_ANY |
-# define OBJ_ANY 0x00000400 |
-#endif |
- |
-/***************************************************************************** |
-** The next group of routines implement the I/O methods specified |
-** by the sqlite3_io_methods object. |
-******************************************************************************/ |
- |
-/* |
-** Close a file. |
-*/ |
-static int os2Close( sqlite3_file *id ){ |
- APIRET rc; |
- os2File *pFile = (os2File*)id; |
- |
- assert( id!=0 ); |
- OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp )); |
- |
- rc = DosClose( pFile->h ); |
- |
- if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE ) |
- DosForceDelete( (PSZ)pFile->zFullPathCp ); |
- |
- free( pFile->zFullPathCp ); |
- pFile->zFullPathCp = NULL; |
- pFile->locktype = NO_LOCK; |
- pFile->h = (HFILE)-1; |
- pFile->flags = 0; |
- |
- OpenCounter( -1 ); |
- return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
-} |
- |
-/* |
-** Read data from a file into a buffer. Return SQLITE_OK if all |
-** bytes were read successfully and SQLITE_IOERR if anything goes |
-** wrong. |
-*/ |
-static int os2Read( |
- sqlite3_file *id, /* File to read from */ |
- void *pBuf, /* Write content into this buffer */ |
- int amt, /* Number of bytes to read */ |
- sqlite3_int64 offset /* Begin reading at this offset */ |
-){ |
- ULONG fileLocation = 0L; |
- ULONG got; |
- os2File *pFile = (os2File*)id; |
- assert( id!=0 ); |
- SimulateIOError( return SQLITE_IOERR_READ ); |
- OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype )); |
- if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ |
- return SQLITE_IOERR; |
- } |
- if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){ |
- return SQLITE_IOERR_READ; |
- } |
- if( got == (ULONG)amt ) |
- return SQLITE_OK; |
- else { |
- /* Unread portions of the input buffer must be zero-filled */ |
- memset(&((char*)pBuf)[got], 0, amt-got); |
- return SQLITE_IOERR_SHORT_READ; |
- } |
-} |
- |
-/* |
-** Write data from a buffer into a file. Return SQLITE_OK on success |
-** or some other error code on failure. |
-*/ |
-static int os2Write( |
- sqlite3_file *id, /* File to write into */ |
- const void *pBuf, /* The bytes to be written */ |
- int amt, /* Number of bytes to write */ |
- sqlite3_int64 offset /* Offset into the file to begin writing at */ |
-){ |
- ULONG fileLocation = 0L; |
- APIRET rc = NO_ERROR; |
- ULONG wrote; |
- os2File *pFile = (os2File*)id; |
- assert( id!=0 ); |
- SimulateIOError( return SQLITE_IOERR_WRITE ); |
- SimulateDiskfullError( return SQLITE_FULL ); |
- OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype )); |
- if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ |
- return SQLITE_IOERR; |
- } |
- assert( amt>0 ); |
- while( amt > 0 && |
- ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR && |
- wrote > 0 |
- ){ |
- amt -= wrote; |
- pBuf = &((char*)pBuf)[wrote]; |
- } |
- |
- return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; |
-} |
- |
-/* |
-** Truncate an open file to a specified size |
-*/ |
-static int os2Truncate( sqlite3_file *id, i64 nByte ){ |
- APIRET rc; |
- os2File *pFile = (os2File*)id; |
- assert( id!=0 ); |
- OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte )); |
- SimulateIOError( return SQLITE_IOERR_TRUNCATE ); |
- |
- /* If the user has configured a chunk-size for this file, truncate the |
- ** file so that it consists of an integer number of chunks (i.e. the |
- ** actual file size after the operation may be larger than the requested |
- ** size). |
- */ |
- if( pFile->szChunk ){ |
- nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
- } |
- |
- rc = DosSetFileSize( pFile->h, nByte ); |
- return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; |
-} |
- |
-#ifdef SQLITE_TEST |
-/* |
-** Count the number of fullsyncs and normal syncs. This is used to test |
-** that syncs and fullsyncs are occuring at the right times. |
-*/ |
-int sqlite3_sync_count = 0; |
-int sqlite3_fullsync_count = 0; |
-#endif |
- |
-/* |
-** Make sure all writes to a particular file are committed to disk. |
-*/ |
-static int os2Sync( sqlite3_file *id, int flags ){ |
- os2File *pFile = (os2File*)id; |
- OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype )); |
-#ifdef SQLITE_TEST |
- if( flags & SQLITE_SYNC_FULL){ |
- sqlite3_fullsync_count++; |
- } |
- sqlite3_sync_count++; |
-#endif |
- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a |
- ** no-op |
- */ |
-#ifdef SQLITE_NO_SYNC |
- UNUSED_PARAMETER(pFile); |
- return SQLITE_OK; |
-#else |
- return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
-#endif |
-} |
- |
-/* |
-** Determine the current size of a file in bytes |
-*/ |
-static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){ |
- APIRET rc = NO_ERROR; |
- FILESTATUS3 fsts3FileInfo; |
- memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); |
- assert( id!=0 ); |
- SimulateIOError( return SQLITE_IOERR_FSTAT ); |
- rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); |
- if( rc == NO_ERROR ){ |
- *pSize = fsts3FileInfo.cbFile; |
- return SQLITE_OK; |
- }else{ |
- return SQLITE_IOERR_FSTAT; |
- } |
-} |
- |
-/* |
-** Acquire a reader lock. |
-*/ |
-static int getReadLock( os2File *pFile ){ |
- FILELOCK LockArea, |
- UnlockArea; |
- APIRET res; |
- memset(&LockArea, 0, sizeof(LockArea)); |
- memset(&UnlockArea, 0, sizeof(UnlockArea)); |
- LockArea.lOffset = SHARED_FIRST; |
- LockArea.lRange = SHARED_SIZE; |
- UnlockArea.lOffset = 0L; |
- UnlockArea.lRange = 0L; |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); |
- OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res )); |
- return res; |
-} |
- |
-/* |
-** Undo a readlock |
-*/ |
-static int unlockReadLock( os2File *id ){ |
- FILELOCK LockArea, |
- UnlockArea; |
- APIRET res; |
- memset(&LockArea, 0, sizeof(LockArea)); |
- memset(&UnlockArea, 0, sizeof(UnlockArea)); |
- LockArea.lOffset = 0L; |
- LockArea.lRange = 0L; |
- UnlockArea.lOffset = SHARED_FIRST; |
- UnlockArea.lRange = SHARED_SIZE; |
- res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); |
- OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res )); |
- return res; |
-} |
- |
-/* |
-** Lock the file with the lock specified by parameter locktype - one |
-** of the following: |
-** |
-** (1) SHARED_LOCK |
-** (2) RESERVED_LOCK |
-** (3) PENDING_LOCK |
-** (4) EXCLUSIVE_LOCK |
-** |
-** Sometimes when requesting one lock state, additional lock states |
-** are inserted in between. The locking might fail on one of the later |
-** transitions leaving the lock state different from what it started but |
-** still short of its goal. The following chart shows the allowed |
-** transitions and the inserted intermediate states: |
-** |
-** UNLOCKED -> SHARED |
-** SHARED -> RESERVED |
-** SHARED -> (PENDING) -> EXCLUSIVE |
-** RESERVED -> (PENDING) -> EXCLUSIVE |
-** PENDING -> EXCLUSIVE |
-** |
-** This routine will only increase a lock. The os2Unlock() routine |
-** erases all locks at once and returns us immediately to locking level 0. |
-** It is not possible to lower the locking level one step at a time. You |
-** must go straight to locking level 0. |
-*/ |
-static int os2Lock( sqlite3_file *id, int locktype ){ |
- int rc = SQLITE_OK; /* Return code from subroutines */ |
- APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ |
- int newLocktype; /* Set pFile->locktype to this value before exiting */ |
- int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ |
- FILELOCK LockArea, |
- UnlockArea; |
- os2File *pFile = (os2File*)id; |
- memset(&LockArea, 0, sizeof(LockArea)); |
- memset(&UnlockArea, 0, sizeof(UnlockArea)); |
- assert( pFile!=0 ); |
- OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype )); |
- |
- /* If there is already a lock of this type or more restrictive on the |
- ** os2File, do nothing. Don't use the end_lock: exit path, as |
- ** sqlite3_mutex_enter() hasn't been called yet. |
- */ |
- if( pFile->locktype>=locktype ){ |
- OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype )); |
- return SQLITE_OK; |
- } |
- |
- /* Make sure the locking sequence is correct |
- */ |
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); |
- assert( locktype!=PENDING_LOCK ); |
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); |
- |
- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or |
- ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of |
- ** the PENDING_LOCK byte is temporary. |
- */ |
- newLocktype = pFile->locktype; |
- if( pFile->locktype==NO_LOCK |
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) |
- ){ |
- LockArea.lOffset = PENDING_BYTE; |
- LockArea.lRange = 1L; |
- UnlockArea.lOffset = 0L; |
- UnlockArea.lRange = 0L; |
- |
- /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */ |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L ); |
- if( res == NO_ERROR ){ |
- gotPendingLock = 1; |
- OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res )); |
- } |
- } |
- |
- /* Acquire a shared lock |
- */ |
- if( locktype==SHARED_LOCK && res == NO_ERROR ){ |
- assert( pFile->locktype==NO_LOCK ); |
- res = getReadLock(pFile); |
- if( res == NO_ERROR ){ |
- newLocktype = SHARED_LOCK; |
- } |
- OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res )); |
- } |
- |
- /* Acquire a RESERVED lock |
- */ |
- if( locktype==RESERVED_LOCK && res == NO_ERROR ){ |
- assert( pFile->locktype==SHARED_LOCK ); |
- LockArea.lOffset = RESERVED_BYTE; |
- LockArea.lRange = 1L; |
- UnlockArea.lOffset = 0L; |
- UnlockArea.lRange = 0L; |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- if( res == NO_ERROR ){ |
- newLocktype = RESERVED_LOCK; |
- } |
- OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res )); |
- } |
- |
- /* Acquire a PENDING lock |
- */ |
- if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ |
- newLocktype = PENDING_LOCK; |
- gotPendingLock = 0; |
- OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n", |
- pFile->h )); |
- } |
- |
- /* Acquire an EXCLUSIVE lock |
- */ |
- if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ |
- assert( pFile->locktype>=SHARED_LOCK ); |
- res = unlockReadLock(pFile); |
- OSTRACE(( "unreadlock = %d\n", res )); |
- LockArea.lOffset = SHARED_FIRST; |
- LockArea.lRange = SHARED_SIZE; |
- UnlockArea.lOffset = 0L; |
- UnlockArea.lRange = 0L; |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- if( res == NO_ERROR ){ |
- newLocktype = EXCLUSIVE_LOCK; |
- }else{ |
- OSTRACE(( "OS/2 error-code = %d\n", res )); |
- getReadLock(pFile); |
- } |
- OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res )); |
- } |
- |
- /* If we are holding a PENDING lock that ought to be released, then |
- ** release it now. |
- */ |
- if( gotPendingLock && locktype==SHARED_LOCK ){ |
- int r; |
- LockArea.lOffset = 0L; |
- LockArea.lRange = 0L; |
- UnlockArea.lOffset = PENDING_BYTE; |
- UnlockArea.lRange = 1L; |
- r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r )); |
- } |
- |
- /* Update the state of the lock has held in the file descriptor then |
- ** return the appropriate result code. |
- */ |
- if( res == NO_ERROR ){ |
- rc = SQLITE_OK; |
- }else{ |
- OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, |
- locktype, newLocktype )); |
- rc = SQLITE_BUSY; |
- } |
- pFile->locktype = newLocktype; |
- OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype )); |
- return rc; |
-} |
- |
-/* |
-** This routine checks if there is a RESERVED lock held on the specified |
-** file by this or any other process. If such a lock is held, return |
-** non-zero, otherwise zero. |
-*/ |
-static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){ |
- int r = 0; |
- os2File *pFile = (os2File*)id; |
- assert( pFile!=0 ); |
- if( pFile->locktype>=RESERVED_LOCK ){ |
- r = 1; |
- OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r )); |
- }else{ |
- FILELOCK LockArea, |
- UnlockArea; |
- APIRET rc = NO_ERROR; |
- memset(&LockArea, 0, sizeof(LockArea)); |
- memset(&UnlockArea, 0, sizeof(UnlockArea)); |
- LockArea.lOffset = RESERVED_BYTE; |
- LockArea.lRange = 1L; |
- UnlockArea.lOffset = 0L; |
- UnlockArea.lRange = 0L; |
- rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc )); |
- if( rc == NO_ERROR ){ |
- APIRET rcu = NO_ERROR; /* return code for unlocking */ |
- LockArea.lOffset = 0L; |
- LockArea.lRange = 0L; |
- UnlockArea.lOffset = RESERVED_BYTE; |
- UnlockArea.lRange = 1L; |
- rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu )); |
- } |
- r = !(rc == NO_ERROR); |
- OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r )); |
- } |
- *pOut = r; |
- return SQLITE_OK; |
-} |
- |
-/* |
-** Lower the locking level on file descriptor id to locktype. locktype |
-** must be either NO_LOCK or SHARED_LOCK. |
-** |
-** If the locking level of the file descriptor is already at or below |
-** the requested locking level, this routine is a no-op. |
-** |
-** It is not possible for this routine to fail if the second argument |
-** is NO_LOCK. If the second argument is SHARED_LOCK then this routine |
-** might return SQLITE_IOERR; |
-*/ |
-static int os2Unlock( sqlite3_file *id, int locktype ){ |
- int type; |
- os2File *pFile = (os2File*)id; |
- APIRET rc = SQLITE_OK; |
- APIRET res = NO_ERROR; |
- FILELOCK LockArea, |
- UnlockArea; |
- memset(&LockArea, 0, sizeof(LockArea)); |
- memset(&UnlockArea, 0, sizeof(UnlockArea)); |
- assert( pFile!=0 ); |
- assert( locktype<=SHARED_LOCK ); |
- OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype )); |
- type = pFile->locktype; |
- if( type>=EXCLUSIVE_LOCK ){ |
- LockArea.lOffset = 0L; |
- LockArea.lRange = 0L; |
- UnlockArea.lOffset = SHARED_FIRST; |
- UnlockArea.lRange = SHARED_SIZE; |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res )); |
- if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ |
- /* This should never happen. We should always be able to |
- ** reacquire the read lock */ |
- OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype )); |
- rc = SQLITE_IOERR_UNLOCK; |
- } |
- } |
- if( type>=RESERVED_LOCK ){ |
- LockArea.lOffset = 0L; |
- LockArea.lRange = 0L; |
- UnlockArea.lOffset = RESERVED_BYTE; |
- UnlockArea.lRange = 1L; |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res )); |
- } |
- if( locktype==NO_LOCK && type>=SHARED_LOCK ){ |
- res = unlockReadLock(pFile); |
- OSTRACE(( "UNLOCK %d is %d want %d res=%d\n", |
- pFile->h, type, locktype, res )); |
- } |
- if( type>=PENDING_LOCK ){ |
- LockArea.lOffset = 0L; |
- LockArea.lRange = 0L; |
- UnlockArea.lOffset = PENDING_BYTE; |
- UnlockArea.lRange = 1L; |
- res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
- OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res )); |
- } |
- pFile->locktype = locktype; |
- OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype )); |
- return rc; |
-} |
- |
-/* |
-** Control and query of the open file handle. |
-*/ |
-static int os2FileControl(sqlite3_file *id, int op, void *pArg){ |
- switch( op ){ |
- case SQLITE_FCNTL_LOCKSTATE: { |
- *(int*)pArg = ((os2File*)id)->locktype; |
- OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n", |
- ((os2File*)id)->h, ((os2File*)id)->locktype )); |
- return SQLITE_OK; |
- } |
- case SQLITE_FCNTL_CHUNK_SIZE: { |
- ((os2File*)id)->szChunk = *(int*)pArg; |
- return SQLITE_OK; |
- } |
- case SQLITE_FCNTL_SIZE_HINT: { |
- sqlite3_int64 sz = *(sqlite3_int64*)pArg; |
- SimulateIOErrorBenign(1); |
- os2Truncate(id, sz); |
- SimulateIOErrorBenign(0); |
- return SQLITE_OK; |
- } |
- case SQLITE_FCNTL_SYNC_OMITTED: { |
- return SQLITE_OK; |
- } |
- } |
- return SQLITE_NOTFOUND; |
-} |
- |
-/* |
-** Return the sector size in bytes of the underlying block device for |
-** the specified file. This is almost always 512 bytes, but may be |
-** larger for some devices. |
-** |
-** SQLite code assumes this function cannot fail. It also assumes that |
-** if two files are created in the same file-system directory (i.e. |
-** a database and its journal file) that the sector size will be the |
-** same for both. |
-*/ |
-static int os2SectorSize(sqlite3_file *id){ |
- UNUSED_PARAMETER(id); |
- return SQLITE_DEFAULT_SECTOR_SIZE; |
-} |
- |
-/* |
-** Return a vector of device characteristics. |
-*/ |
-static int os2DeviceCharacteristics(sqlite3_file *id){ |
- UNUSED_PARAMETER(id); |
- return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; |
-} |
- |
- |
-/* |
-** Character set conversion objects used by conversion routines. |
-*/ |
-static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */ |
-static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */ |
- |
-/* |
-** Helper function to initialize the conversion objects from and to UTF-8. |
-*/ |
-static void initUconvObjects( void ){ |
- if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS ) |
- ucUtf8 = NULL; |
- if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS ) |
- uclCp = NULL; |
-} |
- |
-/* |
-** Helper function to free the conversion objects from and to UTF-8. |
-*/ |
-static void freeUconvObjects( void ){ |
- if ( ucUtf8 ) |
- UniFreeUconvObject( ucUtf8 ); |
- if ( uclCp ) |
- UniFreeUconvObject( uclCp ); |
- ucUtf8 = NULL; |
- uclCp = NULL; |
-} |
- |
-/* |
-** Helper function to convert UTF-8 filenames to local OS/2 codepage. |
-** The two-step process: first convert the incoming UTF-8 string |
-** into UCS-2 and then from UCS-2 to the current codepage. |
-** The returned char pointer has to be freed. |
-*/ |
-static char *convertUtf8PathToCp( const char *in ){ |
- UniChar tempPath[CCHMAXPATH]; |
- char *out = (char *)calloc( CCHMAXPATH, 1 ); |
- |
- if( !out ) |
- return NULL; |
- |
- if( !ucUtf8 || !uclCp ) |
- initUconvObjects(); |
- |
- /* determine string for the conversion of UTF-8 which is CP1208 */ |
- if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS ) |
- return out; /* if conversion fails, return the empty string */ |
- |
- /* conversion for current codepage which can be used for paths */ |
- UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH ); |
- |
- return out; |
-} |
- |
-/* |
-** Helper function to convert filenames from local codepage to UTF-8. |
-** The two-step process: first convert the incoming codepage-specific |
-** string into UCS-2 and then from UCS-2 to the codepage of UTF-8. |
-** The returned char pointer has to be freed. |
-** |
-** This function is non-static to be able to use this in shell.c and |
-** similar applications that take command line arguments. |
-*/ |
-char *convertCpPathToUtf8( const char *in ){ |
- UniChar tempPath[CCHMAXPATH]; |
- char *out = (char *)calloc( CCHMAXPATH, 1 ); |
- |
- if( !out ) |
- return NULL; |
- |
- if( !ucUtf8 || !uclCp ) |
- initUconvObjects(); |
- |
- /* conversion for current codepage which can be used for paths */ |
- if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS ) |
- return out; /* if conversion fails, return the empty string */ |
- |
- /* determine string for the conversion of UTF-8 which is CP1208 */ |
- UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); |
- |
- return out; |
-} |
- |
- |
-#ifndef SQLITE_OMIT_WAL |
- |
-/* |
-** Use main database file for interprocess locking. If un-defined |
-** a separate file is created for this purpose. The file will be |
-** used only to set file locks. There will be no data written to it. |
-*/ |
-#define SQLITE_OS2_NO_WAL_LOCK_FILE |
- |
-#if 0 |
-static void _ERR_TRACE( const char *fmt, ... ) { |
- va_list ap; |
- va_start(ap, fmt); |
- vfprintf(stderr, fmt, ap); |
- fflush(stderr); |
-} |
-#define ERR_TRACE(rc, msg) \ |
- if( (rc) != SQLITE_OK ) _ERR_TRACE msg; |
-#else |
-#define ERR_TRACE(rc, msg) |
-#endif |
- |
-/* |
-** Helper functions to obtain and relinquish the global mutex. The |
-** global mutex is used to protect os2ShmNodeList. |
-** |
-** Function os2ShmMutexHeld() is used to assert() that the global mutex |
-** is held when required. This function is only used as part of assert() |
-** statements. e.g. |
-** |
-** os2ShmEnterMutex() |
-** assert( os2ShmMutexHeld() ); |
-** os2ShmLeaveMutex() |
-*/ |
-static void os2ShmEnterMutex(void){ |
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
-} |
-static void os2ShmLeaveMutex(void){ |
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
-} |
-#ifdef SQLITE_DEBUG |
-static int os2ShmMutexHeld(void) { |
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
-} |
-int GetCurrentProcessId(void) { |
- PPIB pib; |
- DosGetInfoBlocks(NULL, &pib); |
- return (int)pib->pib_ulpid; |
-} |
-#endif |
- |
-/* |
-** Object used to represent a the shared memory area for a single log file. |
-** When multiple threads all reference the same log-summary, each thread has |
-** its own os2File object, but they all point to a single instance of this |
-** object. In other words, each log-summary is opened only once per process. |
-** |
-** os2ShmMutexHeld() must be true when creating or destroying |
-** this object or while reading or writing the following fields: |
-** |
-** nRef |
-** pNext |
-** |
-** The following fields are read-only after the object is created: |
-** |
-** szRegion |
-** hLockFile |
-** shmBaseName |
-** |
-** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and |
-** os2ShmMutexHeld() is true when reading or writing any other field |
-** in this structure. |
-** |
-*/ |
-struct os2ShmNode { |
- sqlite3_mutex *mutex; /* Mutex to access this object */ |
- os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */ |
- |
- int szRegion; /* Size of shared-memory regions */ |
- |
- int nRegion; /* Size of array apRegion */ |
- void **apRegion; /* Array of pointers to shared-memory regions */ |
- |
- int nRef; /* Number of os2ShmLink objects pointing to this */ |
- os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */ |
- |
- HFILE hLockFile; /* File used for inter-process memory locking */ |
- char shmBaseName[1]; /* Name of the memory object !!! must last !!! */ |
-}; |
- |
- |
-/* |
-** Structure used internally by this VFS to record the state of an |
-** open shared memory connection. |
-** |
-** The following fields are initialized when this object is created and |
-** are read-only thereafter: |
-** |
-** os2Shm.pShmNode |
-** os2Shm.id |
-** |
-** All other fields are read/write. The os2Shm.pShmNode->mutex must be held |
-** while accessing any read/write fields. |
-*/ |
-struct os2ShmLink { |
- os2ShmNode *pShmNode; /* The underlying os2ShmNode object */ |
- os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */ |
- u32 sharedMask; /* Mask of shared locks held */ |
- u32 exclMask; /* Mask of exclusive locks held */ |
-#ifdef SQLITE_DEBUG |
- u8 id; /* Id of this connection with its os2ShmNode */ |
-#endif |
-}; |
- |
- |
-/* |
-** A global list of all os2ShmNode objects. |
-** |
-** The os2ShmMutexHeld() must be true while reading or writing this list. |
-*/ |
-static os2ShmNode *os2ShmNodeList = NULL; |
- |
-/* |
-** Constants used for locking |
-*/ |
-#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE |
-#define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */ |
-#else |
-#define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ |
-#endif |
- |
-#define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ |
- |
-/* |
-** Apply advisory locks for all n bytes beginning at ofst. |
-*/ |
-#define _SHM_UNLCK 1 /* no lock */ |
-#define _SHM_RDLCK 2 /* shared lock, no wait */ |
-#define _SHM_WRLCK 3 /* exlusive lock, no wait */ |
-#define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */ |
-static int os2ShmSystemLock( |
- os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */ |
- int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */ |
- int ofst, /* Offset to first byte to be locked/unlocked */ |
- int nByte /* Number of bytes to lock or unlock */ |
-){ |
- APIRET rc; |
- FILELOCK area; |
- ULONG mode, timeout; |
- |
- /* Access to the os2ShmNode object is serialized by the caller */ |
- assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 ); |
- |
- mode = 1; /* shared lock */ |
- timeout = 0; /* no wait */ |
- area.lOffset = ofst; |
- area.lRange = nByte; |
- |
- switch( lockType ) { |
- case _SHM_WRLCK_WAIT: |
- timeout = (ULONG)-1; /* wait forever */ |
- case _SHM_WRLCK: |
- mode = 0; /* exclusive lock */ |
- case _SHM_RDLCK: |
- rc = DosSetFileLocks(pNode->hLockFile, |
- NULL, &area, timeout, mode); |
- break; |
- /* case _SHM_UNLCK: */ |
- default: |
- rc = DosSetFileLocks(pNode->hLockFile, |
- &area, NULL, 0, 0); |
- break; |
- } |
- |
- OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n", |
- pNode->hLockFile, |
- rc==SQLITE_OK ? "ok" : "failed", |
- lockType==_SHM_UNLCK ? "Unlock" : "Lock", |
- rc)); |
- |
- ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName)) |
- |
- return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY; |
-} |
- |
-/* |
-** Find an os2ShmNode in global list or allocate a new one, if not found. |
-** |
-** This is not a VFS shared-memory method; it is a utility function called |
-** by VFS shared-memory methods. |
-*/ |
-static int os2OpenSharedMemory( os2File *fd, int szRegion ) { |
- os2ShmLink *pLink; |
- os2ShmNode *pNode; |
- int cbShmName, rc = SQLITE_OK; |
- char shmName[CCHMAXPATH + 30]; |
-#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE |
- ULONG action; |
-#endif |
- |
- /* We need some additional space at the end to append the region number */ |
- cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp ); |
- if( cbShmName >= CCHMAXPATH-8 ) |
- return SQLITE_IOERR_SHMOPEN; |
- |
- /* Replace colon in file name to form a valid shared memory name */ |
- shmName[10+1] = '!'; |
- |
- /* Allocate link object (we free it later in case of failure) */ |
- pLink = sqlite3_malloc( sizeof(*pLink) ); |
- if( !pLink ) |
- return SQLITE_NOMEM; |
- |
- /* Access node list */ |
- os2ShmEnterMutex(); |
- |
- /* Find node by it's shared memory base name */ |
- for( pNode = os2ShmNodeList; |
- pNode && stricmp(shmName, pNode->shmBaseName) != 0; |
- pNode = pNode->pNext ) ; |
- |
- /* Not found: allocate a new node */ |
- if( !pNode ) { |
- pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName ); |
- if( pNode ) { |
- memset(pNode, 0, sizeof(*pNode) ); |
- pNode->szRegion = szRegion; |
- pNode->hLockFile = (HFILE)-1; |
- strcpy(pNode->shmBaseName, shmName); |
- |
-#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE |
- if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) { |
-#else |
- sprintf(shmName, "%s-lck", fd->zFullPathCp); |
- if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL, |
- OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, |
- OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | |
- OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR, |
- NULL) != 0 ) { |
-#endif |
- sqlite3_free(pNode); |
- rc = SQLITE_IOERR; |
- } else { |
- pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
- if( !pNode->mutex ) { |
- sqlite3_free(pNode); |
- rc = SQLITE_NOMEM; |
- } |
- } |
- } else { |
- rc = SQLITE_NOMEM; |
- } |
- |
- if( rc == SQLITE_OK ) { |
- pNode->pNext = os2ShmNodeList; |
- os2ShmNodeList = pNode; |
- } else { |
- pNode = NULL; |
- } |
- } else if( pNode->szRegion != szRegion ) { |
- rc = SQLITE_IOERR_SHMSIZE; |
- pNode = NULL; |
- } |
- |
- if( pNode ) { |
- sqlite3_mutex_enter(pNode->mutex); |
- |
- memset(pLink, 0, sizeof(*pLink)); |
- |
- pLink->pShmNode = pNode; |
- pLink->pNext = pNode->pFirst; |
- pNode->pFirst = pLink; |
- pNode->nRef++; |
- |
- fd->pShmLink = pLink; |
- |
- sqlite3_mutex_leave(pNode->mutex); |
- |
- } else { |
- /* Error occured. Free our link object. */ |
- sqlite3_free(pLink); |
- } |
- |
- os2ShmLeaveMutex(); |
- |
- ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp)) |
- |
- return rc; |
-} |
- |
-/* |
-** Purge the os2ShmNodeList list of all entries with nRef==0. |
-** |
-** This is not a VFS shared-memory method; it is a utility function called |
-** by VFS shared-memory methods. |
-*/ |
-static void os2PurgeShmNodes( int deleteFlag ) { |
- os2ShmNode *pNode; |
- os2ShmNode **ppNode; |
- |
- os2ShmEnterMutex(); |
- |
- ppNode = &os2ShmNodeList; |
- |
- while( *ppNode ) { |
- pNode = *ppNode; |
- |
- if( pNode->nRef == 0 ) { |
- *ppNode = pNode->pNext; |
- |
- if( pNode->apRegion ) { |
- /* Prevent other processes from resizing the shared memory */ |
- os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); |
- |
- while( pNode->nRegion-- ) { |
-#ifdef SQLITE_DEBUG |
- int rc = |
-#endif |
- DosFreeMem(pNode->apRegion[pNode->nRegion]); |
- |
- OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n", |
- (int)GetCurrentProcessId(), pNode->nRegion, |
- rc == 0 ? "ok" : "failed")); |
- } |
- |
- /* Allow other processes to resize the shared memory */ |
- os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); |
- |
- sqlite3_free(pNode->apRegion); |
- } |
- |
- DosClose(pNode->hLockFile); |
- |
-#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE |
- if( deleteFlag ) { |
- char fileName[CCHMAXPATH]; |
- /* Skip "\\SHAREMEM\\" */ |
- sprintf(fileName, "%s-lck", pNode->shmBaseName + 10); |
- /* restore colon */ |
- fileName[1] = ':'; |
- |
- DosForceDelete(fileName); |
- } |
-#endif |
- |
- sqlite3_mutex_free(pNode->mutex); |
- |
- sqlite3_free(pNode); |
- |
- } else { |
- ppNode = &pNode->pNext; |
- } |
- } |
- |
- os2ShmLeaveMutex(); |
-} |
- |
-/* |
-** This function is called to obtain a pointer to region iRegion of the |
-** shared-memory associated with the database file id. Shared-memory regions |
-** are numbered starting from zero. Each shared-memory region is szRegion |
-** bytes in size. |
-** |
-** If an error occurs, an error code is returned and *pp is set to NULL. |
-** |
-** Otherwise, if the bExtend parameter is 0 and the requested shared-memory |
-** region has not been allocated (by any client, including one running in a |
-** separate process), then *pp is set to NULL and SQLITE_OK returned. If |
-** bExtend is non-zero and the requested shared-memory region has not yet |
-** been allocated, it is allocated by this function. |
-** |
-** If the shared-memory region has already been allocated or is allocated by |
-** this call as described above, then it is mapped into this processes |
-** address space (if it is not already), *pp is set to point to the mapped |
-** memory and SQLITE_OK returned. |
-*/ |
-static int os2ShmMap( |
- sqlite3_file *id, /* Handle open on database file */ |
- int iRegion, /* Region to retrieve */ |
- int szRegion, /* Size of regions */ |
- int bExtend, /* True to extend block if necessary */ |
- void volatile **pp /* OUT: Mapped memory */ |
-){ |
- PVOID pvTemp; |
- void **apRegion; |
- os2ShmNode *pNode; |
- int n, rc = SQLITE_OK; |
- char shmName[CCHMAXPATH]; |
- os2File *pFile = (os2File*)id; |
- |
- *pp = NULL; |
- |
- if( !pFile->pShmLink ) |
- rc = os2OpenSharedMemory( pFile, szRegion ); |
- |
- if( rc == SQLITE_OK ) { |
- pNode = pFile->pShmLink->pShmNode ; |
- |
- sqlite3_mutex_enter(pNode->mutex); |
- |
- assert( szRegion==pNode->szRegion ); |
- |
- /* Unmapped region ? */ |
- if( iRegion >= pNode->nRegion ) { |
- /* Prevent other processes from resizing the shared memory */ |
- os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); |
- |
- apRegion = sqlite3_realloc( |
- pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0])); |
- |
- if( apRegion ) { |
- pNode->apRegion = apRegion; |
- |
- while( pNode->nRegion <= iRegion ) { |
- sprintf(shmName, "%s-%u", |
- pNode->shmBaseName, pNode->nRegion); |
- |
- if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName, |
- PAG_READ | PAG_WRITE) != NO_ERROR ) { |
- if( !bExtend ) |
- break; |
- |
- if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, |
- PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR && |
- DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, |
- PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) { |
- rc = SQLITE_NOMEM; |
- break; |
- } |
- } |
- |
- apRegion[pNode->nRegion++] = pvTemp; |
- } |
- |
- /* zero out remaining entries */ |
- for( n = pNode->nRegion; n <= iRegion; n++ ) |
- pNode->apRegion[n] = NULL; |
- |
- /* Return this region (maybe zero) */ |
- *pp = pNode->apRegion[iRegion]; |
- } else { |
- rc = SQLITE_NOMEM; |
- } |
- |
- /* Allow other processes to resize the shared memory */ |
- os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); |
- |
- } else { |
- /* Region has been mapped previously */ |
- *pp = pNode->apRegion[iRegion]; |
- } |
- |
- sqlite3_mutex_leave(pNode->mutex); |
- } |
- |
- ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n", |
- pFile->zFullPathCp, iRegion, szRegion, bExtend, rc)) |
- |
- return rc; |
-} |
- |
-/* |
-** Close a connection to shared-memory. Delete the underlying |
-** storage if deleteFlag is true. |
-** |
-** If there is no shared memory associated with the connection then this |
-** routine is a harmless no-op. |
-*/ |
-static int os2ShmUnmap( |
- sqlite3_file *id, /* The underlying database file */ |
- int deleteFlag /* Delete shared-memory if true */ |
-){ |
- os2File *pFile = (os2File*)id; |
- os2ShmLink *pLink = pFile->pShmLink; |
- |
- if( pLink ) { |
- int nRef = -1; |
- os2ShmLink **ppLink; |
- os2ShmNode *pNode = pLink->pShmNode; |
- |
- sqlite3_mutex_enter(pNode->mutex); |
- |
- for( ppLink = &pNode->pFirst; |
- *ppLink && *ppLink != pLink; |
- ppLink = &(*ppLink)->pNext ) ; |
- |
- assert(*ppLink); |
- |
- if( *ppLink ) { |
- *ppLink = pLink->pNext; |
- nRef = --pNode->nRef; |
- } else { |
- ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n", |
- pNode->shmBaseName)) |
- } |
- |
- pFile->pShmLink = NULL; |
- sqlite3_free(pLink); |
- |
- sqlite3_mutex_leave(pNode->mutex); |
- |
- if( nRef == 0 ) |
- os2PurgeShmNodes( deleteFlag ); |
- } |
- |
- return SQLITE_OK; |
-} |
- |
-/* |
-** Change the lock state for a shared-memory segment. |
-** |
-** Note that the relationship between SHAREd and EXCLUSIVE locks is a little |
-** different here than in posix. In xShmLock(), one can go from unlocked |
-** to shared and back or from unlocked to exclusive and back. But one may |
-** not go from shared to exclusive or from exclusive to shared. |
-*/ |
-static int os2ShmLock( |
- sqlite3_file *id, /* Database file holding the shared memory */ |
- int ofst, /* First lock to acquire or release */ |
- int n, /* Number of locks to acquire or release */ |
- int flags /* What to do with the lock */ |
-){ |
- u32 mask; /* Mask of locks to take or release */ |
- int rc = SQLITE_OK; /* Result code */ |
- os2File *pFile = (os2File*)id; |
- os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */ |
- os2ShmLink *pX; /* For looping over all siblings */ |
- os2ShmNode *pShmNode = p->pShmNode; /* Our node */ |
- |
- assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); |
- assert( n>=1 ); |
- assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) |
- || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) |
- || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) |
- || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); |
- assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); |
- |
- mask = (u32)((1U<<(ofst+n)) - (1U<<ofst)); |
- assert( n>1 || mask==(1<<ofst) ); |
- |
- |
- sqlite3_mutex_enter(pShmNode->mutex); |
- |
- if( flags & SQLITE_SHM_UNLOCK ){ |
- u32 allMask = 0; /* Mask of locks held by siblings */ |
- |
- /* See if any siblings hold this same lock */ |
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
- if( pX==p ) continue; |
- assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); |
- allMask |= pX->sharedMask; |
- } |
- |
- /* Unlock the system-level locks */ |
- if( (mask & allMask)==0 ){ |
- rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n); |
- }else{ |
- rc = SQLITE_OK; |
- } |
- |
- /* Undo the local locks */ |
- if( rc==SQLITE_OK ){ |
- p->exclMask &= ~mask; |
- p->sharedMask &= ~mask; |
- } |
- }else if( flags & SQLITE_SHM_SHARED ){ |
- u32 allShared = 0; /* Union of locks held by connections other than "p" */ |
- |
- /* Find out which shared locks are already held by sibling connections. |
- ** If any sibling already holds an exclusive lock, go ahead and return |
- ** SQLITE_BUSY. |
- */ |
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
- if( (pX->exclMask & mask)!=0 ){ |
- rc = SQLITE_BUSY; |
- break; |
- } |
- allShared |= pX->sharedMask; |
- } |
- |
- /* Get shared locks at the system level, if necessary */ |
- if( rc==SQLITE_OK ){ |
- if( (allShared & mask)==0 ){ |
- rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n); |
- }else{ |
- rc = SQLITE_OK; |
- } |
- } |
- |
- /* Get the local shared locks */ |
- if( rc==SQLITE_OK ){ |
- p->sharedMask |= mask; |
- } |
- }else{ |
- /* Make sure no sibling connections hold locks that will block this |
- ** lock. If any do, return SQLITE_BUSY right away. |
- */ |
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
- if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ |
- rc = SQLITE_BUSY; |
- break; |
- } |
- } |
- |
- /* Get the exclusive locks at the system level. Then if successful |
- ** also mark the local connection as being locked. |
- */ |
- if( rc==SQLITE_OK ){ |
- rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n); |
- if( rc==SQLITE_OK ){ |
- assert( (p->sharedMask & mask)==0 ); |
- p->exclMask |= mask; |
- } |
- } |
- } |
- |
- sqlite3_mutex_leave(pShmNode->mutex); |
- |
- OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n", |
- p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask, |
- rc ? "failed" : "ok")); |
- |
- ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n", |
- ofst, n, flags, rc)) |
- |
- return rc; |
-} |
- |
-/* |
-** Implement a memory barrier or memory fence on shared memory. |
-** |
-** All loads and stores begun before the barrier must complete before |
-** any load or store begun after the barrier. |
-*/ |
-static void os2ShmBarrier( |
- sqlite3_file *id /* Database file holding the shared memory */ |
-){ |
- UNUSED_PARAMETER(id); |
- os2ShmEnterMutex(); |
- os2ShmLeaveMutex(); |
-} |
- |
-#else |
-# define os2ShmMap 0 |
-# define os2ShmLock 0 |
-# define os2ShmBarrier 0 |
-# define os2ShmUnmap 0 |
-#endif /* #ifndef SQLITE_OMIT_WAL */ |
- |
- |
-/* |
-** This vector defines all the methods that can operate on an |
-** sqlite3_file for os2. |
-*/ |
-static const sqlite3_io_methods os2IoMethod = { |
- 2, /* iVersion */ |
- os2Close, /* xClose */ |
- os2Read, /* xRead */ |
- os2Write, /* xWrite */ |
- os2Truncate, /* xTruncate */ |
- os2Sync, /* xSync */ |
- os2FileSize, /* xFileSize */ |
- os2Lock, /* xLock */ |
- os2Unlock, /* xUnlock */ |
- os2CheckReservedLock, /* xCheckReservedLock */ |
- os2FileControl, /* xFileControl */ |
- os2SectorSize, /* xSectorSize */ |
- os2DeviceCharacteristics, /* xDeviceCharacteristics */ |
- os2ShmMap, /* xShmMap */ |
- os2ShmLock, /* xShmLock */ |
- os2ShmBarrier, /* xShmBarrier */ |
- os2ShmUnmap /* xShmUnmap */ |
-}; |
- |
- |
-/*************************************************************************** |
-** Here ends the I/O methods that form the sqlite3_io_methods object. |
-** |
-** The next block of code implements the VFS methods. |
-****************************************************************************/ |
- |
-/* |
-** Create a temporary file name in zBuf. zBuf must be big enough to |
-** hold at pVfs->mxPathname characters. |
-*/ |
-static int getTempname(int nBuf, char *zBuf ){ |
- static const char zChars[] = |
- "abcdefghijklmnopqrstuvwxyz" |
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
- "0123456789"; |
- int i, j; |
- PSZ zTempPathCp; |
- char zTempPath[CCHMAXPATH]; |
- ULONG ulDriveNum, ulDriveMap; |
- |
- /* It's odd to simulate an io-error here, but really this is just |
- ** using the io-error infrastructure to test that SQLite handles this |
- ** function failing. |
- */ |
- SimulateIOError( return SQLITE_IOERR ); |
- |
- if( sqlite3_temp_directory ) { |
- sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory); |
- } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR || |
- DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR || |
- DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) { |
- char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp ); |
- sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF); |
- free( zTempPathUTF ); |
- } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) { |
- zTempPath[0] = (char)('A' + ulDriveNum - 1); |
- zTempPath[1] = ':'; |
- zTempPath[2] = '\0'; |
- } else { |
- zTempPath[0] = '\0'; |
- } |
- |
- /* Strip off a trailing slashes or backslashes, otherwise we would get * |
- * multiple (back)slashes which causes DosOpen() to fail. * |
- * Trailing spaces are not allowed, either. */ |
- j = sqlite3Strlen30(zTempPath); |
- while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' || |
- zTempPath[j-1] == ' ' ) ){ |
- j--; |
- } |
- zTempPath[j] = '\0'; |
- |
- /* We use 20 bytes to randomize the name */ |
- sqlite3_snprintf(nBuf-22, zBuf, |
- "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); |
- j = sqlite3Strlen30(zBuf); |
- sqlite3_randomness( 20, &zBuf[j] ); |
- for( i = 0; i < 20; i++, j++ ){ |
- zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
- } |
- zBuf[j] = 0; |
- |
- OSTRACE(( "TEMP FILENAME: %s\n", zBuf )); |
- return SQLITE_OK; |
-} |
- |
- |
-/* |
-** Turn a relative pathname into a full pathname. Write the full |
-** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname |
-** bytes in size. |
-*/ |
-static int os2FullPathname( |
- sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
- const char *zRelative, /* Possibly relative input path */ |
- int nFull, /* Size of output buffer in bytes */ |
- char *zFull /* Output buffer */ |
-){ |
- char *zRelativeCp = convertUtf8PathToCp( zRelative ); |
- char zFullCp[CCHMAXPATH] = "\0"; |
- char *zFullUTF; |
- APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME, |
- zFullCp, CCHMAXPATH ); |
- free( zRelativeCp ); |
- zFullUTF = convertCpPathToUtf8( zFullCp ); |
- sqlite3_snprintf( nFull, zFull, zFullUTF ); |
- free( zFullUTF ); |
- return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
-} |
- |
- |
-/* |
-** Open a file. |
-*/ |
-static int os2Open( |
- sqlite3_vfs *pVfs, /* Not used */ |
- const char *zName, /* Name of the file (UTF-8) */ |
- sqlite3_file *id, /* Write the SQLite file handle here */ |
- int flags, /* Open mode flags */ |
- int *pOutFlags /* Status return flags */ |
-){ |
- HFILE h; |
- ULONG ulOpenFlags = 0; |
- ULONG ulOpenMode = 0; |
- ULONG ulAction = 0; |
- ULONG rc; |
- os2File *pFile = (os2File*)id; |
- const char *zUtf8Name = zName; |
- char *zNameCp; |
- char zTmpname[CCHMAXPATH]; |
- |
- int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
- int isCreate = (flags & SQLITE_OPEN_CREATE); |
- int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
-#ifndef NDEBUG |
- int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); |
- int isReadonly = (flags & SQLITE_OPEN_READONLY); |
- int eType = (flags & 0xFFFFFF00); |
- int isOpenJournal = (isCreate && ( |
- eType==SQLITE_OPEN_MASTER_JOURNAL |
- || eType==SQLITE_OPEN_MAIN_JOURNAL |
- || eType==SQLITE_OPEN_WAL |
- )); |
-#endif |
- |
- UNUSED_PARAMETER(pVfs); |
- assert( id!=0 ); |
- |
- /* Check the following statements are true: |
- ** |
- ** (a) Exactly one of the READWRITE and READONLY flags must be set, and |
- ** (b) if CREATE is set, then READWRITE must also be set, and |
- ** (c) if EXCLUSIVE is set, then CREATE must also be set. |
- ** (d) if DELETEONCLOSE is set, then CREATE must also be set. |
- */ |
- assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); |
- assert(isCreate==0 || isReadWrite); |
- assert(isExclusive==0 || isCreate); |
- assert(isDelete==0 || isCreate); |
- |
- /* The main DB, main journal, WAL file and master journal are never |
- ** automatically deleted. Nor are they ever temporary files. */ |
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); |
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); |
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); |
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); |
- |
- /* Assert that the upper layer has set one of the "file-type" flags. */ |
- assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB |
- || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL |
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
- || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
- ); |
- |
- memset( pFile, 0, sizeof(*pFile) ); |
- pFile->h = (HFILE)-1; |
- |
- /* If the second argument to this function is NULL, generate a |
- ** temporary file name to use |
- */ |
- if( !zUtf8Name ){ |
- assert(isDelete && !isOpenJournal); |
- rc = getTempname(CCHMAXPATH, zTmpname); |
- if( rc!=SQLITE_OK ){ |
- return rc; |
- } |
- zUtf8Name = zTmpname; |
- } |
- |
- if( isReadWrite ){ |
- ulOpenMode |= OPEN_ACCESS_READWRITE; |
- }else{ |
- ulOpenMode |= OPEN_ACCESS_READONLY; |
- } |
- |
- /* Open in random access mode for possibly better speed. Allow full |
- ** sharing because file locks will provide exclusive access when needed. |
- ** The handle should not be inherited by child processes and we don't |
- ** want popups from the critical error handler. |
- */ |
- ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | |
- OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR; |
- |
- /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is |
- ** created. SQLite doesn't use it to indicate "exclusive access" |
- ** as it is usually understood. |
- */ |
- if( isExclusive ){ |
- /* Creates a new file, only if it does not already exist. */ |
- /* If the file exists, it fails. */ |
- ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS; |
- }else if( isCreate ){ |
- /* Open existing file, or create if it doesn't exist */ |
- ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
- }else{ |
- /* Opens a file, only if it exists. */ |
- ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
- } |
- |
- zNameCp = convertUtf8PathToCp( zUtf8Name ); |
- rc = DosOpen( (PSZ)zNameCp, |
- &h, |
- &ulAction, |
- 0L, |
- FILE_NORMAL, |
- ulOpenFlags, |
- ulOpenMode, |
- (PEAOP2)NULL ); |
- free( zNameCp ); |
- |
- if( rc != NO_ERROR ){ |
- OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n", |
- rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode )); |
- |
- if( isReadWrite ){ |
- return os2Open( pVfs, zName, id, |
- ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), |
- pOutFlags ); |
- }else{ |
- return SQLITE_CANTOPEN; |
- } |
- } |
- |
- if( pOutFlags ){ |
- *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; |
- } |
- |
- os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname ); |
- pFile->zFullPathCp = convertUtf8PathToCp( zTmpname ); |
- pFile->pMethod = &os2IoMethod; |
- pFile->flags = flags; |
- pFile->h = h; |
- |
- OpenCounter(+1); |
- OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags )); |
- return SQLITE_OK; |
-} |
- |
-/* |
-** Delete the named file. |
-*/ |
-static int os2Delete( |
- sqlite3_vfs *pVfs, /* Not used on os2 */ |
- const char *zFilename, /* Name of file to delete */ |
- int syncDir /* Not used on os2 */ |
-){ |
- APIRET rc; |
- char *zFilenameCp; |
- SimulateIOError( return SQLITE_IOERR_DELETE ); |
- zFilenameCp = convertUtf8PathToCp( zFilename ); |
- rc = DosDelete( (PSZ)zFilenameCp ); |
- free( zFilenameCp ); |
- OSTRACE(( "DELETE \"%s\"\n", zFilename )); |
- return (rc == NO_ERROR || |
- rc == ERROR_FILE_NOT_FOUND || |
- rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE; |
-} |
- |
-/* |
-** Check the existance and status of a file. |
-*/ |
-static int os2Access( |
- sqlite3_vfs *pVfs, /* Not used on os2 */ |
- const char *zFilename, /* Name of file to check */ |
- int flags, /* Type of test to make on this file */ |
- int *pOut /* Write results here */ |
-){ |
- APIRET rc; |
- FILESTATUS3 fsts3ConfigInfo; |
- char *zFilenameCp; |
- |
- UNUSED_PARAMETER(pVfs); |
- SimulateIOError( return SQLITE_IOERR_ACCESS; ); |
- |
- zFilenameCp = convertUtf8PathToCp( zFilename ); |
- rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, |
- &fsts3ConfigInfo, sizeof(FILESTATUS3) ); |
- free( zFilenameCp ); |
- OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", |
- fsts3ConfigInfo.attrFile, flags, rc )); |
- |
- switch( flags ){ |
- case SQLITE_ACCESS_EXISTS: |
- /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file |
- ** as if it does not exist. |
- */ |
- if( fsts3ConfigInfo.cbFile == 0 ) |
- rc = ERROR_FILE_NOT_FOUND; |
- break; |
- case SQLITE_ACCESS_READ: |
- break; |
- case SQLITE_ACCESS_READWRITE: |
- if( fsts3ConfigInfo.attrFile & FILE_READONLY ) |
- rc = ERROR_ACCESS_DENIED; |
- break; |
- default: |
- rc = ERROR_FILE_NOT_FOUND; |
- assert( !"Invalid flags argument" ); |
- } |
- |
- *pOut = (rc == NO_ERROR); |
- OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut )); |
- |
- return SQLITE_OK; |
-} |
- |
- |
-#ifndef SQLITE_OMIT_LOAD_EXTENSION |
-/* |
-** Interfaces for opening a shared library, finding entry points |
-** within the shared library, and closing the shared library. |
-*/ |
-/* |
-** Interfaces for opening a shared library, finding entry points |
-** within the shared library, and closing the shared library. |
-*/ |
-static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
- HMODULE hmod; |
- APIRET rc; |
- char *zFilenameCp = convertUtf8PathToCp(zFilename); |
- rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod); |
- free(zFilenameCp); |
- return rc != NO_ERROR ? 0 : (void*)hmod; |
-} |
-/* |
-** A no-op since the error code is returned on the DosLoadModule call. |
-** os2Dlopen returns zero if DosLoadModule is not successful. |
-*/ |
-static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ |
-/* no-op */ |
-} |
-static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ |
- PFN pfn; |
- APIRET rc; |
- rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn); |
- if( rc != NO_ERROR ){ |
- /* if the symbol itself was not found, search again for the same |
- * symbol with an extra underscore, that might be needed depending |
- * on the calling convention */ |
- char _zSymbol[256] = "_"; |
- strncat(_zSymbol, zSymbol, 254); |
- rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn); |
- } |
- return rc != NO_ERROR ? 0 : (void(*)(void))pfn; |
-} |
-static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ |
- DosFreeModule((HMODULE)pHandle); |
-} |
-#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ |
- #define os2DlOpen 0 |
- #define os2DlError 0 |
- #define os2DlSym 0 |
- #define os2DlClose 0 |
-#endif |
- |
- |
-/* |
-** Write up to nBuf bytes of randomness into zBuf. |
-*/ |
-static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){ |
- int n = 0; |
-#if defined(SQLITE_TEST) |
- n = nBuf; |
- memset(zBuf, 0, nBuf); |
-#else |
- int i; |
- PPIB ppib; |
- PTIB ptib; |
- DATETIME dt; |
- static unsigned c = 0; |
- /* Ordered by variation probability */ |
- static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW, |
- QSV_MAXPRMEM, QSV_MAXSHMEM, |
- QSV_TOTAVAILMEM, QSV_TOTRESMEM }; |
- |
- /* 8 bytes; timezone and weekday don't increase the randomness much */ |
- if( (int)sizeof(dt)-3 <= nBuf - n ){ |
- c += 0x0100; |
- DosGetDateTime(&dt); |
- dt.year = (USHORT)((dt.year - 1900) | c); |
- memcpy(&zBuf[n], &dt, sizeof(dt)-3); |
- n += sizeof(dt)-3; |
- } |
- |
- /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */ |
- if( (int)sizeof(ULONG) <= nBuf - n ){ |
- DosGetInfoBlocks(&ptib, &ppib); |
- *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid, |
- ptib->tib_ptib2->tib2_ultid); |
- n += sizeof(ULONG); |
- } |
- |
- /* Up to 6 * 4 bytes; variables depend on the system state */ |
- for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){ |
- DosQuerySysInfo(svIdx[i], svIdx[i], |
- (PULONG)&zBuf[n], sizeof(ULONG)); |
- n += sizeof(ULONG); |
- } |
-#endif |
- |
- return n; |
-} |
- |
-/* |
-** Sleep for a little while. Return the amount of time slept. |
-** The argument is the number of microseconds we want to sleep. |
-** The return value is the number of microseconds of sleep actually |
-** requested from the underlying operating system, a number which |
-** might be greater than or equal to the argument, but not less |
-** than the argument. |
-*/ |
-static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){ |
- DosSleep( (microsec/1000) ); |
- return microsec; |
-} |
- |
-/* |
-** The following variable, if set to a non-zero value, becomes the result |
-** returned from sqlite3OsCurrentTime(). This is used for testing. |
-*/ |
-#ifdef SQLITE_TEST |
-int sqlite3_current_time = 0; |
-#endif |
- |
-/* |
-** Find the current time (in Universal Coordinated Time). Write into *piNow |
-** the current time and date as a Julian Day number times 86_400_000. In |
-** other words, write into *piNow the number of milliseconds since the Julian |
-** epoch of noon in Greenwich on November 24, 4714 B.C according to the |
-** proleptic Gregorian calendar. |
-** |
-** On success, return 0. Return 1 if the time and date cannot be found. |
-*/ |
-static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ |
-#ifdef SQLITE_TEST |
- static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; |
-#endif |
- int year, month, datepart, timepart; |
- |
- DATETIME dt; |
- DosGetDateTime( &dt ); |
- |
- year = dt.year; |
- month = dt.month; |
- |
- /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html |
- ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c |
- ** Calculate the Julian days |
- */ |
- datepart = (int)dt.day - 32076 + |
- 1461*(year + 4800 + (month - 14)/12)/4 + |
- 367*(month - 2 - (month - 14)/12*12)/12 - |
- 3*((year + 4900 + (month - 14)/12)/100)/4; |
- |
- /* Time in milliseconds, hours to noon added */ |
- timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 + |
- ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000; |
- |
- *piNow = (sqlite3_int64)datepart*86400*1000 + timepart; |
- |
-#ifdef SQLITE_TEST |
- if( sqlite3_current_time ){ |
- *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; |
- } |
-#endif |
- |
- UNUSED_PARAMETER(pVfs); |
- return 0; |
-} |
- |
-/* |
-** Find the current time (in Universal Coordinated Time). Write the |
-** current time and date as a Julian Day number into *prNow and |
-** return 0. Return 1 if the time and date cannot be found. |
-*/ |
-static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ |
- int rc; |
- sqlite3_int64 i; |
- rc = os2CurrentTimeInt64(pVfs, &i); |
- if( !rc ){ |
- *prNow = i/86400000.0; |
- } |
- return rc; |
-} |
- |
-/* |
-** The idea is that this function works like a combination of |
-** GetLastError() and FormatMessage() on windows (or errno and |
-** strerror_r() on unix). After an error is returned by an OS |
-** function, SQLite calls this function with zBuf pointing to |
-** a buffer of nBuf bytes. The OS layer should populate the |
-** buffer with a nul-terminated UTF-8 encoded error message |
-** describing the last IO error to have occurred within the calling |
-** thread. |
-** |
-** If the error message is too large for the supplied buffer, |
-** it should be truncated. The return value of xGetLastError |
-** is zero if the error message fits in the buffer, or non-zero |
-** otherwise (if the message was truncated). If non-zero is returned, |
-** then it is not necessary to include the nul-terminator character |
-** in the output buffer. |
-** |
-** Not supplying an error message will have no adverse effect |
-** on SQLite. It is fine to have an implementation that never |
-** returns an error message: |
-** |
-** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
-** assert(zBuf[0]=='\0'); |
-** return 0; |
-** } |
-** |
-** However if an error message is supplied, it will be incorporated |
-** by sqlite into the error message available to the user using |
-** sqlite3_errmsg(), possibly making IO errors easier to debug. |
-*/ |
-static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
- assert(zBuf[0]=='\0'); |
- return 0; |
-} |
- |
-/* |
-** Initialize and deinitialize the operating system interface. |
-*/ |
-int sqlite3_os_init(void){ |
- static sqlite3_vfs os2Vfs = { |
- 3, /* iVersion */ |
- sizeof(os2File), /* szOsFile */ |
- CCHMAXPATH, /* mxPathname */ |
- 0, /* pNext */ |
- "os2", /* zName */ |
- 0, /* pAppData */ |
- |
- os2Open, /* xOpen */ |
- os2Delete, /* xDelete */ |
- os2Access, /* xAccess */ |
- os2FullPathname, /* xFullPathname */ |
- os2DlOpen, /* xDlOpen */ |
- os2DlError, /* xDlError */ |
- os2DlSym, /* xDlSym */ |
- os2DlClose, /* xDlClose */ |
- os2Randomness, /* xRandomness */ |
- os2Sleep, /* xSleep */ |
- os2CurrentTime, /* xCurrentTime */ |
- os2GetLastError, /* xGetLastError */ |
- os2CurrentTimeInt64, /* xCurrentTimeInt64 */ |
- 0, /* xSetSystemCall */ |
- 0, /* xGetSystemCall */ |
- 0 /* xNextSystemCall */ |
- }; |
- sqlite3_vfs_register(&os2Vfs, 1); |
- initUconvObjects(); |
-/* sqlite3OSTrace = 1; */ |
- return SQLITE_OK; |
-} |
-int sqlite3_os_end(void){ |
- freeUconvObjects(); |
- return SQLITE_OK; |
-} |
- |
-#endif /* SQLITE_OS_OS2 */ |