blob: 8bcdb8c0b30e82d3c78f6931b2298a6eb7a0c8c1 [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**
pweilbacherd102d112008-11-26 20:03:21 +000015** $Id: os_os2.c,v 1.62 2008/11/26 20:03:21 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
pweilbacherd102d112008-11-26 20:03:21 +0000203 UNUSED_PARAMETER(pFile);
pweilbacher50128ae2008-11-18 23:03:39 +0000204 return SQLITE_OK;
205#else
pweilbacherb36dc732007-10-21 22:47:03 +0000206 return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
pweilbacher50128ae2008-11-18 23:03:39 +0000207#endif
drh60a1e4b2006-06-03 18:02:15 +0000208}
209
210/*
211** Determine the current size of a file in bytes
212*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000213static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){
pweilbacher04bd0c12006-06-24 12:38:59 +0000214 APIRET rc = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000215 FILESTATUS3 fsts3FileInfo;
216 memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo));
217 assert( id!=0 );
pweilbacherab88e172008-10-13 21:46:46 +0000218 SimulateIOError( return SQLITE_IOERR_FSTAT );
drh60a1e4b2006-06-03 18:02:15 +0000219 rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) );
220 if( rc == NO_ERROR ){
221 *pSize = fsts3FileInfo.cbFile;
222 return SQLITE_OK;
pweilbacherb36dc732007-10-21 22:47:03 +0000223 }else{
pweilbacherab88e172008-10-13 21:46:46 +0000224 return SQLITE_IOERR_FSTAT;
drh60a1e4b2006-06-03 18:02:15 +0000225 }
226}
227
228/*
229** Acquire a reader lock.
230*/
pweilbacherb36dc732007-10-21 22:47:03 +0000231static int getReadLock( os2File *pFile ){
drh60a1e4b2006-06-03 18:02:15 +0000232 FILELOCK LockArea,
233 UnlockArea;
pweilbacherb36dc732007-10-21 22:47:03 +0000234 APIRET res;
drh60a1e4b2006-06-03 18:02:15 +0000235 memset(&LockArea, 0, sizeof(LockArea));
236 memset(&UnlockArea, 0, sizeof(UnlockArea));
237 LockArea.lOffset = SHARED_FIRST;
238 LockArea.lRange = SHARED_SIZE;
239 UnlockArea.lOffset = 0L;
240 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000241 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
pweilbacherb36dc732007-10-21 22:47:03 +0000242 OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
243 return res;
drh60a1e4b2006-06-03 18:02:15 +0000244}
245
246/*
247** Undo a readlock
248*/
249static int unlockReadLock( os2File *id ){
250 FILELOCK LockArea,
251 UnlockArea;
pweilbacherb36dc732007-10-21 22:47:03 +0000252 APIRET res;
drh60a1e4b2006-06-03 18:02:15 +0000253 memset(&LockArea, 0, sizeof(LockArea));
254 memset(&UnlockArea, 0, sizeof(UnlockArea));
255 LockArea.lOffset = 0L;
256 LockArea.lRange = 0L;
257 UnlockArea.lOffset = SHARED_FIRST;
258 UnlockArea.lRange = SHARED_SIZE;
pweilbacherf19dfc42008-05-12 00:32:08 +0000259 res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
pweilbacherb36dc732007-10-21 22:47:03 +0000260 OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
261 return res;
drh60a1e4b2006-06-03 18:02:15 +0000262}
263
drh60a1e4b2006-06-03 18:02:15 +0000264/*
265** Lock the file with the lock specified by parameter locktype - one
266** of the following:
267**
268** (1) SHARED_LOCK
269** (2) RESERVED_LOCK
270** (3) PENDING_LOCK
271** (4) EXCLUSIVE_LOCK
272**
273** Sometimes when requesting one lock state, additional lock states
274** are inserted in between. The locking might fail on one of the later
275** transitions leaving the lock state different from what it started but
276** still short of its goal. The following chart shows the allowed
277** transitions and the inserted intermediate states:
278**
279** UNLOCKED -> SHARED
280** SHARED -> RESERVED
281** SHARED -> (PENDING) -> EXCLUSIVE
282** RESERVED -> (PENDING) -> EXCLUSIVE
283** PENDING -> EXCLUSIVE
284**
285** This routine will only increase a lock. The os2Unlock() routine
286** erases all locks at once and returns us immediately to locking level 0.
287** It is not possible to lower the locking level one step at a time. You
288** must go straight to locking level 0.
289*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000290static int os2Lock( sqlite3_file *id, int locktype ){
pweilbacherb36dc732007-10-21 22:47:03 +0000291 int rc = SQLITE_OK; /* Return code from subroutines */
pweilbacher04bd0c12006-06-24 12:38:59 +0000292 APIRET res = NO_ERROR; /* Result of an OS/2 lock call */
pweilbacherb36dc732007-10-21 22:47:03 +0000293 int newLocktype; /* Set pFile->locktype to this value before exiting */
drh60a1e4b2006-06-03 18:02:15 +0000294 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
295 FILELOCK LockArea,
296 UnlockArea;
297 os2File *pFile = (os2File*)id;
298 memset(&LockArea, 0, sizeof(LockArea));
299 memset(&UnlockArea, 0, sizeof(UnlockArea));
300 assert( pFile!=0 );
drh4f0c5872007-03-26 22:05:01 +0000301 OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000302
303 /* If there is already a lock of this type or more restrictive on the
pweilbacherb36dc732007-10-21 22:47:03 +0000304 ** os2File, do nothing. Don't use the end_lock: exit path, as
pweilbacherd190be82008-04-15 18:50:02 +0000305 ** sqlite3_mutex_enter() hasn't been called yet.
drh60a1e4b2006-06-03 18:02:15 +0000306 */
307 if( pFile->locktype>=locktype ){
pweilbacherb36dc732007-10-21 22:47:03 +0000308 OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
drh60a1e4b2006-06-03 18:02:15 +0000309 return SQLITE_OK;
310 }
311
312 /* Make sure the locking sequence is correct
313 */
314 assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
315 assert( locktype!=PENDING_LOCK );
316 assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
317
318 /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
319 ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
320 ** the PENDING_LOCK byte is temporary.
321 */
322 newLocktype = pFile->locktype;
323 if( pFile->locktype==NO_LOCK
pweilbacherb36dc732007-10-21 22:47:03 +0000324 || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
drh60a1e4b2006-06-03 18:02:15 +0000325 ){
drh60a1e4b2006-06-03 18:02:15 +0000326 LockArea.lOffset = PENDING_BYTE;
327 LockArea.lRange = 1L;
328 UnlockArea.lOffset = 0L;
329 UnlockArea.lRange = 0L;
330
pweilbacherf19dfc42008-05-12 00:32:08 +0000331 /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */
332 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
333 if( res == NO_ERROR ){
pweilbacherb36dc732007-10-21 22:47:03 +0000334 gotPendingLock = 1;
335 OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res );
336 }
drh60a1e4b2006-06-03 18:02:15 +0000337 }
338
339 /* Acquire a shared lock
340 */
pweilbacherb36dc732007-10-21 22:47:03 +0000341 if( locktype==SHARED_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000342 assert( pFile->locktype==NO_LOCK );
343 res = getReadLock(pFile);
344 if( res == NO_ERROR ){
345 newLocktype = SHARED_LOCK;
346 }
pweilbacherb36dc732007-10-21 22:47:03 +0000347 OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000348 }
349
350 /* Acquire a RESERVED lock
351 */
pweilbacherb36dc732007-10-21 22:47:03 +0000352 if( locktype==RESERVED_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000353 assert( pFile->locktype==SHARED_LOCK );
354 LockArea.lOffset = RESERVED_BYTE;
355 LockArea.lRange = 1L;
356 UnlockArea.lOffset = 0L;
357 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000358 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
drh60a1e4b2006-06-03 18:02:15 +0000359 if( res == NO_ERROR ){
360 newLocktype = RESERVED_LOCK;
361 }
pweilbacherb36dc732007-10-21 22:47:03 +0000362 OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000363 }
364
365 /* Acquire a PENDING lock
366 */
pweilbacherb36dc732007-10-21 22:47:03 +0000367 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000368 newLocktype = PENDING_LOCK;
369 gotPendingLock = 0;
pweilbacherb36dc732007-10-21 22:47:03 +0000370 OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
drh60a1e4b2006-06-03 18:02:15 +0000371 }
372
373 /* Acquire an EXCLUSIVE lock
374 */
pweilbacherb36dc732007-10-21 22:47:03 +0000375 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
drh60a1e4b2006-06-03 18:02:15 +0000376 assert( pFile->locktype>=SHARED_LOCK );
377 res = unlockReadLock(pFile);
drh4f0c5872007-03-26 22:05:01 +0000378 OSTRACE2( "unreadlock = %d\n", res );
drh60a1e4b2006-06-03 18:02:15 +0000379 LockArea.lOffset = SHARED_FIRST;
380 LockArea.lRange = SHARED_SIZE;
381 UnlockArea.lOffset = 0L;
382 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000383 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
drh60a1e4b2006-06-03 18:02:15 +0000384 if( res == NO_ERROR ){
385 newLocktype = EXCLUSIVE_LOCK;
386 }else{
pweilbacherb36dc732007-10-21 22:47:03 +0000387 OSTRACE2( "OS/2 error-code = %d\n", res );
388 getReadLock(pFile);
drh60a1e4b2006-06-03 18:02:15 +0000389 }
pweilbacherb36dc732007-10-21 22:47:03 +0000390 OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000391 }
392
393 /* If we are holding a PENDING lock that ought to be released, then
394 ** release it now.
395 */
396 if( gotPendingLock && locktype==SHARED_LOCK ){
pweilbacherb36dc732007-10-21 22:47:03 +0000397 int r;
drh60a1e4b2006-06-03 18:02:15 +0000398 LockArea.lOffset = 0L;
399 LockArea.lRange = 0L;
400 UnlockArea.lOffset = PENDING_BYTE;
401 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000402 r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000403 OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
drh60a1e4b2006-06-03 18:02:15 +0000404 }
405
406 /* Update the state of the lock has held in the file descriptor then
407 ** return the appropriate result code.
408 */
409 if( res == NO_ERROR ){
410 rc = SQLITE_OK;
411 }else{
drh4f0c5872007-03-26 22:05:01 +0000412 OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
pweilbacherb36dc732007-10-21 22:47:03 +0000413 locktype, newLocktype );
drh60a1e4b2006-06-03 18:02:15 +0000414 rc = SQLITE_BUSY;
415 }
416 pFile->locktype = newLocktype;
pweilbacherb36dc732007-10-21 22:47:03 +0000417 OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000418 return rc;
419}
420
421/*
422** This routine checks if there is a RESERVED lock held on the specified
423** file by this or any other process. If such a lock is held, return
424** non-zero, otherwise zero.
425*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000426static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
pweilbacherd4c8a602008-02-14 00:00:50 +0000427 int r = 0;
drh60a1e4b2006-06-03 18:02:15 +0000428 os2File *pFile = (os2File*)id;
429 assert( pFile!=0 );
430 if( pFile->locktype>=RESERVED_LOCK ){
pweilbacherd4c8a602008-02-14 00:00:50 +0000431 r = 1;
432 OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
drh60a1e4b2006-06-03 18:02:15 +0000433 }else{
434 FILELOCK LockArea,
435 UnlockArea;
pweilbacherd4c8a602008-02-14 00:00:50 +0000436 APIRET rc = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000437 memset(&LockArea, 0, sizeof(LockArea));
438 memset(&UnlockArea, 0, sizeof(UnlockArea));
439 LockArea.lOffset = RESERVED_BYTE;
440 LockArea.lRange = 1L;
441 UnlockArea.lOffset = 0L;
442 UnlockArea.lRange = 0L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000443 rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000444 OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
drh60a1e4b2006-06-03 18:02:15 +0000445 if( rc == NO_ERROR ){
pweilbacherd4c8a602008-02-14 00:00:50 +0000446 APIRET rcu = NO_ERROR; /* return code for unlocking */
drh60a1e4b2006-06-03 18:02:15 +0000447 LockArea.lOffset = 0L;
448 LockArea.lRange = 0L;
449 UnlockArea.lOffset = RESERVED_BYTE;
450 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000451 rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherd4c8a602008-02-14 00:00:50 +0000452 OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
drh60a1e4b2006-06-03 18:02:15 +0000453 }
pweilbacherd4c8a602008-02-14 00:00:50 +0000454 r = !(rc == NO_ERROR);
455 OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
drh60a1e4b2006-06-03 18:02:15 +0000456 }
drh9a8f1762008-06-12 12:38:10 +0000457 *pOut = r;
458 return SQLITE_OK;
drh60a1e4b2006-06-03 18:02:15 +0000459}
460
461/*
462** Lower the locking level on file descriptor id to locktype. locktype
463** must be either NO_LOCK or SHARED_LOCK.
464**
465** If the locking level of the file descriptor is already at or below
466** the requested locking level, this routine is a no-op.
467**
468** It is not possible for this routine to fail if the second argument
469** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
470** might return SQLITE_IOERR;
471*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000472static int os2Unlock( sqlite3_file *id, int locktype ){
drh60a1e4b2006-06-03 18:02:15 +0000473 int type;
drh60a1e4b2006-06-03 18:02:15 +0000474 os2File *pFile = (os2File*)id;
pweilbacherb36dc732007-10-21 22:47:03 +0000475 APIRET rc = SQLITE_OK;
476 APIRET res = NO_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000477 FILELOCK LockArea,
478 UnlockArea;
479 memset(&LockArea, 0, sizeof(LockArea));
480 memset(&UnlockArea, 0, sizeof(UnlockArea));
481 assert( pFile!=0 );
482 assert( locktype<=SHARED_LOCK );
drh4f0c5872007-03-26 22:05:01 +0000483 OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000484 type = pFile->locktype;
485 if( type>=EXCLUSIVE_LOCK ){
486 LockArea.lOffset = 0L;
487 LockArea.lRange = 0L;
488 UnlockArea.lOffset = SHARED_FIRST;
489 UnlockArea.lRange = SHARED_SIZE;
pweilbacherf19dfc42008-05-12 00:32:08 +0000490 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000491 OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000492 if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
493 /* This should never happen. We should always be able to
494 ** reacquire the read lock */
pweilbacherb36dc732007-10-21 22:47:03 +0000495 OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
496 rc = SQLITE_IOERR_UNLOCK;
drh60a1e4b2006-06-03 18:02:15 +0000497 }
498 }
499 if( type>=RESERVED_LOCK ){
500 LockArea.lOffset = 0L;
501 LockArea.lRange = 0L;
502 UnlockArea.lOffset = RESERVED_BYTE;
503 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000504 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000505 OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000506 }
507 if( locktype==NO_LOCK && type>=SHARED_LOCK ){
pweilbacherb36dc732007-10-21 22:47:03 +0000508 res = unlockReadLock(pFile);
509 OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
drh60a1e4b2006-06-03 18:02:15 +0000510 }
511 if( type>=PENDING_LOCK ){
512 LockArea.lOffset = 0L;
513 LockArea.lRange = 0L;
514 UnlockArea.lOffset = PENDING_BYTE;
515 UnlockArea.lRange = 1L;
pweilbacherf19dfc42008-05-12 00:32:08 +0000516 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
pweilbacherb36dc732007-10-21 22:47:03 +0000517 OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
drh60a1e4b2006-06-03 18:02:15 +0000518 }
519 pFile->locktype = locktype;
pweilbacherb36dc732007-10-21 22:47:03 +0000520 OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
drh60a1e4b2006-06-03 18:02:15 +0000521 return rc;
522}
523
524/*
pweilbacherb36dc732007-10-21 22:47:03 +0000525** Control and query of the open file handle.
drh60a1e4b2006-06-03 18:02:15 +0000526*/
pweilbacherb36dc732007-10-21 22:47:03 +0000527static int os2FileControl(sqlite3_file *id, int op, void *pArg){
528 switch( op ){
529 case SQLITE_FCNTL_LOCKSTATE: {
530 *(int*)pArg = ((os2File*)id)->locktype;
531 OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
532 return SQLITE_OK;
pweilbacher503028d2007-07-01 15:41:02 +0000533 }
drh60a1e4b2006-06-03 18:02:15 +0000534 }
pweilbacherb36dc732007-10-21 22:47:03 +0000535 return SQLITE_ERROR;
drh60a1e4b2006-06-03 18:02:15 +0000536}
537
538/*
danielk1977a3d4c882007-03-23 10:08:38 +0000539** Return the sector size in bytes of the underlying block device for
540** the specified file. This is almost always 512 bytes, but may be
541** larger for some devices.
542**
543** SQLite code assumes this function cannot fail. It also assumes that
544** if two files are created in the same file-system directory (i.e.
drh85b623f2007-12-13 21:54:09 +0000545** a database and its journal file) that the sector size will be the
danielk1977a3d4c882007-03-23 10:08:38 +0000546** same for both.
547*/
pweilbacherb36dc732007-10-21 22:47:03 +0000548static int os2SectorSize(sqlite3_file *id){
drh3ceeb752007-03-29 18:19:52 +0000549 return SQLITE_DEFAULT_SECTOR_SIZE;
danielk1977a3d4c882007-03-23 10:08:38 +0000550}
551
552/*
pweilbacherb36dc732007-10-21 22:47:03 +0000553** Return a vector of device characteristics.
drh60a1e4b2006-06-03 18:02:15 +0000554*/
pweilbacherb36dc732007-10-21 22:47:03 +0000555static int os2DeviceCharacteristics(sqlite3_file *id){
556 return 0;
557}
558
pweilbacher2a6962a2008-07-15 22:59:04 +0000559
560/*
561** Character set conversion objects used by conversion routines.
562*/
563static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
564static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */
565
566/*
567** Helper function to initialize the conversion objects from and to UTF-8.
568*/
569static void initUconvObjects( void ){
pweilbacher2a6962a2008-07-15 22:59:04 +0000570 if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS )
571 ucUtf8 = NULL;
572 if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS )
573 uclCp = NULL;
574}
575
576/*
577** Helper function to free the conversion objects from and to UTF-8.
578*/
579static void freeUconvObjects( void ){
pweilbacher2a6962a2008-07-15 22:59:04 +0000580 if ( ucUtf8 )
581 UniFreeUconvObject( ucUtf8 );
582 if ( uclCp )
583 UniFreeUconvObject( uclCp );
584 ucUtf8 = NULL;
585 uclCp = NULL;
586}
587
pweilbacherb36dc732007-10-21 22:47:03 +0000588/*
pweilbacherd190be82008-04-15 18:50:02 +0000589** Helper function to convert UTF-8 filenames to local OS/2 codepage.
590** The two-step process: first convert the incoming UTF-8 string
591** into UCS-2 and then from UCS-2 to the current codepage.
592** The returned char pointer has to be freed.
593*/
pweilbacher2a6962a2008-07-15 22:59:04 +0000594static char *convertUtf8PathToCp( const char *in ){
595 UniChar tempPath[CCHMAXPATH];
596 char *out = (char *)calloc( CCHMAXPATH, 1 );
pweilbacherd190be82008-04-15 18:50:02 +0000597
pweilbacher2a6962a2008-07-15 22:59:04 +0000598 if( !out )
599 return NULL;
600
601 if( !ucUtf8 || !uclCp )
602 initUconvObjects();
pweilbacherd190be82008-04-15 18:50:02 +0000603
604 /* determine string for the conversion of UTF-8 which is CP1208 */
pweilbacher2a6962a2008-07-15 22:59:04 +0000605 if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
606 return out; /* if conversion fails, return the empty string */
pweilbacherd190be82008-04-15 18:50:02 +0000607
608 /* conversion for current codepage which can be used for paths */
pweilbacher2a6962a2008-07-15 22:59:04 +0000609 UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH );
pweilbacherd190be82008-04-15 18:50:02 +0000610
611 return out;
612}
613
614/*
615** Helper function to convert filenames from local codepage to UTF-8.
616** The two-step process: first convert the incoming codepage-specific
617** string into UCS-2 and then from UCS-2 to the codepage of UTF-8.
618** The returned char pointer has to be freed.
pweilbacher2a6962a2008-07-15 22:59:04 +0000619**
620** This function is non-static to be able to use this in shell.c and
621** similar applications that take command line arguments.
pweilbacherd190be82008-04-15 18:50:02 +0000622*/
pweilbacher2a6962a2008-07-15 22:59:04 +0000623char *convertCpPathToUtf8( const char *in ){
624 UniChar tempPath[CCHMAXPATH];
625 char *out = (char *)calloc( CCHMAXPATH, 1 );
pweilbacherd190be82008-04-15 18:50:02 +0000626
pweilbacher2a6962a2008-07-15 22:59:04 +0000627 if( !out )
628 return NULL;
629
630 if( !ucUtf8 || !uclCp )
631 initUconvObjects();
pweilbacherd190be82008-04-15 18:50:02 +0000632
633 /* conversion for current codepage which can be used for paths */
pweilbacher2a6962a2008-07-15 22:59:04 +0000634 if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
635 return out; /* if conversion fails, return the empty string */
pweilbacherd190be82008-04-15 18:50:02 +0000636
637 /* determine string for the conversion of UTF-8 which is CP1208 */
pweilbacher2a6962a2008-07-15 22:59:04 +0000638 UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );
pweilbacherd190be82008-04-15 18:50:02 +0000639
640 return out;
641}
642
643/*
pweilbacherb36dc732007-10-21 22:47:03 +0000644** This vector defines all the methods that can operate on an
645** sqlite3_file for os2.
646*/
647static const sqlite3_io_methods os2IoMethod = {
648 1, /* iVersion */
drh60a1e4b2006-06-03 18:02:15 +0000649 os2Close,
drh60a1e4b2006-06-03 18:02:15 +0000650 os2Read,
651 os2Write,
drh60a1e4b2006-06-03 18:02:15 +0000652 os2Truncate,
653 os2Sync,
drh60a1e4b2006-06-03 18:02:15 +0000654 os2FileSize,
655 os2Lock,
656 os2Unlock,
drh60a1e4b2006-06-03 18:02:15 +0000657 os2CheckReservedLock,
pweilbacherb36dc732007-10-21 22:47:03 +0000658 os2FileControl,
danielk1977a3d4c882007-03-23 10:08:38 +0000659 os2SectorSize,
pweilbacherb36dc732007-10-21 22:47:03 +0000660 os2DeviceCharacteristics
drh60a1e4b2006-06-03 18:02:15 +0000661};
662
pweilbacherb36dc732007-10-21 22:47:03 +0000663/***************************************************************************
664** Here ends the I/O methods that form the sqlite3_io_methods object.
665**
666** The next block of code implements the VFS methods.
667****************************************************************************/
668
drh60a1e4b2006-06-03 18:02:15 +0000669/*
drh9a8f1762008-06-12 12:38:10 +0000670** Create a temporary file name in zBuf. zBuf must be big enough to
671** hold at pVfs->mxPathname characters.
672*/
673static int getTempname(int nBuf, char *zBuf ){
674 static const unsigned char zChars[] =
675 "abcdefghijklmnopqrstuvwxyz"
676 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
677 "0123456789";
678 int i, j;
679 char zTempPathBuf[3];
680 PSZ zTempPath = (PSZ)&zTempPathBuf;
pweilbacher96d9cf02008-07-08 22:34:06 +0000681 if( sqlite3_temp_directory ){
682 zTempPath = sqlite3_temp_directory;
683 }else{
684 if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){
685 if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){
686 if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){
pweilbacher2a6962a2008-07-15 22:59:04 +0000687 ULONG ulDriveNum = 0, ulDriveMap = 0;
688 DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
689 sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) );
pweilbacher96d9cf02008-07-08 22:34:06 +0000690 }
drh9a8f1762008-06-12 12:38:10 +0000691 }
692 }
693 }
pweilbacher96d9cf02008-07-08 22:34:06 +0000694 /* Strip off a trailing slashes or backslashes, otherwise we would get *
695 * multiple (back)slashes which causes DosOpen() to fail. *
696 * Trailing spaces are not allowed, either. */
drh9a8f1762008-06-12 12:38:10 +0000697 j = strlen(zTempPath);
pweilbacher96d9cf02008-07-08 22:34:06 +0000698 while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/'
699 || zTempPath[j-1] == ' ' ) ){
drh9a8f1762008-06-12 12:38:10 +0000700 j--;
701 }
702 zTempPath[j] = '\0';
pweilbacher96d9cf02008-07-08 22:34:06 +0000703 if( !sqlite3_temp_directory ){
704 char *zTempPathUTF = convertCpPathToUtf8( zTempPath );
705 sqlite3_snprintf( nBuf-30, zBuf,
706 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF );
707 free( zTempPathUTF );
708 }else{
709 sqlite3_snprintf( nBuf-30, zBuf,
710 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath );
711 }
drh9a8f1762008-06-12 12:38:10 +0000712 j = strlen( zBuf );
713 sqlite3_randomness( 20, &zBuf[j] );
714 for( i = 0; i < 20; i++, j++ ){
715 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
716 }
717 zBuf[j] = 0;
718 OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
719 return SQLITE_OK;
720}
721
722
723/*
pweilbacher6d2a4b02008-07-29 18:35:53 +0000724** Turn a relative pathname into a full pathname. Write the full
725** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname
726** bytes in size.
727*/
728static int os2FullPathname(
729 sqlite3_vfs *pVfs, /* Pointer to vfs object */
730 const char *zRelative, /* Possibly relative input path */
731 int nFull, /* Size of output buffer in bytes */
732 char *zFull /* Output buffer */
733){
734 char *zRelativeCp = convertUtf8PathToCp( zRelative );
735 char zFullCp[CCHMAXPATH] = "\0";
736 char *zFullUTF;
737 APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
738 CCHMAXPATH );
739 free( zRelativeCp );
740 zFullUTF = convertCpPathToUtf8( zFullCp );
741 sqlite3_snprintf( nFull, zFull, zFullUTF );
742 free( zFullUTF );
743 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
744}
745
746
747/*
pweilbacherb36dc732007-10-21 22:47:03 +0000748** Open a file.
drh60a1e4b2006-06-03 18:02:15 +0000749*/
pweilbacherb36dc732007-10-21 22:47:03 +0000750static int os2Open(
751 sqlite3_vfs *pVfs, /* Not used */
752 const char *zName, /* Name of the file */
753 sqlite3_file *id, /* Write the SQLite file handle here */
754 int flags, /* Open mode flags */
755 int *pOutFlags /* Status return flags */
756){
757 HFILE h;
pweilbacher7fc76d82008-08-22 13:47:56 +0000758 ULONG ulFileAttribute = FILE_NORMAL;
pweilbacherb36dc732007-10-21 22:47:03 +0000759 ULONG ulOpenFlags = 0;
760 ULONG ulOpenMode = 0;
761 os2File *pFile = (os2File*)id;
762 APIRET rc = NO_ERROR;
763 ULONG ulAction;
pweilbacher8407f0e2008-05-20 19:08:53 +0000764 char *zNameCp;
pweilbacher6a9773e2008-06-18 21:08:16 +0000765 char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */
drh9a8f1762008-06-12 12:38:10 +0000766
767 /* If the second argument to this function is NULL, generate a
768 ** temporary file name to use
769 */
770 if( !zName ){
pweilbacher6a9773e2008-06-18 21:08:16 +0000771 int rc = getTempname(CCHMAXPATH+1, zTmpname);
drh9a8f1762008-06-12 12:38:10 +0000772 if( rc!=SQLITE_OK ){
773 return rc;
774 }
775 zName = zTmpname;
776 }
777
pweilbacherb36dc732007-10-21 22:47:03 +0000778
pweilbacherd190be82008-04-15 18:50:02 +0000779 memset( pFile, 0, sizeof(*pFile) );
pweilbacherb36dc732007-10-21 22:47:03 +0000780
781 OSTRACE2( "OPEN want %d\n", flags );
782
pweilbacherb36dc732007-10-21 22:47:03 +0000783 if( flags & SQLITE_OPEN_READWRITE ){
784 ulOpenMode |= OPEN_ACCESS_READWRITE;
785 OSTRACE1( "OPEN read/write\n" );
drh60a1e4b2006-06-03 18:02:15 +0000786 }else{
pweilbacherb36dc732007-10-21 22:47:03 +0000787 ulOpenMode |= OPEN_ACCESS_READONLY;
788 OSTRACE1( "OPEN read only\n" );
drh60a1e4b2006-06-03 18:02:15 +0000789 }
pweilbacherb36dc732007-10-21 22:47:03 +0000790
pweilbacherb36dc732007-10-21 22:47:03 +0000791 if( flags & SQLITE_OPEN_CREATE ){
792 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
793 OSTRACE1( "OPEN open new/create\n" );
794 }else{
795 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
796 OSTRACE1( "OPEN open existing\n" );
797 }
798
pweilbacherb36dc732007-10-21 22:47:03 +0000799 if( flags & SQLITE_OPEN_MAIN_DB ){
800 ulOpenMode |= OPEN_SHARE_DENYNONE;
801 OSTRACE1( "OPEN share read/write\n" );
802 }else{
803 ulOpenMode |= OPEN_SHARE_DENYWRITE;
804 OSTRACE1( "OPEN share read only\n" );
805 }
806
pweilbacher7fc76d82008-08-22 13:47:56 +0000807 if( flags & SQLITE_OPEN_DELETEONCLOSE ){
pweilbacher0e6cf0a2008-05-06 22:15:26 +0000808 char pathUtf8[CCHMAXPATH];
pweilbacherd6a75f82008-07-29 18:49:28 +0000809#ifdef NDEBUG /* when debugging we want to make sure it is deleted */
810 ulFileAttribute = FILE_HIDDEN;
811#endif
pweilbacher6d2a4b02008-07-29 18:35:53 +0000812 os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
pweilbacher0e6cf0a2008-05-06 22:15:26 +0000813 pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
pweilbacherb36dc732007-10-21 22:47:03 +0000814 OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
815 }else{
pweilbacherb36dc732007-10-21 22:47:03 +0000816 pFile->pathToDel = NULL;
817 OSTRACE1( "OPEN normal file attribute\n" );
818 }
819
pweilbacher6034b1e2008-02-13 23:48:02 +0000820 /* always open in random access mode for possibly better speed */
821 ulOpenMode |= OPEN_FLAGS_RANDOM;
pweilbacherb36dc732007-10-21 22:47:03 +0000822 ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
pweilbacher5ff10202008-04-23 23:03:10 +0000823 ulOpenMode |= OPEN_FLAGS_NOINHERIT;
pweilbacherb36dc732007-10-21 22:47:03 +0000824
pweilbacher8407f0e2008-05-20 19:08:53 +0000825 zNameCp = convertUtf8PathToCp( zName );
pweilbacherd190be82008-04-15 18:50:02 +0000826 rc = DosOpen( (PSZ)zNameCp,
pweilbacherb36dc732007-10-21 22:47:03 +0000827 &h,
828 &ulAction,
829 0L,
830 ulFileAttribute,
831 ulOpenFlags,
832 ulOpenMode,
833 (PEAOP2)NULL );
pweilbacherd190be82008-04-15 18:50:02 +0000834 free( zNameCp );
pweilbacherb36dc732007-10-21 22:47:03 +0000835 if( rc != NO_ERROR ){
836 OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
837 rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
pweilbacher96d9cf02008-07-08 22:34:06 +0000838 if( pFile->pathToDel )
pweilbacher91ef8f42008-06-24 22:50:06 +0000839 free( pFile->pathToDel );
pweilbacherd2dadc92008-05-09 19:38:24 +0000840 pFile->pathToDel = NULL;
pweilbacherb36dc732007-10-21 22:47:03 +0000841 if( flags & SQLITE_OPEN_READWRITE ){
842 OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
pweilbacheraf3cc182008-07-29 18:38:47 +0000843 return os2Open( pVfs, zName, id,
pweilbacherb36dc732007-10-21 22:47:03 +0000844 ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
845 pOutFlags );
846 }else{
847 return SQLITE_CANTOPEN;
848 }
849 }
850
851 if( pOutFlags ){
852 *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
853 }
854
855 pFile->pMethod = &os2IoMethod;
856 pFile->h = h;
857 OpenCounter(+1);
858 OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
859 return SQLITE_OK;
drh60a1e4b2006-06-03 18:02:15 +0000860}
861
pweilbacherb36dc732007-10-21 22:47:03 +0000862/*
863** Delete the named file.
864*/
pweilbacher7f6358b2008-07-08 19:46:24 +0000865static int os2Delete(
pweilbacherb36dc732007-10-21 22:47:03 +0000866 sqlite3_vfs *pVfs, /* Not used on os2 */
867 const char *zFilename, /* Name of file to delete */
868 int syncDir /* Not used on os2 */
869){
870 APIRET rc = NO_ERROR;
pweilbacherd190be82008-04-15 18:50:02 +0000871 char *zFilenameCp = convertUtf8PathToCp( zFilename );
pweilbacher91ef8f42008-06-24 22:50:06 +0000872 SimulateIOError( return SQLITE_IOERR_DELETE );
pweilbacherd190be82008-04-15 18:50:02 +0000873 rc = DosDelete( (PSZ)zFilenameCp );
874 free( zFilenameCp );
pweilbacherb36dc732007-10-21 22:47:03 +0000875 OSTRACE2( "DELETE \"%s\"\n", zFilename );
pweilbacherab88e172008-10-13 21:46:46 +0000876 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
pweilbacherb36dc732007-10-21 22:47:03 +0000877}
878
879/*
880** Check the existance and status of a file.
881*/
882static int os2Access(
883 sqlite3_vfs *pVfs, /* Not used on os2 */
884 const char *zFilename, /* Name of file to check */
drh9a8f1762008-06-12 12:38:10 +0000885 int flags, /* Type of test to make on this file */
886 int *pOut /* Write results here */
pweilbacherb36dc732007-10-21 22:47:03 +0000887){
888 FILESTATUS3 fsts3ConfigInfo;
889 APIRET rc = NO_ERROR;
pweilbacher91ef8f42008-06-24 22:50:06 +0000890 char *zFilenameCp = convertUtf8PathToCp( zFilename );
pweilbacherb36dc732007-10-21 22:47:03 +0000891
pweilbacherd190be82008-04-15 18:50:02 +0000892 memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) );
pweilbacherd190be82008-04-15 18:50:02 +0000893 rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
pweilbacherb36dc732007-10-21 22:47:03 +0000894 &fsts3ConfigInfo, sizeof(FILESTATUS3) );
pweilbacherd190be82008-04-15 18:50:02 +0000895 free( zFilenameCp );
pweilbacherb36dc732007-10-21 22:47:03 +0000896 OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
897 fsts3ConfigInfo.attrFile, flags, rc );
898 switch( flags ){
899 case SQLITE_ACCESS_READ:
900 case SQLITE_ACCESS_EXISTS:
901 rc = (rc == NO_ERROR);
902 OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc );
903 break;
904 case SQLITE_ACCESS_READWRITE:
pweilbacher91ef8f42008-06-24 22:50:06 +0000905 rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
pweilbacherb36dc732007-10-21 22:47:03 +0000906 OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc );
907 break;
908 default:
909 assert( !"Invalid flags argument" );
910 }
drh9a8f1762008-06-12 12:38:10 +0000911 *pOut = rc;
pweilbacherb36dc732007-10-21 22:47:03 +0000912 return SQLITE_OK;
913}
914
915
drh761df872006-12-21 01:29:22 +0000916#ifndef SQLITE_OMIT_LOAD_EXTENSION
917/*
918** Interfaces for opening a shared library, finding entry points
919** within the shared library, and closing the shared library.
920*/
pweilbacherb36dc732007-10-21 22:47:03 +0000921/*
922** Interfaces for opening a shared library, finding entry points
923** within the shared library, and closing the shared library.
924*/
925static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
pweilbacher5fecee12007-01-28 21:42:08 +0000926 UCHAR loadErr[256];
927 HMODULE hmod;
928 APIRET rc;
pweilbacherd190be82008-04-15 18:50:02 +0000929 char *zFilenameCp = convertUtf8PathToCp(zFilename);
930 rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod);
931 free(zFilenameCp);
pweilbacherb36dc732007-10-21 22:47:03 +0000932 return rc != NO_ERROR ? 0 : (void*)hmod;
drh761df872006-12-21 01:29:22 +0000933}
pweilbacherb36dc732007-10-21 22:47:03 +0000934/*
935** A no-op since the error code is returned on the DosLoadModule call.
936** os2Dlopen returns zero if DosLoadModule is not successful.
937*/
938static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
939/* no-op */
940}
pweilbacher7f6358b2008-07-08 19:46:24 +0000941static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
pweilbacher5fecee12007-01-28 21:42:08 +0000942 PFN pfn;
943 APIRET rc;
944 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
pweilbacherb36dc732007-10-21 22:47:03 +0000945 if( rc != NO_ERROR ){
pweilbacher5fecee12007-01-28 21:42:08 +0000946 /* if the symbol itself was not found, search again for the same
947 * symbol with an extra underscore, that might be needed depending
948 * on the calling convention */
949 char _zSymbol[256] = "_";
950 strncat(_zSymbol, zSymbol, 255);
951 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
952 }
pweilbacherb36dc732007-10-21 22:47:03 +0000953 return rc != NO_ERROR ? 0 : (void*)pfn;
drh761df872006-12-21 01:29:22 +0000954}
pweilbacher7f6358b2008-07-08 19:46:24 +0000955static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
pweilbacherb36dc732007-10-21 22:47:03 +0000956 DosFreeModule((HMODULE)pHandle);
drh761df872006-12-21 01:29:22 +0000957}
pweilbacherb36dc732007-10-21 22:47:03 +0000958#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
959 #define os2DlOpen 0
960 #define os2DlError 0
961 #define os2DlSym 0
962 #define os2DlClose 0
963#endif
drh761df872006-12-21 01:29:22 +0000964
965
drh60a1e4b2006-06-03 18:02:15 +0000966/*
pweilbacherb36dc732007-10-21 22:47:03 +0000967** Write up to nBuf bytes of randomness into zBuf.
drh60a1e4b2006-06-03 18:02:15 +0000968*/
pweilbacherb36dc732007-10-21 22:47:03 +0000969static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
pweilbacherb36dc732007-10-21 22:47:03 +0000970 int n = 0;
pweilbacherefdabe92008-11-26 19:56:48 +0000971#if defined(SQLITE_TEST)
972 n = nBuf;
973 memset(zBuf, 0, nBuf);
974#else
975 int sizeofULong = sizeof(ULONG);
pweilbacherc06b54f2008-11-22 19:50:53 +0000976 if( (int)sizeof(DATETIME) <= nBuf - n ){
pweilbacherb36dc732007-10-21 22:47:03 +0000977 DATETIME x;
978 DosGetDateTime(&x);
979 memcpy(&zBuf[n], &x, sizeof(x));
980 n += sizeof(x);
981 }
982
983 if( sizeofULong <= nBuf - n ){
984 PPIB ppib;
985 DosGetInfoBlocks(NULL, &ppib);
986 memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong);
987 n += sizeofULong;
988 }
989
990 if( sizeofULong <= nBuf - n ){
991 PTIB ptib;
992 DosGetInfoBlocks(&ptib, NULL);
993 memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong);
994 n += sizeofULong;
995 }
996
997 /* if we still haven't filled the buffer yet the following will */
998 /* grab everything once instead of making several calls for a single item */
999 if( sizeofULong <= nBuf - n ){
1000 ULONG ulSysInfo[QSV_MAX];
1001 DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX);
1002
1003 memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong);
1004 n += sizeofULong;
1005
1006 if( sizeofULong <= nBuf - n ){
1007 memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong);
1008 n += sizeofULong;
1009 }
1010 if( sizeofULong <= nBuf - n ){
1011 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong);
1012 n += sizeofULong;
1013 }
1014 if( sizeofULong <= nBuf - n ){
1015 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong);
1016 n += sizeofULong;
1017 }
1018 if( sizeofULong <= nBuf - n ){
1019 memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong);
1020 n += sizeofULong;
1021 }
1022 }
pweilbacherefdabe92008-11-26 19:56:48 +00001023#endif
pweilbacherb36dc732007-10-21 22:47:03 +00001024
1025 return n;
drh60a1e4b2006-06-03 18:02:15 +00001026}
1027
1028/*
1029** Sleep for a little while. Return the amount of time slept.
pweilbacherb36dc732007-10-21 22:47:03 +00001030** The argument is the number of microseconds we want to sleep.
1031** The return value is the number of microseconds of sleep actually
1032** requested from the underlying operating system, a number which
1033** might be greater than or equal to the argument, but not less
1034** than the argument.
drh60a1e4b2006-06-03 18:02:15 +00001035*/
pweilbacherb36dc732007-10-21 22:47:03 +00001036static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){
1037 DosSleep( (microsec/1000) );
1038 return microsec;
drh60a1e4b2006-06-03 18:02:15 +00001039}
1040
1041/*
1042** The following variable, if set to a non-zero value, becomes the result
1043** returned from sqlite3OsCurrentTime(). This is used for testing.
1044*/
1045#ifdef SQLITE_TEST
1046int sqlite3_current_time = 0;
1047#endif
1048
1049/*
1050** Find the current time (in Universal Coordinated Time). Write the
1051** current time and date as a Julian Day number into *prNow and
1052** return 0. Return 1 if the time and date cannot be found.
1053*/
pweilbacherb36dc732007-10-21 22:47:03 +00001054int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
drh60a1e4b2006-06-03 18:02:15 +00001055 double now;
pweilbacher71be8e62007-10-24 23:04:32 +00001056 SHORT minute; /* needs to be able to cope with negative timezone offset */
1057 USHORT second, hour,
drh60a1e4b2006-06-03 18:02:15 +00001058 day, month, year;
1059 DATETIME dt;
1060 DosGetDateTime( &dt );
1061 second = (USHORT)dt.seconds;
pweilbacher71be8e62007-10-24 23:04:32 +00001062 minute = (SHORT)dt.minutes + dt.timezone;
drh60a1e4b2006-06-03 18:02:15 +00001063 hour = (USHORT)dt.hours;
1064 day = (USHORT)dt.day;
1065 month = (USHORT)dt.month;
1066 year = (USHORT)dt.year;
1067
1068 /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
1069 http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
1070 /* Calculate the Julian days */
1071 now = day - 32076 +
1072 1461*(year + 4800 + (month - 14)/12)/4 +
1073 367*(month - 2 - (month - 14)/12*12)/12 -
1074 3*((year + 4900 + (month - 14)/12)/100)/4;
1075
1076 /* Add the fractional hours, mins and seconds */
1077 now += (hour + 12.0)/24.0;
1078 now += minute/1440.0;
1079 now += second/86400.0;
1080 *prNow = now;
1081#ifdef SQLITE_TEST
1082 if( sqlite3_current_time ){
1083 *prNow = sqlite3_current_time/86400.0 + 2440587.5;
1084 }
1085#endif
1086 return 0;
1087}
1088
pweilbacher6a9773e2008-06-18 21:08:16 +00001089static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
1090 return 0;
1091}
1092
drh60a1e4b2006-06-03 18:02:15 +00001093/*
danielk1977c0fa4c52008-06-25 17:19:00 +00001094** Initialize and deinitialize the operating system interface.
drh60a1e4b2006-06-03 18:02:15 +00001095*/
danielk1977c0fa4c52008-06-25 17:19:00 +00001096int sqlite3_os_init(void){
pweilbacherb36dc732007-10-21 22:47:03 +00001097 static sqlite3_vfs os2Vfs = {
1098 1, /* iVersion */
1099 sizeof(os2File), /* szOsFile */
1100 CCHMAXPATH, /* mxPathname */
1101 0, /* pNext */
1102 "os2", /* zName */
1103 0, /* pAppData */
drh60a1e4b2006-06-03 18:02:15 +00001104
pweilbacherb36dc732007-10-21 22:47:03 +00001105 os2Open, /* xOpen */
1106 os2Delete, /* xDelete */
1107 os2Access, /* xAccess */
pweilbacherb36dc732007-10-21 22:47:03 +00001108 os2FullPathname, /* xFullPathname */
1109 os2DlOpen, /* xDlOpen */
1110 os2DlError, /* xDlError */
1111 os2DlSym, /* xDlSym */
1112 os2DlClose, /* xDlClose */
1113 os2Randomness, /* xRandomness */
1114 os2Sleep, /* xSleep */
pweilbacher6a9773e2008-06-18 21:08:16 +00001115 os2CurrentTime, /* xCurrentTime */
drh9a8f1762008-06-12 12:38:10 +00001116 os2GetLastError /* xGetLastError */
pweilbacherb36dc732007-10-21 22:47:03 +00001117 };
danielk1977c0fa4c52008-06-25 17:19:00 +00001118 sqlite3_vfs_register(&os2Vfs, 1);
pweilbacher71b53ca2008-07-16 19:30:37 +00001119 initUconvObjects();
pweilbacher7f6358b2008-07-08 19:46:24 +00001120 return SQLITE_OK;
drh60a1e4b2006-06-03 18:02:15 +00001121}
pweilbacher7f6358b2008-07-08 19:46:24 +00001122int sqlite3_os_end(void){
pweilbacher2a6962a2008-07-15 22:59:04 +00001123 freeUconvObjects();
pweilbacher7f6358b2008-07-08 19:46:24 +00001124 return SQLITE_OK;
danielk1977c0fa4c52008-06-25 17:19:00 +00001125}
drh40257ff2008-06-13 18:24:27 +00001126
danielk197729bafea2008-06-26 10:41:19 +00001127#endif /* SQLITE_OS_OS2 */