blob: 058a801300b2fd042e2ab5c1499436d82a1b54d6 [file] [log] [blame]
drh60a1e4b2006-06-03 18:02:15 +00001/*
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.
danielk1977822a5162008-05-16 04:51:54 +000014**
pweilbacherc06b54f2008-11-22 19:50:53 +000015** $Id: os_os2.c,v 1.60 2008/11/22 19:50:54 pweilbacher Exp $
drh60a1e4b2006-06-03 18:02:15 +000016*/
pweilbacher4fffb4f2006-12-22 20:33:13 +000017
drh60a1e4b2006-06-03 18:02:15 +000018#include "sqliteInt.h"
drh60a1e4b2006-06-03 18:02:15 +000019
danielk197729bafea2008-06-26 10:41:19 +000020#if SQLITE_OS_OS2
drh60a1e4b2006-06-03 18:02:15 +000021
22/*
pweilbacherb36dc732007-10-21 22:47:03 +000023** A Note About Memory Allocation:
24**
25** This driver uses malloc()/free() directly rather than going through
26** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers
27** are designed for use on embedded systems where memory is scarce and
28** malloc failures happen frequently. OS/2 does not typically run on
29** embedded systems, and when it does the developers normally have bigger
30** problems to worry about than running out of memory. So there is not
31** a compelling need to use the wrappers.
32**
33** But there is a good reason to not use the wrappers. If we use the
34** wrappers then we will get simulated malloc() failures within this
35** driver. And that causes all kinds of problems for our tests. We
36** could enhance SQLite to deal with simulated malloc failures within
37** the OS driver, but the code to deal with those failure would not
38** be exercised on Linux (which does not need to malloc() in the driver)
39** and so we would have difficulty writing coverage tests for that
40** code. Better to leave the code out, we think.
41**
42** The point of this discussion is as follows: When creating a new
43** OS layer for an embedded system, if you use this file as an example,
44** avoid the use of malloc()/free(). Those routines work ok on OS/2
45** desktops but not so well in embedded systems.
46*/
47
48/*
drh60a1e4b2006-06-03 18:02:15 +000049** Macros used to determine whether or not to use threads.
50*/
pweilbacherb36dc732007-10-21 22:47:03 +000051#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE
drh60a1e4b2006-06-03 18:02:15 +000052# define SQLITE_OS2_THREADS 1
53#endif
54
55/*
56** Include code that is common to all os_*.c files
57*/
58#include "os_common.h"
59
60/*
pweilbacherb36dc732007-10-21 22:47:03 +000061** The os2File structure is subclass of sqlite3_file specific for the OS/2
drh60a1e4b2006-06-03 18:02:15 +000062** protability layer.
63*/
64typedef struct os2File os2File;
65struct os2File {
pweilbacherb36dc732007-10-21 22:47:03 +000066 const sqlite3_io_methods *pMethod; /* Always the first entry */
drh60a1e4b2006-06-03 18:02:15 +000067 HFILE h; /* Handle for accessing the file */
pweilbacher7c74f122008-05-06 21:42:09 +000068 char* pathToDel; /* Name of file to delete on close, NULL if not */
drh60a1e4b2006-06-03 18:02:15 +000069 unsigned char locktype; /* Type of lock currently held on this file */
70};
71
pweilbacherf19dfc42008-05-12 00:32:08 +000072#define LOCK_TIMEOUT 10L /* the default locking timeout */
73
pweilbacherb36dc732007-10-21 22:47:03 +000074/*****************************************************************************
75** The next group of routines implement the I/O methods specified
76** by the sqlite3_io_methods object.
77******************************************************************************/
drh60a1e4b2006-06-03 18:02:15 +000078
79/*
80** Close a file.
81*/
pweilbacher7f6358b2008-07-08 19:46:24 +000082static int os2Close( sqlite3_file *id ){
pweilbacher04bd0c12006-06-24 12:38:59 +000083 APIRET rc = NO_ERROR;
pweilbacherb36dc732007-10-21 22:47:03 +000084 os2File *pFile;
85 if( id && (pFile = (os2File*)id) != 0 ){
drh4f0c5872007-03-26 22:05:01 +000086 OSTRACE2( "CLOSE %d\n", pFile->h );
pweilbacher04bd0c12006-06-24 12:38:59 +000087 rc = DosClose( pFile->h );
drh60a1e4b2006-06-03 18:02:15 +000088 pFile->locktype = NO_LOCK;
pweilbacher7c74f122008-05-06 21:42:09 +000089 if( pFile->pathToDel != NULL ){
pweilbacherb36dc732007-10-21 22:47:03 +000090 rc = DosForceDelete( (PSZ)pFile->pathToDel );
pweilbacherb36dc732007-10-21 22:47:03 +000091 free( pFile->pathToDel );
pweilbacher7c74f122008-05-06 21:42:09 +000092 pFile->pathToDel = NULL;
pweilbacherb36dc732007-10-21 22:47:03 +000093 }
94 id = 0;
drh60a1e4b2006-06-03 18:02:15 +000095 OpenCounter( -1 );
96 }
97
pweilbacher04bd0c12006-06-24 12:38:59 +000098 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
drh60a1e4b2006-06-03 18:02:15 +000099}
100
101/*
102** Read data from a file into a buffer. Return SQLITE_OK if all
103** bytes were read successfully and SQLITE_IOERR if anything goes
104** wrong.
105*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000106static int os2Read(
pweilbacherb36dc732007-10-21 22:47:03 +0000107 sqlite3_file *id, /* File to read from */
108 void *pBuf, /* Write content into this buffer */
109 int amt, /* Number of bytes to read */
110 sqlite3_int64 offset /* Begin reading at this offset */
111){
112 ULONG fileLocation = 0L;
drh60a1e4b2006-06-03 18:02:15 +0000113 ULONG got;
pweilbacherb36dc732007-10-21 22:47:03 +0000114 os2File *pFile = (os2File*)id;
drh60a1e4b2006-06-03 18:02:15 +0000115 assert( id!=0 );
pweilbacherb36dc732007-10-21 22:47:03 +0000116 SimulateIOError( return SQLITE_IOERR_READ );
117 OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype );
118 if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
119 return SQLITE_IOERR;
120 }
121 if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){
pweilbacher4a53cdb2007-01-28 21:12:13 +0000122 return SQLITE_IOERR_READ;
pweilbacherb36dc732007-10-21 22:47:03 +0000123 }
124 if( got == (ULONG)amt )
125 return SQLITE_OK;
pweilbacher4a53cdb2007-01-28 21:12:13 +0000126 else {
drh4c17c3f2008-11-07 00:06:18 +0000127 /* Unread portions of the input buffer must be zero-filled */
pweilbacher4a53cdb2007-01-28 21:12:13 +0000128 memset(&((char*)pBuf)[got], 0, amt-got);
129 return SQLITE_IOERR_SHORT_READ;
130 }
drh60a1e4b2006-06-03 18:02:15 +0000131}
132
133/*
134** Write data from a buffer into a file. Return SQLITE_OK on success
135** or some other error code on failure.
136*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000137static int os2Write(
pweilbacherb36dc732007-10-21 22:47:03 +0000138 sqlite3_file *id, /* File to write into */
139 const void *pBuf, /* The bytes to be written */
140 int amt, /* Number of bytes to write */
141 sqlite3_int64 offset /* Offset into the file to begin writing at */
142){
143 ULONG fileLocation = 0L;
pweilbacher04bd0c12006-06-24 12:38:59 +0000144 APIRET rc = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000145 ULONG wrote;
pweilbacherb36dc732007-10-21 22:47:03 +0000146 os2File *pFile = (os2File*)id;
drh60a1e4b2006-06-03 18:02:15 +0000147 assert( id!=0 );
pweilbacherb36dc732007-10-21 22:47:03 +0000148 SimulateIOError( return SQLITE_IOERR_WRITE );
drh59685932006-09-14 13:47:11 +0000149 SimulateDiskfullError( return SQLITE_FULL );
pweilbacherb36dc732007-10-21 22:47:03 +0000150 OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype );
151 if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
152 return SQLITE_IOERR;
153 }
154 assert( amt>0 );
drh60a1e4b2006-06-03 18:02:15 +0000155 while( amt > 0 &&
pweilbacher8bf23da2008-05-12 16:56:13 +0000156 ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR &&
pweilbacherb36dc732007-10-21 22:47:03 +0000157 wrote > 0
158 ){
159 amt -= wrote;
160 pBuf = &((char*)pBuf)[wrote];
drh60a1e4b2006-06-03 18:02:15 +0000161 }
162
163 return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
164}
165
166/*
pweilbacherb36dc732007-10-21 22:47:03 +0000167** Truncate an open file to a specified size
drh60a1e4b2006-06-03 18:02:15 +0000168*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000169static int os2Truncate( sqlite3_file *id, i64 nByte ){
pweilbacher04bd0c12006-06-24 12:38:59 +0000170 APIRET rc = NO_ERROR;
pweilbacherb36dc732007-10-21 22:47:03 +0000171 os2File *pFile = (os2File*)id;
172 OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte );
173 SimulateIOError( return SQLITE_IOERR_TRUNCATE );
pweilbacher0fd508e2008-02-01 00:31:59 +0000174 rc = DosSetFileSize( pFile->h, nByte );
pweilbacherab88e172008-10-13 21:46:46 +0000175 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
drh60a1e4b2006-06-03 18:02:15 +0000176}
177
pweilbacherb36dc732007-10-21 22:47:03 +0000178#ifdef SQLITE_TEST
179/*
180** Count the number of fullsyncs and normal syncs. This is used to test
181** that syncs and fullsyncs are occuring at the right times.
182*/
183int sqlite3_sync_count = 0;
184int sqlite3_fullsync_count = 0;
185#endif
186
drh60a1e4b2006-06-03 18:02:15 +0000187/*
188** Make sure all writes to a particular file are committed to disk.
189*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000190static int os2Sync( sqlite3_file *id, int flags ){
pweilbacherb36dc732007-10-21 22:47:03 +0000191 os2File *pFile = (os2File*)id;
192 OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );
193#ifdef SQLITE_TEST
194 if( flags & SQLITE_SYNC_FULL){
195 sqlite3_fullsync_count++;
drh60a1e4b2006-06-03 18:02:15 +0000196 }
pweilbacherb36dc732007-10-21 22:47:03 +0000197 sqlite3_sync_count++;
198#endif
pweilbacher50128ae2008-11-18 23:03:39 +0000199 /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
200 ** no-op
201 */
202#ifdef SQLITE_NO_SYNC
203 return SQLITE_OK;
204#else
pweilbacherb36dc732007-10-21 22:47:03 +0000205 return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
pweilbacher50128ae2008-11-18 23:03:39 +0000206#endif
drh60a1e4b2006-06-03 18:02:15 +0000207}
208
209/*
210** Determine the current size of a file in bytes
211*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000212static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){
pweilbacher04bd0c12006-06-24 12:38:59 +0000213 APIRET rc = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000214 FILESTATUS3 fsts3FileInfo;
215 memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo));
216 assert( id!=0 );
pweilbacherab88e172008-10-13 21:46:46 +0000217 SimulateIOError( return SQLITE_IOERR_FSTAT );
drh60a1e4b2006-06-03 18:02:15 +0000218 rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) );
219 if( rc == NO_ERROR ){
220 *pSize = fsts3FileInfo.cbFile;
221 return SQLITE_OK;
pweilbacherb36dc732007-10-21 22:47:03 +0000222 }else{
pweilbacherab88e172008-10-13 21:46:46 +0000223 return SQLITE_IOERR_FSTAT;
drh60a1e4b2006-06-03 18:02:15 +0000224 }
225}
226
227/*
228** Acquire a reader lock.
229*/
pweilbacherb36dc732007-10-21 22:47:03 +0000230static int getReadLock( os2File *pFile ){
drh60a1e4b2006-06-03 18:02:15 +0000231 FILELOCK LockArea,
232 UnlockArea;
pweilbacherb36dc732007-10-21 22:47:03 +0000233 APIRET res;
drh60a1e4b2006-06-03 18:02:15 +0000234 memset(&LockArea, 0, sizeof(LockArea));
235 memset(&UnlockArea, 0, sizeof(UnlockArea));
236 LockArea.lOffset = SHARED_FIRST;
237 LockArea.lRange = SHARED_SIZE;
238 UnlockArea.lOffset = 0L;
239 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000240 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
pweilbacherb36dc732007-10-21 22:47:03 +0000241 OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
242 return res;
drh60a1e4b2006-06-03 18:02:15 +0000243}
244
245/*
246** Undo a readlock
247*/
248static int unlockReadLock( os2File *id ){
249 FILELOCK LockArea,
250 UnlockArea;
pweilbacherb36dc732007-10-21 22:47:03 +0000251 APIRET res;
drh60a1e4b2006-06-03 18:02:15 +0000252 memset(&LockArea, 0, sizeof(LockArea));
253 memset(&UnlockArea, 0, sizeof(UnlockArea));
254 LockArea.lOffset = 0L;
255 LockArea.lRange = 0L;
256 UnlockArea.lOffset = SHARED_FIRST;
257 UnlockArea.lRange = SHARED_SIZE;
pweilbacherf19dfc42008-05-12 00:32:08 +0000258 res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
pweilbacherb36dc732007-10-21 22:47:03 +0000259 OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
260 return res;
drh60a1e4b2006-06-03 18:02:15 +0000261}
262
drh60a1e4b2006-06-03 18:02:15 +0000263/*
264** Lock the file with the lock specified by parameter locktype - one
265** of the following:
266**
267** (1) SHARED_LOCK
268** (2) RESERVED_LOCK
269** (3) PENDING_LOCK
270** (4) EXCLUSIVE_LOCK
271**
272** Sometimes when requesting one lock state, additional lock states
273** are inserted in between. The locking might fail on one of the later
274** transitions leaving the lock state different from what it started but
275** still short of its goal. The following chart shows the allowed
276** transitions and the inserted intermediate states:
277**
278** UNLOCKED -> SHARED
279** SHARED -> RESERVED
280** SHARED -> (PENDING) -> EXCLUSIVE
281** RESERVED -> (PENDING) -> EXCLUSIVE
282** PENDING -> EXCLUSIVE
283**
284** This routine will only increase a lock. The os2Unlock() routine
285** erases all locks at once and returns us immediately to locking level 0.
286** It is not possible to lower the locking level one step at a time. You
287** must go straight to locking level 0.
288*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000289static int os2Lock( sqlite3_file *id, int locktype ){
pweilbacherb36dc732007-10-21 22:47:03 +0000290 int rc = SQLITE_OK; /* Return code from subroutines */
pweilbacher04bd0c12006-06-24 12:38:59 +0000291 APIRET res = NO_ERROR; /* Result of an OS/2 lock call */
pweilbacherb36dc732007-10-21 22:47:03 +0000292 int newLocktype; /* Set pFile->locktype to this value before exiting */
drh60a1e4b2006-06-03 18:02:15 +0000293 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
294 FILELOCK LockArea,
295 UnlockArea;
296 os2File *pFile = (os2File*)id;
297 memset(&LockArea, 0, sizeof(LockArea));
298 memset(&UnlockArea, 0, sizeof(UnlockArea));
299 assert( pFile!=0 );
drh4f0c5872007-03-26 22:05:01 +0000300 OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000301
302 /* If there is already a lock of this type or more restrictive on the
pweilbacherb36dc732007-10-21 22:47:03 +0000303 ** os2File, do nothing. Don't use the end_lock: exit path, as
pweilbacherd190be82008-04-15 18:50:02 +0000304 ** sqlite3_mutex_enter() hasn't been called yet.
drh60a1e4b2006-06-03 18:02:15 +0000305 */
306 if( pFile->locktype>=locktype ){
pweilbacherb36dc732007-10-21 22:47:03 +0000307 OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
drh60a1e4b2006-06-03 18:02:15 +0000308 return SQLITE_OK;
309 }
310
311 /* Make sure the locking sequence is correct
312 */
313 assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
314 assert( locktype!=PENDING_LOCK );
315 assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
316
317 /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
318 ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
319 ** the PENDING_LOCK byte is temporary.
320 */
321 newLocktype = pFile->locktype;
322 if( pFile->locktype==NO_LOCK
pweilbacherb36dc732007-10-21 22:47:03 +0000323 || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
drh60a1e4b2006-06-03 18:02:15 +0000324 ){
drh60a1e4b2006-06-03 18:02:15 +0000325 LockArea.lOffset = PENDING_BYTE;
326 LockArea.lRange = 1L;
327 UnlockArea.lOffset = 0L;
328 UnlockArea.lRange = 0L;
329
pweilbacherf19dfc42008-05-12 00:32:08 +0000330 /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */
331 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
332 if( res == NO_ERROR ){
pweilbacherb36dc732007-10-21 22:47:03 +0000333 gotPendingLock = 1;
334 OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res );
335 }
drh60a1e4b2006-06-03 18:02:15 +0000336 }
337
338 /* Acquire a shared lock
339 */
pweilbacherb36dc732007-10-21 22:47:03 +0000340 if( locktype==SHARED_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000341 assert( pFile->locktype==NO_LOCK );
342 res = getReadLock(pFile);
343 if( res == NO_ERROR ){
344 newLocktype = SHARED_LOCK;
345 }
pweilbacherb36dc732007-10-21 22:47:03 +0000346 OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000347 }
348
349 /* Acquire a RESERVED lock
350 */
pweilbacherb36dc732007-10-21 22:47:03 +0000351 if( locktype==RESERVED_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000352 assert( pFile->locktype==SHARED_LOCK );
353 LockArea.lOffset = RESERVED_BYTE;
354 LockArea.lRange = 1L;
355 UnlockArea.lOffset = 0L;
356 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000357 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
drh60a1e4b2006-06-03 18:02:15 +0000358 if( res == NO_ERROR ){
359 newLocktype = RESERVED_LOCK;
360 }
pweilbacherb36dc732007-10-21 22:47:03 +0000361 OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000362 }
363
364 /* Acquire a PENDING lock
365 */
pweilbacherb36dc732007-10-21 22:47:03 +0000366 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000367 newLocktype = PENDING_LOCK;
368 gotPendingLock = 0;
pweilbacherb36dc732007-10-21 22:47:03 +0000369 OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
drh60a1e4b2006-06-03 18:02:15 +0000370 }
371
372 /* Acquire an EXCLUSIVE lock
373 */
pweilbacherb36dc732007-10-21 22:47:03 +0000374 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000375 assert( pFile->locktype>=SHARED_LOCK );
376 res = unlockReadLock(pFile);
drh4f0c5872007-03-26 22:05:01 +0000377 OSTRACE2( "unreadlock = %d\n", res );
drh60a1e4b2006-06-03 18:02:15 +0000378 LockArea.lOffset = SHARED_FIRST;
379 LockArea.lRange = SHARED_SIZE;
380 UnlockArea.lOffset = 0L;
381 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000382 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
drh60a1e4b2006-06-03 18:02:15 +0000383 if( res == NO_ERROR ){
384 newLocktype = EXCLUSIVE_LOCK;
385 }else{
pweilbacherb36dc732007-10-21 22:47:03 +0000386 OSTRACE2( "OS/2 error-code = %d\n", res );
387 getReadLock(pFile);
drh60a1e4b2006-06-03 18:02:15 +0000388 }
pweilbacherb36dc732007-10-21 22:47:03 +0000389 OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000390 }
391
392 /* If we are holding a PENDING lock that ought to be released, then
393 ** release it now.
394 */
395 if( gotPendingLock && locktype==SHARED_LOCK ){
pweilbacherb36dc732007-10-21 22:47:03 +0000396 int r;
drh60a1e4b2006-06-03 18:02:15 +0000397 LockArea.lOffset = 0L;
398 LockArea.lRange = 0L;
399 UnlockArea.lOffset = PENDING_BYTE;
400 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000401 r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000402 OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
drh60a1e4b2006-06-03 18:02:15 +0000403 }
404
405 /* Update the state of the lock has held in the file descriptor then
406 ** return the appropriate result code.
407 */
408 if( res == NO_ERROR ){
409 rc = SQLITE_OK;
410 }else{
drh4f0c5872007-03-26 22:05:01 +0000411 OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
pweilbacherb36dc732007-10-21 22:47:03 +0000412 locktype, newLocktype );
drh60a1e4b2006-06-03 18:02:15 +0000413 rc = SQLITE_BUSY;
414 }
415 pFile->locktype = newLocktype;
pweilbacherb36dc732007-10-21 22:47:03 +0000416 OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000417 return rc;
418}
419
420/*
421** This routine checks if there is a RESERVED lock held on the specified
422** file by this or any other process. If such a lock is held, return
423** non-zero, otherwise zero.
424*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000425static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
pweilbacherd4c8a602008-02-14 00:00:50 +0000426 int r = 0;
drh60a1e4b2006-06-03 18:02:15 +0000427 os2File *pFile = (os2File*)id;
428 assert( pFile!=0 );
429 if( pFile->locktype>=RESERVED_LOCK ){
pweilbacherd4c8a602008-02-14 00:00:50 +0000430 r = 1;
431 OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
drh60a1e4b2006-06-03 18:02:15 +0000432 }else{
433 FILELOCK LockArea,
434 UnlockArea;
pweilbacherd4c8a602008-02-14 00:00:50 +0000435 APIRET rc = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000436 memset(&LockArea, 0, sizeof(LockArea));
437 memset(&UnlockArea, 0, sizeof(UnlockArea));
438 LockArea.lOffset = RESERVED_BYTE;
439 LockArea.lRange = 1L;
440 UnlockArea.lOffset = 0L;
441 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000442 rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000443 OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
drh60a1e4b2006-06-03 18:02:15 +0000444 if( rc == NO_ERROR ){
pweilbacherd4c8a602008-02-14 00:00:50 +0000445 APIRET rcu = NO_ERROR; /* return code for unlocking */
drh60a1e4b2006-06-03 18:02:15 +0000446 LockArea.lOffset = 0L;
447 LockArea.lRange = 0L;
448 UnlockArea.lOffset = RESERVED_BYTE;
449 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000450 rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherd4c8a602008-02-14 00:00:50 +0000451 OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
drh60a1e4b2006-06-03 18:02:15 +0000452 }
pweilbacherd4c8a602008-02-14 00:00:50 +0000453 r = !(rc == NO_ERROR);
454 OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
drh60a1e4b2006-06-03 18:02:15 +0000455 }
drh9a8f1762008-06-12 12:38:10 +0000456 *pOut = r;
457 return SQLITE_OK;
drh60a1e4b2006-06-03 18:02:15 +0000458}
459
460/*
461** Lower the locking level on file descriptor id to locktype. locktype
462** must be either NO_LOCK or SHARED_LOCK.
463**
464** If the locking level of the file descriptor is already at or below
465** the requested locking level, this routine is a no-op.
466**
467** It is not possible for this routine to fail if the second argument
468** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
469** might return SQLITE_IOERR;
470*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000471static int os2Unlock( sqlite3_file *id, int locktype ){
drh60a1e4b2006-06-03 18:02:15 +0000472 int type;
drh60a1e4b2006-06-03 18:02:15 +0000473 os2File *pFile = (os2File*)id;
pweilbacherb36dc732007-10-21 22:47:03 +0000474 APIRET rc = SQLITE_OK;
475 APIRET res = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000476 FILELOCK LockArea,
477 UnlockArea;
478 memset(&LockArea, 0, sizeof(LockArea));
479 memset(&UnlockArea, 0, sizeof(UnlockArea));
480 assert( pFile!=0 );
481 assert( locktype<=SHARED_LOCK );
drh4f0c5872007-03-26 22:05:01 +0000482 OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000483 type = pFile->locktype;
484 if( type>=EXCLUSIVE_LOCK ){
485 LockArea.lOffset = 0L;
486 LockArea.lRange = 0L;
487 UnlockArea.lOffset = SHARED_FIRST;
488 UnlockArea.lRange = SHARED_SIZE;
pweilbacherf19dfc42008-05-12 00:32:08 +0000489 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000490 OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000491 if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
492 /* This should never happen. We should always be able to
493 ** reacquire the read lock */
pweilbacherb36dc732007-10-21 22:47:03 +0000494 OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
495 rc = SQLITE_IOERR_UNLOCK;
drh60a1e4b2006-06-03 18:02:15 +0000496 }
497 }
498 if( type>=RESERVED_LOCK ){
499 LockArea.lOffset = 0L;
500 LockArea.lRange = 0L;
501 UnlockArea.lOffset = RESERVED_BYTE;
502 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000503 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000504 OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000505 }
506 if( locktype==NO_LOCK && type>=SHARED_LOCK ){
pweilbacherb36dc732007-10-21 22:47:03 +0000507 res = unlockReadLock(pFile);
508 OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
drh60a1e4b2006-06-03 18:02:15 +0000509 }
510 if( type>=PENDING_LOCK ){
511 LockArea.lOffset = 0L;
512 LockArea.lRange = 0L;
513 UnlockArea.lOffset = PENDING_BYTE;
514 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000515 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000516 OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000517 }
518 pFile->locktype = locktype;
pweilbacherb36dc732007-10-21 22:47:03 +0000519 OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000520 return rc;
521}
522
523/*
pweilbacherb36dc732007-10-21 22:47:03 +0000524** Control and query of the open file handle.
drh60a1e4b2006-06-03 18:02:15 +0000525*/
pweilbacherb36dc732007-10-21 22:47:03 +0000526static int os2FileControl(sqlite3_file *id, int op, void *pArg){
527 switch( op ){
528 case SQLITE_FCNTL_LOCKSTATE: {
529 *(int*)pArg = ((os2File*)id)->locktype;
530 OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
531 return SQLITE_OK;
pweilbacher503028d2007-07-01 15:41:02 +0000532 }
drh60a1e4b2006-06-03 18:02:15 +0000533 }
pweilbacherb36dc732007-10-21 22:47:03 +0000534 return SQLITE_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000535}
536
537/*
danielk1977a3d4c882007-03-23 10:08:38 +0000538** Return the sector size in bytes of the underlying block device for
539** the specified file. This is almost always 512 bytes, but may be
540** larger for some devices.
541**
542** SQLite code assumes this function cannot fail. It also assumes that
543** if two files are created in the same file-system directory (i.e.
drh85b623f2007-12-13 21:54:09 +0000544** a database and its journal file) that the sector size will be the
danielk1977a3d4c882007-03-23 10:08:38 +0000545** same for both.
546*/
pweilbacherb36dc732007-10-21 22:47:03 +0000547static int os2SectorSize(sqlite3_file *id){
drh3ceeb752007-03-29 18:19:52 +0000548 return SQLITE_DEFAULT_SECTOR_SIZE;
danielk1977a3d4c882007-03-23 10:08:38 +0000549}
550
551/*
pweilbacherb36dc732007-10-21 22:47:03 +0000552** Return a vector of device characteristics.
drh60a1e4b2006-06-03 18:02:15 +0000553*/
pweilbacherb36dc732007-10-21 22:47:03 +0000554static int os2DeviceCharacteristics(sqlite3_file *id){
555 return 0;
556}
557
pweilbacher2a6962a2008-07-15 22:59:04 +0000558
559/*
560** Character set conversion objects used by conversion routines.
561*/
562static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
563static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */
564
565/*
566** Helper function to initialize the conversion objects from and to UTF-8.
567*/
568static void initUconvObjects( void ){
pweilbacher2a6962a2008-07-15 22:59:04 +0000569 if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS )
570 ucUtf8 = NULL;
571 if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS )
572 uclCp = NULL;
573}
574
575/*
576** Helper function to free the conversion objects from and to UTF-8.
577*/
578static void freeUconvObjects( void ){
pweilbacher2a6962a2008-07-15 22:59:04 +0000579 if ( ucUtf8 )
580 UniFreeUconvObject( ucUtf8 );
581 if ( uclCp )
582 UniFreeUconvObject( uclCp );
583 ucUtf8 = NULL;
584 uclCp = NULL;
585}
586
pweilbacherb36dc732007-10-21 22:47:03 +0000587/*
pweilbacherd190be82008-04-15 18:50:02 +0000588** Helper function to convert UTF-8 filenames to local OS/2 codepage.
589** The two-step process: first convert the incoming UTF-8 string
590** into UCS-2 and then from UCS-2 to the current codepage.
591** The returned char pointer has to be freed.
592*/
pweilbacher2a6962a2008-07-15 22:59:04 +0000593static char *convertUtf8PathToCp( const char *in ){
594 UniChar tempPath[CCHMAXPATH];
595 char *out = (char *)calloc( CCHMAXPATH, 1 );
pweilbacherd190be82008-04-15 18:50:02 +0000596
pweilbacher2a6962a2008-07-15 22:59:04 +0000597 if( !out )
598 return NULL;
599
600 if( !ucUtf8 || !uclCp )
601 initUconvObjects();
pweilbacherd190be82008-04-15 18:50:02 +0000602
603 /* determine string for the conversion of UTF-8 which is CP1208 */
pweilbacher2a6962a2008-07-15 22:59:04 +0000604 if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
605 return out; /* if conversion fails, return the empty string */
pweilbacherd190be82008-04-15 18:50:02 +0000606
607 /* conversion for current codepage which can be used for paths */
pweilbacher2a6962a2008-07-15 22:59:04 +0000608 UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH );
pweilbacherd190be82008-04-15 18:50:02 +0000609
610 return out;
611}
612
613/*
614** Helper function to convert filenames from local codepage to UTF-8.
615** The two-step process: first convert the incoming codepage-specific
616** string into UCS-2 and then from UCS-2 to the codepage of UTF-8.
617** The returned char pointer has to be freed.
pweilbacher2a6962a2008-07-15 22:59:04 +0000618**
619** This function is non-static to be able to use this in shell.c and
620** similar applications that take command line arguments.
pweilbacherd190be82008-04-15 18:50:02 +0000621*/
pweilbacher2a6962a2008-07-15 22:59:04 +0000622char *convertCpPathToUtf8( const char *in ){
623 UniChar tempPath[CCHMAXPATH];
624 char *out = (char *)calloc( CCHMAXPATH, 1 );
pweilbacherd190be82008-04-15 18:50:02 +0000625
pweilbacher2a6962a2008-07-15 22:59:04 +0000626 if( !out )
627 return NULL;
628
629 if( !ucUtf8 || !uclCp )
630 initUconvObjects();
pweilbacherd190be82008-04-15 18:50:02 +0000631
632 /* conversion for current codepage which can be used for paths */
pweilbacher2a6962a2008-07-15 22:59:04 +0000633 if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
634 return out; /* if conversion fails, return the empty string */
pweilbacherd190be82008-04-15 18:50:02 +0000635
636 /* determine string for the conversion of UTF-8 which is CP1208 */
pweilbacher2a6962a2008-07-15 22:59:04 +0000637 UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );
pweilbacherd190be82008-04-15 18:50:02 +0000638
639 return out;
640}
641
642/*
pweilbacherb36dc732007-10-21 22:47:03 +0000643** This vector defines all the methods that can operate on an
644** sqlite3_file for os2.
645*/
646static const sqlite3_io_methods os2IoMethod = {
647 1, /* iVersion */
drh60a1e4b2006-06-03 18:02:15 +0000648 os2Close,
drh60a1e4b2006-06-03 18:02:15 +0000649 os2Read,
650 os2Write,
drh60a1e4b2006-06-03 18:02:15 +0000651 os2Truncate,
652 os2Sync,
drh60a1e4b2006-06-03 18:02:15 +0000653 os2FileSize,
654 os2Lock,
655 os2Unlock,
drh60a1e4b2006-06-03 18:02:15 +0000656 os2CheckReservedLock,
pweilbacherb36dc732007-10-21 22:47:03 +0000657 os2FileControl,
danielk1977a3d4c882007-03-23 10:08:38 +0000658 os2SectorSize,
pweilbacherb36dc732007-10-21 22:47:03 +0000659 os2DeviceCharacteristics
drh60a1e4b2006-06-03 18:02:15 +0000660};
661
pweilbacherb36dc732007-10-21 22:47:03 +0000662/***************************************************************************
663** Here ends the I/O methods that form the sqlite3_io_methods object.
664**
665** The next block of code implements the VFS methods.
666****************************************************************************/
667
drh60a1e4b2006-06-03 18:02:15 +0000668/*
drh9a8f1762008-06-12 12:38:10 +0000669** Create a temporary file name in zBuf. zBuf must be big enough to
670** hold at pVfs->mxPathname characters.
671*/
672static int getTempname(int nBuf, char *zBuf ){
673 static const unsigned char zChars[] =
674 "abcdefghijklmnopqrstuvwxyz"
675 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
676 "0123456789";
677 int i, j;
678 char zTempPathBuf[3];
679 PSZ zTempPath = (PSZ)&zTempPathBuf;
pweilbacher96d9cf02008-07-08 22:34:06 +0000680 if( sqlite3_temp_directory ){
681 zTempPath = sqlite3_temp_directory;
682 }else{
683 if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){
684 if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){
685 if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){
pweilbacher2a6962a2008-07-15 22:59:04 +0000686 ULONG ulDriveNum = 0, ulDriveMap = 0;
687 DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
688 sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) );
pweilbacher96d9cf02008-07-08 22:34:06 +0000689 }
drh9a8f1762008-06-12 12:38:10 +0000690 }
691 }
692 }
pweilbacher96d9cf02008-07-08 22:34:06 +0000693 /* Strip off a trailing slashes or backslashes, otherwise we would get *
694 * multiple (back)slashes which causes DosOpen() to fail. *
695 * Trailing spaces are not allowed, either. */
drh9a8f1762008-06-12 12:38:10 +0000696 j = strlen(zTempPath);
pweilbacher96d9cf02008-07-08 22:34:06 +0000697 while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/'
698 || zTempPath[j-1] == ' ' ) ){
drh9a8f1762008-06-12 12:38:10 +0000699 j--;
700 }
701 zTempPath[j] = '\0';
pweilbacher96d9cf02008-07-08 22:34:06 +0000702 if( !sqlite3_temp_directory ){
703 char *zTempPathUTF = convertCpPathToUtf8( zTempPath );
704 sqlite3_snprintf( nBuf-30, zBuf,
705 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF );
706 free( zTempPathUTF );
707 }else{
708 sqlite3_snprintf( nBuf-30, zBuf,
709 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath );
710 }
drh9a8f1762008-06-12 12:38:10 +0000711 j = strlen( zBuf );
712 sqlite3_randomness( 20, &zBuf[j] );
713 for( i = 0; i < 20; i++, j++ ){
714 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
715 }
716 zBuf[j] = 0;
717 OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
718 return SQLITE_OK;
719}
720
721
722/*
pweilbacher6d2a4b02008-07-29 18:35:53 +0000723** Turn a relative pathname into a full pathname. Write the full
724** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname
725** bytes in size.
726*/
727static int os2FullPathname(
728 sqlite3_vfs *pVfs, /* Pointer to vfs object */
729 const char *zRelative, /* Possibly relative input path */
730 int nFull, /* Size of output buffer in bytes */
731 char *zFull /* Output buffer */
732){
733 char *zRelativeCp = convertUtf8PathToCp( zRelative );
734 char zFullCp[CCHMAXPATH] = "\0";
735 char *zFullUTF;
736 APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
737 CCHMAXPATH );
738 free( zRelativeCp );
739 zFullUTF = convertCpPathToUtf8( zFullCp );
740 sqlite3_snprintf( nFull, zFull, zFullUTF );
741 free( zFullUTF );
742 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
743}
744
745
746/*
pweilbacherb36dc732007-10-21 22:47:03 +0000747** Open a file.
drh60a1e4b2006-06-03 18:02:15 +0000748*/
pweilbacherb36dc732007-10-21 22:47:03 +0000749static int os2Open(
750 sqlite3_vfs *pVfs, /* Not used */
751 const char *zName, /* Name of the file */
752 sqlite3_file *id, /* Write the SQLite file handle here */
753 int flags, /* Open mode flags */
754 int *pOutFlags /* Status return flags */
755){
756 HFILE h;
pweilbacher7fc76d82008-08-22 13:47:56 +0000757 ULONG ulFileAttribute = FILE_NORMAL;
pweilbacherb36dc732007-10-21 22:47:03 +0000758 ULONG ulOpenFlags = 0;
759 ULONG ulOpenMode = 0;
760 os2File *pFile = (os2File*)id;
761 APIRET rc = NO_ERROR;
762 ULONG ulAction;
pweilbacher8407f0e2008-05-20 19:08:53 +0000763 char *zNameCp;
pweilbacher6a9773e2008-06-18 21:08:16 +0000764 char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */
drh9a8f1762008-06-12 12:38:10 +0000765
766 /* If the second argument to this function is NULL, generate a
767 ** temporary file name to use
768 */
769 if( !zName ){
pweilbacher6a9773e2008-06-18 21:08:16 +0000770 int rc = getTempname(CCHMAXPATH+1, zTmpname);
drh9a8f1762008-06-12 12:38:10 +0000771 if( rc!=SQLITE_OK ){
772 return rc;
773 }
774 zName = zTmpname;
775 }
776
pweilbacherb36dc732007-10-21 22:47:03 +0000777
pweilbacherd190be82008-04-15 18:50:02 +0000778 memset( pFile, 0, sizeof(*pFile) );
pweilbacherb36dc732007-10-21 22:47:03 +0000779
780 OSTRACE2( "OPEN want %d\n", flags );
781
pweilbacherb36dc732007-10-21 22:47:03 +0000782 if( flags & SQLITE_OPEN_READWRITE ){
783 ulOpenMode |= OPEN_ACCESS_READWRITE;
784 OSTRACE1( "OPEN read/write\n" );
drh60a1e4b2006-06-03 18:02:15 +0000785 }else{
pweilbacherb36dc732007-10-21 22:47:03 +0000786 ulOpenMode |= OPEN_ACCESS_READONLY;
787 OSTRACE1( "OPEN read only\n" );
drh60a1e4b2006-06-03 18:02:15 +0000788 }
pweilbacherb36dc732007-10-21 22:47:03 +0000789
pweilbacherb36dc732007-10-21 22:47:03 +0000790 if( flags & SQLITE_OPEN_CREATE ){
791 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
792 OSTRACE1( "OPEN open new/create\n" );
793 }else{
794 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
795 OSTRACE1( "OPEN open existing\n" );
796 }
797
pweilbacherb36dc732007-10-21 22:47:03 +0000798 if( flags & SQLITE_OPEN_MAIN_DB ){
799 ulOpenMode |= OPEN_SHARE_DENYNONE;
800 OSTRACE1( "OPEN share read/write\n" );
801 }else{
802 ulOpenMode |= OPEN_SHARE_DENYWRITE;
803 OSTRACE1( "OPEN share read only\n" );
804 }
805
pweilbacher7fc76d82008-08-22 13:47:56 +0000806 if( flags & SQLITE_OPEN_DELETEONCLOSE ){
pweilbacher0e6cf0a2008-05-06 22:15:26 +0000807 char pathUtf8[CCHMAXPATH];
pweilbacherd6a75f82008-07-29 18:49:28 +0000808#ifdef NDEBUG /* when debugging we want to make sure it is deleted */
809 ulFileAttribute = FILE_HIDDEN;
810#endif
pweilbacher6d2a4b02008-07-29 18:35:53 +0000811 os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
pweilbacher0e6cf0a2008-05-06 22:15:26 +0000812 pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
pweilbacherb36dc732007-10-21 22:47:03 +0000813 OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
814 }else{
pweilbacherb36dc732007-10-21 22:47:03 +0000815 pFile->pathToDel = NULL;
816 OSTRACE1( "OPEN normal file attribute\n" );
817 }
818
pweilbacher6034b1e2008-02-13 23:48:02 +0000819 /* always open in random access mode for possibly better speed */
820 ulOpenMode |= OPEN_FLAGS_RANDOM;
pweilbacherb36dc732007-10-21 22:47:03 +0000821 ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
pweilbacher5ff10202008-04-23 23:03:10 +0000822 ulOpenMode |= OPEN_FLAGS_NOINHERIT;
pweilbacherb36dc732007-10-21 22:47:03 +0000823
pweilbacher8407f0e2008-05-20 19:08:53 +0000824 zNameCp = convertUtf8PathToCp( zName );
pweilbacherd190be82008-04-15 18:50:02 +0000825 rc = DosOpen( (PSZ)zNameCp,
pweilbacherb36dc732007-10-21 22:47:03 +0000826 &h,
827 &ulAction,
828 0L,
829 ulFileAttribute,
830 ulOpenFlags,
831 ulOpenMode,
832 (PEAOP2)NULL );
pweilbacherd190be82008-04-15 18:50:02 +0000833 free( zNameCp );
pweilbacherb36dc732007-10-21 22:47:03 +0000834 if( rc != NO_ERROR ){
835 OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
836 rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
pweilbacher96d9cf02008-07-08 22:34:06 +0000837 if( pFile->pathToDel )
pweilbacher91ef8f42008-06-24 22:50:06 +0000838 free( pFile->pathToDel );
pweilbacherd2dadc92008-05-09 19:38:24 +0000839 pFile->pathToDel = NULL;
pweilbacherb36dc732007-10-21 22:47:03 +0000840 if( flags & SQLITE_OPEN_READWRITE ){
841 OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
pweilbacheraf3cc182008-07-29 18:38:47 +0000842 return os2Open( pVfs, zName, id,
pweilbacherb36dc732007-10-21 22:47:03 +0000843 ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
844 pOutFlags );
845 }else{
846 return SQLITE_CANTOPEN;
847 }
848 }
849
850 if( pOutFlags ){
851 *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
852 }
853
854 pFile->pMethod = &os2IoMethod;
855 pFile->h = h;
856 OpenCounter(+1);
857 OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
858 return SQLITE_OK;
drh60a1e4b2006-06-03 18:02:15 +0000859}
860
pweilbacherb36dc732007-10-21 22:47:03 +0000861/*
862** Delete the named file.
863*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000864static int os2Delete(
pweilbacherb36dc732007-10-21 22:47:03 +0000865 sqlite3_vfs *pVfs, /* Not used on os2 */
866 const char *zFilename, /* Name of file to delete */
867 int syncDir /* Not used on os2 */
868){
869 APIRET rc = NO_ERROR;
pweilbacherd190be82008-04-15 18:50:02 +0000870 char *zFilenameCp = convertUtf8PathToCp( zFilename );
pweilbacher91ef8f42008-06-24 22:50:06 +0000871 SimulateIOError( return SQLITE_IOERR_DELETE );
pweilbacherd190be82008-04-15 18:50:02 +0000872 rc = DosDelete( (PSZ)zFilenameCp );
873 free( zFilenameCp );
pweilbacherb36dc732007-10-21 22:47:03 +0000874 OSTRACE2( "DELETE \"%s\"\n", zFilename );
pweilbacherab88e172008-10-13 21:46:46 +0000875 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
pweilbacherb36dc732007-10-21 22:47:03 +0000876}
877
878/*
879** Check the existance and status of a file.
880*/
881static int os2Access(
882 sqlite3_vfs *pVfs, /* Not used on os2 */
883 const char *zFilename, /* Name of file to check */
drh9a8f1762008-06-12 12:38:10 +0000884 int flags, /* Type of test to make on this file */
885 int *pOut /* Write results here */
pweilbacherb36dc732007-10-21 22:47:03 +0000886){
887 FILESTATUS3 fsts3ConfigInfo;
888 APIRET rc = NO_ERROR;
pweilbacher91ef8f42008-06-24 22:50:06 +0000889 char *zFilenameCp = convertUtf8PathToCp( zFilename );
pweilbacherb36dc732007-10-21 22:47:03 +0000890
pweilbacherd190be82008-04-15 18:50:02 +0000891 memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) );
pweilbacherd190be82008-04-15 18:50:02 +0000892 rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
pweilbacherb36dc732007-10-21 22:47:03 +0000893 &fsts3ConfigInfo, sizeof(FILESTATUS3) );
pweilbacherd190be82008-04-15 18:50:02 +0000894 free( zFilenameCp );
pweilbacherb36dc732007-10-21 22:47:03 +0000895 OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
896 fsts3ConfigInfo.attrFile, flags, rc );
897 switch( flags ){
898 case SQLITE_ACCESS_READ:
899 case SQLITE_ACCESS_EXISTS:
900 rc = (rc == NO_ERROR);
901 OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc );
902 break;
903 case SQLITE_ACCESS_READWRITE:
pweilbacher91ef8f42008-06-24 22:50:06 +0000904 rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
pweilbacherb36dc732007-10-21 22:47:03 +0000905 OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc );
906 break;
907 default:
908 assert( !"Invalid flags argument" );
909 }
drh9a8f1762008-06-12 12:38:10 +0000910 *pOut = rc;
pweilbacherb36dc732007-10-21 22:47:03 +0000911 return SQLITE_OK;
912}
913
914
drh761df872006-12-21 01:29:22 +0000915#ifndef SQLITE_OMIT_LOAD_EXTENSION
916/*
917** Interfaces for opening a shared library, finding entry points
918** within the shared library, and closing the shared library.
919*/
pweilbacherb36dc732007-10-21 22:47:03 +0000920/*
921** Interfaces for opening a shared library, finding entry points
922** within the shared library, and closing the shared library.
923*/
924static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
pweilbacher5fecee12007-01-28 21:42:08 +0000925 UCHAR loadErr[256];
926 HMODULE hmod;
927 APIRET rc;
pweilbacherd190be82008-04-15 18:50:02 +0000928 char *zFilenameCp = convertUtf8PathToCp(zFilename);
929 rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod);
930 free(zFilenameCp);
pweilbacherb36dc732007-10-21 22:47:03 +0000931 return rc != NO_ERROR ? 0 : (void*)hmod;
drh761df872006-12-21 01:29:22 +0000932}
pweilbacherb36dc732007-10-21 22:47:03 +0000933/*
934** A no-op since the error code is returned on the DosLoadModule call.
935** os2Dlopen returns zero if DosLoadModule is not successful.
936*/
937static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
938/* no-op */
939}
pweilbacher7f6358b2008-07-08 19:46:24 +0000940static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
pweilbacher5fecee12007-01-28 21:42:08 +0000941 PFN pfn;
942 APIRET rc;
943 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
pweilbacherb36dc732007-10-21 22:47:03 +0000944 if( rc != NO_ERROR ){
pweilbacher5fecee12007-01-28 21:42:08 +0000945 /* if the symbol itself was not found, search again for the same
946 * symbol with an extra underscore, that might be needed depending
947 * on the calling convention */
948 char _zSymbol[256] = "_";
949 strncat(_zSymbol, zSymbol, 255);
950 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
951 }
pweilbacherb36dc732007-10-21 22:47:03 +0000952 return rc != NO_ERROR ? 0 : (void*)pfn;
drh761df872006-12-21 01:29:22 +0000953}
pweilbacher7f6358b2008-07-08 19:46:24 +0000954static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
pweilbacherb36dc732007-10-21 22:47:03 +0000955 DosFreeModule((HMODULE)pHandle);
drh761df872006-12-21 01:29:22 +0000956}
pweilbacherb36dc732007-10-21 22:47:03 +0000957#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
958 #define os2DlOpen 0
959 #define os2DlError 0
960 #define os2DlSym 0
961 #define os2DlClose 0
962#endif
drh761df872006-12-21 01:29:22 +0000963
964
drh60a1e4b2006-06-03 18:02:15 +0000965/*
pweilbacherb36dc732007-10-21 22:47:03 +0000966** Write up to nBuf bytes of randomness into zBuf.
drh60a1e4b2006-06-03 18:02:15 +0000967*/
pweilbacherb36dc732007-10-21 22:47:03 +0000968static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
pweilbacherc06b54f2008-11-22 19:50:53 +0000969 int sizeofULong = sizeof(ULONG);
pweilbacherb36dc732007-10-21 22:47:03 +0000970 int n = 0;
pweilbacherc06b54f2008-11-22 19:50:53 +0000971 if( (int)sizeof(DATETIME) <= nBuf - n ){
pweilbacherb36dc732007-10-21 22:47:03 +0000972 DATETIME x;
973 DosGetDateTime(&x);
974 memcpy(&zBuf[n], &x, sizeof(x));
975 n += sizeof(x);
976 }
977
978 if( sizeofULong <= nBuf - n ){
979 PPIB ppib;
980 DosGetInfoBlocks(NULL, &ppib);
981 memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong);
982 n += sizeofULong;
983 }
984
985 if( sizeofULong <= nBuf - n ){
986 PTIB ptib;
987 DosGetInfoBlocks(&ptib, NULL);
988 memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong);
989 n += sizeofULong;
990 }
991
992 /* if we still haven't filled the buffer yet the following will */
993 /* grab everything once instead of making several calls for a single item */
994 if( sizeofULong <= nBuf - n ){
995 ULONG ulSysInfo[QSV_MAX];
996 DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX);
997
998 memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong);
999 n += sizeofULong;
1000
1001 if( sizeofULong <= nBuf - n ){
1002 memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong);
1003 n += sizeofULong;
1004 }
1005 if( sizeofULong <= nBuf - n ){
1006 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong);
1007 n += sizeofULong;
1008 }
1009 if( sizeofULong <= nBuf - n ){
1010 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong);
1011 n += sizeofULong;
1012 }
1013 if( sizeofULong <= nBuf - n ){
1014 memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong);
1015 n += sizeofULong;
1016 }
1017 }
1018
1019 return n;
drh60a1e4b2006-06-03 18:02:15 +00001020}
1021
1022/*
1023** Sleep for a little while. Return the amount of time slept.
pweilbacherb36dc732007-10-21 22:47:03 +00001024** The argument is the number of microseconds we want to sleep.
1025** The return value is the number of microseconds of sleep actually
1026** requested from the underlying operating system, a number which
1027** might be greater than or equal to the argument, but not less
1028** than the argument.
drh60a1e4b2006-06-03 18:02:15 +00001029*/
pweilbacherb36dc732007-10-21 22:47:03 +00001030static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){
1031 DosSleep( (microsec/1000) );
1032 return microsec;
drh60a1e4b2006-06-03 18:02:15 +00001033}
1034
1035/*
1036** The following variable, if set to a non-zero value, becomes the result
1037** returned from sqlite3OsCurrentTime(). This is used for testing.
1038*/
1039#ifdef SQLITE_TEST
1040int sqlite3_current_time = 0;
1041#endif
1042
1043/*
1044** Find the current time (in Universal Coordinated Time). Write the
1045** current time and date as a Julian Day number into *prNow and
1046** return 0. Return 1 if the time and date cannot be found.
1047*/
pweilbacherb36dc732007-10-21 22:47:03 +00001048int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
drh60a1e4b2006-06-03 18:02:15 +00001049 double now;
pweilbacher71be8e62007-10-24 23:04:32 +00001050 SHORT minute; /* needs to be able to cope with negative timezone offset */
1051 USHORT second, hour,
drh60a1e4b2006-06-03 18:02:15 +00001052 day, month, year;
1053 DATETIME dt;
1054 DosGetDateTime( &dt );
1055 second = (USHORT)dt.seconds;
pweilbacher71be8e62007-10-24 23:04:32 +00001056 minute = (SHORT)dt.minutes + dt.timezone;
drh60a1e4b2006-06-03 18:02:15 +00001057 hour = (USHORT)dt.hours;
1058 day = (USHORT)dt.day;
1059 month = (USHORT)dt.month;
1060 year = (USHORT)dt.year;
1061
1062 /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
1063 http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
1064 /* Calculate the Julian days */
1065 now = day - 32076 +
1066 1461*(year + 4800 + (month - 14)/12)/4 +
1067 367*(month - 2 - (month - 14)/12*12)/12 -
1068 3*((year + 4900 + (month - 14)/12)/100)/4;
1069
1070 /* Add the fractional hours, mins and seconds */
1071 now += (hour + 12.0)/24.0;
1072 now += minute/1440.0;
1073 now += second/86400.0;
1074 *prNow = now;
1075#ifdef SQLITE_TEST
1076 if( sqlite3_current_time ){
1077 *prNow = sqlite3_current_time/86400.0 + 2440587.5;
1078 }
1079#endif
1080 return 0;
1081}
1082
pweilbacher6a9773e2008-06-18 21:08:16 +00001083static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
1084 return 0;
1085}
1086
drh60a1e4b2006-06-03 18:02:15 +00001087/*
danielk1977c0fa4c52008-06-25 17:19:00 +00001088** Initialize and deinitialize the operating system interface.
drh60a1e4b2006-06-03 18:02:15 +00001089*/
danielk1977c0fa4c52008-06-25 17:19:00 +00001090int sqlite3_os_init(void){
pweilbacherb36dc732007-10-21 22:47:03 +00001091 static sqlite3_vfs os2Vfs = {
1092 1, /* iVersion */
1093 sizeof(os2File), /* szOsFile */
1094 CCHMAXPATH, /* mxPathname */
1095 0, /* pNext */
1096 "os2", /* zName */
1097 0, /* pAppData */
drh60a1e4b2006-06-03 18:02:15 +00001098
pweilbacherb36dc732007-10-21 22:47:03 +00001099 os2Open, /* xOpen */
1100 os2Delete, /* xDelete */
1101 os2Access, /* xAccess */
pweilbacherb36dc732007-10-21 22:47:03 +00001102 os2FullPathname, /* xFullPathname */
1103 os2DlOpen, /* xDlOpen */
1104 os2DlError, /* xDlError */
1105 os2DlSym, /* xDlSym */
1106 os2DlClose, /* xDlClose */
1107 os2Randomness, /* xRandomness */
1108 os2Sleep, /* xSleep */
pweilbacher6a9773e2008-06-18 21:08:16 +00001109 os2CurrentTime, /* xCurrentTime */
drh9a8f1762008-06-12 12:38:10 +00001110 os2GetLastError /* xGetLastError */
pweilbacherb36dc732007-10-21 22:47:03 +00001111 };
danielk1977c0fa4c52008-06-25 17:19:00 +00001112 sqlite3_vfs_register(&os2Vfs, 1);
pweilbacher71b53ca2008-07-16 19:30:37 +00001113 initUconvObjects();
pweilbacher7f6358b2008-07-08 19:46:24 +00001114 return SQLITE_OK;
drh60a1e4b2006-06-03 18:02:15 +00001115}
pweilbacher7f6358b2008-07-08 19:46:24 +00001116int sqlite3_os_end(void){
pweilbacher2a6962a2008-07-15 22:59:04 +00001117 freeUconvObjects();
pweilbacher7f6358b2008-07-08 19:46:24 +00001118 return SQLITE_OK;
danielk1977c0fa4c52008-06-25 17:19:00 +00001119}
drh40257ff2008-06-13 18:24:27 +00001120
danielk197729bafea2008-06-26 10:41:19 +00001121#endif /* SQLITE_OS_OS2 */