|
1 /* |
|
2 ** 2006 Feb 14 |
|
3 ** |
|
4 ** The author disclaims copyright to this source code. In place of |
|
5 ** a legal notice, here is a blessing: |
|
6 ** |
|
7 ** May you do good and not evil. |
|
8 ** May you find forgiveness for yourself and forgive others. |
|
9 ** May you share freely, never taking more than you give. |
|
10 ** |
|
11 ****************************************************************************** |
|
12 ** |
|
13 ** This file contains code that is specific to OS/2. |
|
14 ** |
|
15 ** $Id: os_os2.c,v 1.57 2008/10/13 21:46:47 pweilbacher Exp $ |
|
16 */ |
|
17 |
|
18 #include "sqliteInt.h" |
|
19 |
|
20 #if SQLITE_OS_OS2 |
|
21 |
|
22 /* |
|
23 ** 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 /* |
|
49 ** Macros used to determine whether or not to use threads. |
|
50 */ |
|
51 #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE |
|
52 # 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 /* |
|
61 ** The os2File structure is subclass of sqlite3_file specific for the OS/2 |
|
62 ** protability layer. |
|
63 */ |
|
64 typedef struct os2File os2File; |
|
65 struct os2File { |
|
66 const sqlite3_io_methods *pMethod; /* Always the first entry */ |
|
67 HFILE h; /* Handle for accessing the file */ |
|
68 char* pathToDel; /* Name of file to delete on close, NULL if not */ |
|
69 unsigned char locktype; /* Type of lock currently held on this file */ |
|
70 }; |
|
71 |
|
72 #define LOCK_TIMEOUT 10L /* the default locking timeout */ |
|
73 |
|
74 /***************************************************************************** |
|
75 ** The next group of routines implement the I/O methods specified |
|
76 ** by the sqlite3_io_methods object. |
|
77 ******************************************************************************/ |
|
78 |
|
79 /* |
|
80 ** Close a file. |
|
81 */ |
|
82 static int os2Close( sqlite3_file *id ){ |
|
83 APIRET rc = NO_ERROR; |
|
84 os2File *pFile; |
|
85 if( id && (pFile = (os2File*)id) != 0 ){ |
|
86 OSTRACE2( "CLOSE %d\n", pFile->h ); |
|
87 rc = DosClose( pFile->h ); |
|
88 pFile->locktype = NO_LOCK; |
|
89 if( pFile->pathToDel != NULL ){ |
|
90 rc = DosForceDelete( (PSZ)pFile->pathToDel ); |
|
91 free( pFile->pathToDel ); |
|
92 pFile->pathToDel = NULL; |
|
93 } |
|
94 id = 0; |
|
95 OpenCounter( -1 ); |
|
96 } |
|
97 |
|
98 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
99 } |
|
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 */ |
|
106 static int os2Read( |
|
107 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; |
|
113 ULONG got; |
|
114 os2File *pFile = (os2File*)id; |
|
115 assert( id!=0 ); |
|
116 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 ){ |
|
122 return SQLITE_IOERR_READ; |
|
123 } |
|
124 if( got == (ULONG)amt ) |
|
125 return SQLITE_OK; |
|
126 else { |
|
127 memset(&((char*)pBuf)[got], 0, amt-got); |
|
128 return SQLITE_IOERR_SHORT_READ; |
|
129 } |
|
130 } |
|
131 |
|
132 /* |
|
133 ** Write data from a buffer into a file. Return SQLITE_OK on success |
|
134 ** or some other error code on failure. |
|
135 */ |
|
136 static int os2Write( |
|
137 sqlite3_file *id, /* File to write into */ |
|
138 const void *pBuf, /* The bytes to be written */ |
|
139 int amt, /* Number of bytes to write */ |
|
140 sqlite3_int64 offset /* Offset into the file to begin writing at */ |
|
141 ){ |
|
142 ULONG fileLocation = 0L; |
|
143 APIRET rc = NO_ERROR; |
|
144 ULONG wrote; |
|
145 os2File *pFile = (os2File*)id; |
|
146 assert( id!=0 ); |
|
147 SimulateIOError( return SQLITE_IOERR_WRITE ); |
|
148 SimulateDiskfullError( return SQLITE_FULL ); |
|
149 OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ); |
|
150 if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){ |
|
151 return SQLITE_IOERR; |
|
152 } |
|
153 assert( amt>0 ); |
|
154 while( amt > 0 && |
|
155 ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR && |
|
156 wrote > 0 |
|
157 ){ |
|
158 amt -= wrote; |
|
159 pBuf = &((char*)pBuf)[wrote]; |
|
160 } |
|
161 |
|
162 return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; |
|
163 } |
|
164 |
|
165 /* |
|
166 ** Truncate an open file to a specified size |
|
167 */ |
|
168 static int os2Truncate( sqlite3_file *id, i64 nByte ){ |
|
169 APIRET rc = NO_ERROR; |
|
170 os2File *pFile = (os2File*)id; |
|
171 OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte ); |
|
172 SimulateIOError( return SQLITE_IOERR_TRUNCATE ); |
|
173 rc = DosSetFileSize( pFile->h, nByte ); |
|
174 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; |
|
175 } |
|
176 |
|
177 #ifdef SQLITE_TEST |
|
178 /* |
|
179 ** Count the number of fullsyncs and normal syncs. This is used to test |
|
180 ** that syncs and fullsyncs are occuring at the right times. |
|
181 */ |
|
182 int sqlite3_sync_count = 0; |
|
183 int sqlite3_fullsync_count = 0; |
|
184 #endif |
|
185 |
|
186 /* |
|
187 ** Make sure all writes to a particular file are committed to disk. |
|
188 */ |
|
189 static int os2Sync( sqlite3_file *id, int flags ){ |
|
190 os2File *pFile = (os2File*)id; |
|
191 OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ); |
|
192 #ifdef SQLITE_TEST |
|
193 if( flags & SQLITE_SYNC_FULL){ |
|
194 sqlite3_fullsync_count++; |
|
195 } |
|
196 sqlite3_sync_count++; |
|
197 #endif |
|
198 return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
199 } |
|
200 |
|
201 /* |
|
202 ** Determine the current size of a file in bytes |
|
203 */ |
|
204 static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){ |
|
205 APIRET rc = NO_ERROR; |
|
206 FILESTATUS3 fsts3FileInfo; |
|
207 memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); |
|
208 assert( id!=0 ); |
|
209 SimulateIOError( return SQLITE_IOERR_FSTAT ); |
|
210 rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); |
|
211 if( rc == NO_ERROR ){ |
|
212 *pSize = fsts3FileInfo.cbFile; |
|
213 return SQLITE_OK; |
|
214 }else{ |
|
215 return SQLITE_IOERR_FSTAT; |
|
216 } |
|
217 } |
|
218 |
|
219 /* |
|
220 ** Acquire a reader lock. |
|
221 */ |
|
222 static int getReadLock( os2File *pFile ){ |
|
223 FILELOCK LockArea, |
|
224 UnlockArea; |
|
225 APIRET res; |
|
226 memset(&LockArea, 0, sizeof(LockArea)); |
|
227 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
228 LockArea.lOffset = SHARED_FIRST; |
|
229 LockArea.lRange = SHARED_SIZE; |
|
230 UnlockArea.lOffset = 0L; |
|
231 UnlockArea.lRange = 0L; |
|
232 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); |
|
233 OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res ); |
|
234 return res; |
|
235 } |
|
236 |
|
237 /* |
|
238 ** Undo a readlock |
|
239 */ |
|
240 static int unlockReadLock( os2File *id ){ |
|
241 FILELOCK LockArea, |
|
242 UnlockArea; |
|
243 APIRET res; |
|
244 memset(&LockArea, 0, sizeof(LockArea)); |
|
245 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
246 LockArea.lOffset = 0L; |
|
247 LockArea.lRange = 0L; |
|
248 UnlockArea.lOffset = SHARED_FIRST; |
|
249 UnlockArea.lRange = SHARED_SIZE; |
|
250 res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L ); |
|
251 OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ); |
|
252 return res; |
|
253 } |
|
254 |
|
255 /* |
|
256 ** Lock the file with the lock specified by parameter locktype - one |
|
257 ** of the following: |
|
258 ** |
|
259 ** (1) SHARED_LOCK |
|
260 ** (2) RESERVED_LOCK |
|
261 ** (3) PENDING_LOCK |
|
262 ** (4) EXCLUSIVE_LOCK |
|
263 ** |
|
264 ** Sometimes when requesting one lock state, additional lock states |
|
265 ** are inserted in between. The locking might fail on one of the later |
|
266 ** transitions leaving the lock state different from what it started but |
|
267 ** still short of its goal. The following chart shows the allowed |
|
268 ** transitions and the inserted intermediate states: |
|
269 ** |
|
270 ** UNLOCKED -> SHARED |
|
271 ** SHARED -> RESERVED |
|
272 ** SHARED -> (PENDING) -> EXCLUSIVE |
|
273 ** RESERVED -> (PENDING) -> EXCLUSIVE |
|
274 ** PENDING -> EXCLUSIVE |
|
275 ** |
|
276 ** This routine will only increase a lock. The os2Unlock() routine |
|
277 ** erases all locks at once and returns us immediately to locking level 0. |
|
278 ** It is not possible to lower the locking level one step at a time. You |
|
279 ** must go straight to locking level 0. |
|
280 */ |
|
281 static int os2Lock( sqlite3_file *id, int locktype ){ |
|
282 int rc = SQLITE_OK; /* Return code from subroutines */ |
|
283 APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ |
|
284 int newLocktype; /* Set pFile->locktype to this value before exiting */ |
|
285 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ |
|
286 FILELOCK LockArea, |
|
287 UnlockArea; |
|
288 os2File *pFile = (os2File*)id; |
|
289 memset(&LockArea, 0, sizeof(LockArea)); |
|
290 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
291 assert( pFile!=0 ); |
|
292 OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); |
|
293 |
|
294 /* If there is already a lock of this type or more restrictive on the |
|
295 ** os2File, do nothing. Don't use the end_lock: exit path, as |
|
296 ** sqlite3_mutex_enter() hasn't been called yet. |
|
297 */ |
|
298 if( pFile->locktype>=locktype ){ |
|
299 OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype ); |
|
300 return SQLITE_OK; |
|
301 } |
|
302 |
|
303 /* Make sure the locking sequence is correct |
|
304 */ |
|
305 assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); |
|
306 assert( locktype!=PENDING_LOCK ); |
|
307 assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); |
|
308 |
|
309 /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or |
|
310 ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of |
|
311 ** the PENDING_LOCK byte is temporary. |
|
312 */ |
|
313 newLocktype = pFile->locktype; |
|
314 if( pFile->locktype==NO_LOCK |
|
315 || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) |
|
316 ){ |
|
317 LockArea.lOffset = PENDING_BYTE; |
|
318 LockArea.lRange = 1L; |
|
319 UnlockArea.lOffset = 0L; |
|
320 UnlockArea.lRange = 0L; |
|
321 |
|
322 /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */ |
|
323 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L ); |
|
324 if( res == NO_ERROR ){ |
|
325 gotPendingLock = 1; |
|
326 OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ); |
|
327 } |
|
328 } |
|
329 |
|
330 /* Acquire a shared lock |
|
331 */ |
|
332 if( locktype==SHARED_LOCK && res == NO_ERROR ){ |
|
333 assert( pFile->locktype==NO_LOCK ); |
|
334 res = getReadLock(pFile); |
|
335 if( res == NO_ERROR ){ |
|
336 newLocktype = SHARED_LOCK; |
|
337 } |
|
338 OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ); |
|
339 } |
|
340 |
|
341 /* Acquire a RESERVED lock |
|
342 */ |
|
343 if( locktype==RESERVED_LOCK && res == NO_ERROR ){ |
|
344 assert( pFile->locktype==SHARED_LOCK ); |
|
345 LockArea.lOffset = RESERVED_BYTE; |
|
346 LockArea.lRange = 1L; |
|
347 UnlockArea.lOffset = 0L; |
|
348 UnlockArea.lRange = 0L; |
|
349 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
350 if( res == NO_ERROR ){ |
|
351 newLocktype = RESERVED_LOCK; |
|
352 } |
|
353 OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ); |
|
354 } |
|
355 |
|
356 /* Acquire a PENDING lock |
|
357 */ |
|
358 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ |
|
359 newLocktype = PENDING_LOCK; |
|
360 gotPendingLock = 0; |
|
361 OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h ); |
|
362 } |
|
363 |
|
364 /* Acquire an EXCLUSIVE lock |
|
365 */ |
|
366 if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){ |
|
367 assert( pFile->locktype>=SHARED_LOCK ); |
|
368 res = unlockReadLock(pFile); |
|
369 OSTRACE2( "unreadlock = %d\n", res ); |
|
370 LockArea.lOffset = SHARED_FIRST; |
|
371 LockArea.lRange = SHARED_SIZE; |
|
372 UnlockArea.lOffset = 0L; |
|
373 UnlockArea.lRange = 0L; |
|
374 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
375 if( res == NO_ERROR ){ |
|
376 newLocktype = EXCLUSIVE_LOCK; |
|
377 }else{ |
|
378 OSTRACE2( "OS/2 error-code = %d\n", res ); |
|
379 getReadLock(pFile); |
|
380 } |
|
381 OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ); |
|
382 } |
|
383 |
|
384 /* If we are holding a PENDING lock that ought to be released, then |
|
385 ** release it now. |
|
386 */ |
|
387 if( gotPendingLock && locktype==SHARED_LOCK ){ |
|
388 int r; |
|
389 LockArea.lOffset = 0L; |
|
390 LockArea.lRange = 0L; |
|
391 UnlockArea.lOffset = PENDING_BYTE; |
|
392 UnlockArea.lRange = 1L; |
|
393 r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
394 OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ); |
|
395 } |
|
396 |
|
397 /* Update the state of the lock has held in the file descriptor then |
|
398 ** return the appropriate result code. |
|
399 */ |
|
400 if( res == NO_ERROR ){ |
|
401 rc = SQLITE_OK; |
|
402 }else{ |
|
403 OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, |
|
404 locktype, newLocktype ); |
|
405 rc = SQLITE_BUSY; |
|
406 } |
|
407 pFile->locktype = newLocktype; |
|
408 OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype ); |
|
409 return rc; |
|
410 } |
|
411 |
|
412 /* |
|
413 ** This routine checks if there is a RESERVED lock held on the specified |
|
414 ** file by this or any other process. If such a lock is held, return |
|
415 ** non-zero, otherwise zero. |
|
416 */ |
|
417 static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){ |
|
418 int r = 0; |
|
419 os2File *pFile = (os2File*)id; |
|
420 assert( pFile!=0 ); |
|
421 if( pFile->locktype>=RESERVED_LOCK ){ |
|
422 r = 1; |
|
423 OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ); |
|
424 }else{ |
|
425 FILELOCK LockArea, |
|
426 UnlockArea; |
|
427 APIRET rc = NO_ERROR; |
|
428 memset(&LockArea, 0, sizeof(LockArea)); |
|
429 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
430 LockArea.lOffset = RESERVED_BYTE; |
|
431 LockArea.lRange = 1L; |
|
432 UnlockArea.lOffset = 0L; |
|
433 UnlockArea.lRange = 0L; |
|
434 rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
435 OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ); |
|
436 if( rc == NO_ERROR ){ |
|
437 APIRET rcu = NO_ERROR; /* return code for unlocking */ |
|
438 LockArea.lOffset = 0L; |
|
439 LockArea.lRange = 0L; |
|
440 UnlockArea.lOffset = RESERVED_BYTE; |
|
441 UnlockArea.lRange = 1L; |
|
442 rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
443 OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ); |
|
444 } |
|
445 r = !(rc == NO_ERROR); |
|
446 OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ); |
|
447 } |
|
448 *pOut = r; |
|
449 return SQLITE_OK; |
|
450 } |
|
451 |
|
452 /* |
|
453 ** Lower the locking level on file descriptor id to locktype. locktype |
|
454 ** must be either NO_LOCK or SHARED_LOCK. |
|
455 ** |
|
456 ** If the locking level of the file descriptor is already at or below |
|
457 ** the requested locking level, this routine is a no-op. |
|
458 ** |
|
459 ** It is not possible for this routine to fail if the second argument |
|
460 ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine |
|
461 ** might return SQLITE_IOERR; |
|
462 */ |
|
463 static int os2Unlock( sqlite3_file *id, int locktype ){ |
|
464 int type; |
|
465 os2File *pFile = (os2File*)id; |
|
466 APIRET rc = SQLITE_OK; |
|
467 APIRET res = NO_ERROR; |
|
468 FILELOCK LockArea, |
|
469 UnlockArea; |
|
470 memset(&LockArea, 0, sizeof(LockArea)); |
|
471 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
472 assert( pFile!=0 ); |
|
473 assert( locktype<=SHARED_LOCK ); |
|
474 OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ); |
|
475 type = pFile->locktype; |
|
476 if( type>=EXCLUSIVE_LOCK ){ |
|
477 LockArea.lOffset = 0L; |
|
478 LockArea.lRange = 0L; |
|
479 UnlockArea.lOffset = SHARED_FIRST; |
|
480 UnlockArea.lRange = SHARED_SIZE; |
|
481 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
482 OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ); |
|
483 if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ |
|
484 /* This should never happen. We should always be able to |
|
485 ** reacquire the read lock */ |
|
486 OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ); |
|
487 rc = SQLITE_IOERR_UNLOCK; |
|
488 } |
|
489 } |
|
490 if( type>=RESERVED_LOCK ){ |
|
491 LockArea.lOffset = 0L; |
|
492 LockArea.lRange = 0L; |
|
493 UnlockArea.lOffset = RESERVED_BYTE; |
|
494 UnlockArea.lRange = 1L; |
|
495 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
496 OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res ); |
|
497 } |
|
498 if( locktype==NO_LOCK && type>=SHARED_LOCK ){ |
|
499 res = unlockReadLock(pFile); |
|
500 OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res ); |
|
501 } |
|
502 if( type>=PENDING_LOCK ){ |
|
503 LockArea.lOffset = 0L; |
|
504 LockArea.lRange = 0L; |
|
505 UnlockArea.lOffset = PENDING_BYTE; |
|
506 UnlockArea.lRange = 1L; |
|
507 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L ); |
|
508 OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res ); |
|
509 } |
|
510 pFile->locktype = locktype; |
|
511 OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ); |
|
512 return rc; |
|
513 } |
|
514 |
|
515 /* |
|
516 ** Control and query of the open file handle. |
|
517 */ |
|
518 static int os2FileControl(sqlite3_file *id, int op, void *pArg){ |
|
519 switch( op ){ |
|
520 case SQLITE_FCNTL_LOCKSTATE: { |
|
521 *(int*)pArg = ((os2File*)id)->locktype; |
|
522 OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); |
|
523 return SQLITE_OK; |
|
524 } |
|
525 } |
|
526 return SQLITE_ERROR; |
|
527 } |
|
528 |
|
529 /* |
|
530 ** Return the sector size in bytes of the underlying block device for |
|
531 ** the specified file. This is almost always 512 bytes, but may be |
|
532 ** larger for some devices. |
|
533 ** |
|
534 ** SQLite code assumes this function cannot fail. It also assumes that |
|
535 ** if two files are created in the same file-system directory (i.e. |
|
536 ** a database and its journal file) that the sector size will be the |
|
537 ** same for both. |
|
538 */ |
|
539 static int os2SectorSize(sqlite3_file *id){ |
|
540 return SQLITE_DEFAULT_SECTOR_SIZE; |
|
541 } |
|
542 |
|
543 /* |
|
544 ** Return a vector of device characteristics. |
|
545 */ |
|
546 static int os2DeviceCharacteristics(sqlite3_file *id){ |
|
547 return 0; |
|
548 } |
|
549 |
|
550 |
|
551 /* |
|
552 ** Character set conversion objects used by conversion routines. |
|
553 */ |
|
554 static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */ |
|
555 static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */ |
|
556 |
|
557 /* |
|
558 ** Helper function to initialize the conversion objects from and to UTF-8. |
|
559 */ |
|
560 static void initUconvObjects( void ){ |
|
561 if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS ) |
|
562 ucUtf8 = NULL; |
|
563 if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS ) |
|
564 uclCp = NULL; |
|
565 } |
|
566 |
|
567 /* |
|
568 ** Helper function to free the conversion objects from and to UTF-8. |
|
569 */ |
|
570 static void freeUconvObjects( void ){ |
|
571 if ( ucUtf8 ) |
|
572 UniFreeUconvObject( ucUtf8 ); |
|
573 if ( uclCp ) |
|
574 UniFreeUconvObject( uclCp ); |
|
575 ucUtf8 = NULL; |
|
576 uclCp = NULL; |
|
577 } |
|
578 |
|
579 /* |
|
580 ** Helper function to convert UTF-8 filenames to local OS/2 codepage. |
|
581 ** The two-step process: first convert the incoming UTF-8 string |
|
582 ** into UCS-2 and then from UCS-2 to the current codepage. |
|
583 ** The returned char pointer has to be freed. |
|
584 */ |
|
585 static char *convertUtf8PathToCp( const char *in ){ |
|
586 UniChar tempPath[CCHMAXPATH]; |
|
587 char *out = (char *)calloc( CCHMAXPATH, 1 ); |
|
588 |
|
589 if( !out ) |
|
590 return NULL; |
|
591 |
|
592 if( !ucUtf8 || !uclCp ) |
|
593 initUconvObjects(); |
|
594 |
|
595 /* determine string for the conversion of UTF-8 which is CP1208 */ |
|
596 if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS ) |
|
597 return out; /* if conversion fails, return the empty string */ |
|
598 |
|
599 /* conversion for current codepage which can be used for paths */ |
|
600 UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH ); |
|
601 |
|
602 return out; |
|
603 } |
|
604 |
|
605 /* |
|
606 ** Helper function to convert filenames from local codepage to UTF-8. |
|
607 ** The two-step process: first convert the incoming codepage-specific |
|
608 ** string into UCS-2 and then from UCS-2 to the codepage of UTF-8. |
|
609 ** The returned char pointer has to be freed. |
|
610 ** |
|
611 ** This function is non-static to be able to use this in shell.c and |
|
612 ** similar applications that take command line arguments. |
|
613 */ |
|
614 char *convertCpPathToUtf8( const char *in ){ |
|
615 UniChar tempPath[CCHMAXPATH]; |
|
616 char *out = (char *)calloc( CCHMAXPATH, 1 ); |
|
617 |
|
618 if( !out ) |
|
619 return NULL; |
|
620 |
|
621 if( !ucUtf8 || !uclCp ) |
|
622 initUconvObjects(); |
|
623 |
|
624 /* conversion for current codepage which can be used for paths */ |
|
625 if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS ) |
|
626 return out; /* if conversion fails, return the empty string */ |
|
627 |
|
628 /* determine string for the conversion of UTF-8 which is CP1208 */ |
|
629 UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); |
|
630 |
|
631 return out; |
|
632 } |
|
633 |
|
634 /* |
|
635 ** This vector defines all the methods that can operate on an |
|
636 ** sqlite3_file for os2. |
|
637 */ |
|
638 static const sqlite3_io_methods os2IoMethod = { |
|
639 1, /* iVersion */ |
|
640 os2Close, |
|
641 os2Read, |
|
642 os2Write, |
|
643 os2Truncate, |
|
644 os2Sync, |
|
645 os2FileSize, |
|
646 os2Lock, |
|
647 os2Unlock, |
|
648 os2CheckReservedLock, |
|
649 os2FileControl, |
|
650 os2SectorSize, |
|
651 os2DeviceCharacteristics |
|
652 }; |
|
653 |
|
654 /*************************************************************************** |
|
655 ** Here ends the I/O methods that form the sqlite3_io_methods object. |
|
656 ** |
|
657 ** The next block of code implements the VFS methods. |
|
658 ****************************************************************************/ |
|
659 |
|
660 /* |
|
661 ** Create a temporary file name in zBuf. zBuf must be big enough to |
|
662 ** hold at pVfs->mxPathname characters. |
|
663 */ |
|
664 static int getTempname(int nBuf, char *zBuf ){ |
|
665 static const unsigned char zChars[] = |
|
666 "abcdefghijklmnopqrstuvwxyz" |
|
667 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
668 "0123456789"; |
|
669 int i, j; |
|
670 char zTempPathBuf[3]; |
|
671 PSZ zTempPath = (PSZ)&zTempPathBuf; |
|
672 if( sqlite3_temp_directory ){ |
|
673 zTempPath = sqlite3_temp_directory; |
|
674 }else{ |
|
675 if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ |
|
676 if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ |
|
677 if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ |
|
678 ULONG ulDriveNum = 0, ulDriveMap = 0; |
|
679 DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); |
|
680 sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); |
|
681 } |
|
682 } |
|
683 } |
|
684 } |
|
685 /* Strip off a trailing slashes or backslashes, otherwise we would get * |
|
686 * multiple (back)slashes which causes DosOpen() to fail. * |
|
687 * Trailing spaces are not allowed, either. */ |
|
688 j = strlen(zTempPath); |
|
689 while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' |
|
690 || zTempPath[j-1] == ' ' ) ){ |
|
691 j--; |
|
692 } |
|
693 zTempPath[j] = '\0'; |
|
694 if( !sqlite3_temp_directory ){ |
|
695 char *zTempPathUTF = convertCpPathToUtf8( zTempPath ); |
|
696 sqlite3_snprintf( nBuf-30, zBuf, |
|
697 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF ); |
|
698 free( zTempPathUTF ); |
|
699 }else{ |
|
700 sqlite3_snprintf( nBuf-30, zBuf, |
|
701 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath ); |
|
702 } |
|
703 j = strlen( zBuf ); |
|
704 sqlite3_randomness( 20, &zBuf[j] ); |
|
705 for( i = 0; i < 20; i++, j++ ){ |
|
706 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
|
707 } |
|
708 zBuf[j] = 0; |
|
709 OSTRACE2( "TEMP FILENAME: %s\n", zBuf ); |
|
710 return SQLITE_OK; |
|
711 } |
|
712 |
|
713 |
|
714 /* |
|
715 ** Turn a relative pathname into a full pathname. Write the full |
|
716 ** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname |
|
717 ** bytes in size. |
|
718 */ |
|
719 static int os2FullPathname( |
|
720 sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
|
721 const char *zRelative, /* Possibly relative input path */ |
|
722 int nFull, /* Size of output buffer in bytes */ |
|
723 char *zFull /* Output buffer */ |
|
724 ){ |
|
725 char *zRelativeCp = convertUtf8PathToCp( zRelative ); |
|
726 char zFullCp[CCHMAXPATH] = "\0"; |
|
727 char *zFullUTF; |
|
728 APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp, |
|
729 CCHMAXPATH ); |
|
730 free( zRelativeCp ); |
|
731 zFullUTF = convertCpPathToUtf8( zFullCp ); |
|
732 sqlite3_snprintf( nFull, zFull, zFullUTF ); |
|
733 free( zFullUTF ); |
|
734 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
735 } |
|
736 |
|
737 |
|
738 /* |
|
739 ** Open a file. |
|
740 */ |
|
741 static int os2Open( |
|
742 sqlite3_vfs *pVfs, /* Not used */ |
|
743 const char *zName, /* Name of the file */ |
|
744 sqlite3_file *id, /* Write the SQLite file handle here */ |
|
745 int flags, /* Open mode flags */ |
|
746 int *pOutFlags /* Status return flags */ |
|
747 ){ |
|
748 HFILE h; |
|
749 ULONG ulFileAttribute = FILE_NORMAL; |
|
750 ULONG ulOpenFlags = 0; |
|
751 ULONG ulOpenMode = 0; |
|
752 os2File *pFile = (os2File*)id; |
|
753 APIRET rc = NO_ERROR; |
|
754 ULONG ulAction; |
|
755 char *zNameCp; |
|
756 char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */ |
|
757 |
|
758 /* If the second argument to this function is NULL, generate a |
|
759 ** temporary file name to use |
|
760 */ |
|
761 if( !zName ){ |
|
762 int rc = getTempname(CCHMAXPATH+1, zTmpname); |
|
763 if( rc!=SQLITE_OK ){ |
|
764 return rc; |
|
765 } |
|
766 zName = zTmpname; |
|
767 } |
|
768 |
|
769 |
|
770 memset( pFile, 0, sizeof(*pFile) ); |
|
771 |
|
772 OSTRACE2( "OPEN want %d\n", flags ); |
|
773 |
|
774 if( flags & SQLITE_OPEN_READWRITE ){ |
|
775 ulOpenMode |= OPEN_ACCESS_READWRITE; |
|
776 OSTRACE1( "OPEN read/write\n" ); |
|
777 }else{ |
|
778 ulOpenMode |= OPEN_ACCESS_READONLY; |
|
779 OSTRACE1( "OPEN read only\n" ); |
|
780 } |
|
781 |
|
782 if( flags & SQLITE_OPEN_CREATE ){ |
|
783 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW; |
|
784 OSTRACE1( "OPEN open new/create\n" ); |
|
785 }else{ |
|
786 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW; |
|
787 OSTRACE1( "OPEN open existing\n" ); |
|
788 } |
|
789 |
|
790 if( flags & SQLITE_OPEN_MAIN_DB ){ |
|
791 ulOpenMode |= OPEN_SHARE_DENYNONE; |
|
792 OSTRACE1( "OPEN share read/write\n" ); |
|
793 }else{ |
|
794 ulOpenMode |= OPEN_SHARE_DENYWRITE; |
|
795 OSTRACE1( "OPEN share read only\n" ); |
|
796 } |
|
797 |
|
798 if( flags & SQLITE_OPEN_DELETEONCLOSE ){ |
|
799 char pathUtf8[CCHMAXPATH]; |
|
800 #ifdef NDEBUG /* when debugging we want to make sure it is deleted */ |
|
801 ulFileAttribute = FILE_HIDDEN; |
|
802 #endif |
|
803 os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 ); |
|
804 pFile->pathToDel = convertUtf8PathToCp( pathUtf8 ); |
|
805 OSTRACE1( "OPEN hidden/delete on close file attributes\n" ); |
|
806 }else{ |
|
807 pFile->pathToDel = NULL; |
|
808 OSTRACE1( "OPEN normal file attribute\n" ); |
|
809 } |
|
810 |
|
811 /* always open in random access mode for possibly better speed */ |
|
812 ulOpenMode |= OPEN_FLAGS_RANDOM; |
|
813 ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR; |
|
814 ulOpenMode |= OPEN_FLAGS_NOINHERIT; |
|
815 |
|
816 zNameCp = convertUtf8PathToCp( zName ); |
|
817 rc = DosOpen( (PSZ)zNameCp, |
|
818 &h, |
|
819 &ulAction, |
|
820 0L, |
|
821 ulFileAttribute, |
|
822 ulOpenFlags, |
|
823 ulOpenMode, |
|
824 (PEAOP2)NULL ); |
|
825 free( zNameCp ); |
|
826 if( rc != NO_ERROR ){ |
|
827 OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n", |
|
828 rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ); |
|
829 if( pFile->pathToDel ) |
|
830 free( pFile->pathToDel ); |
|
831 pFile->pathToDel = NULL; |
|
832 if( flags & SQLITE_OPEN_READWRITE ){ |
|
833 OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ); |
|
834 return os2Open( pVfs, zName, id, |
|
835 ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE), |
|
836 pOutFlags ); |
|
837 }else{ |
|
838 return SQLITE_CANTOPEN; |
|
839 } |
|
840 } |
|
841 |
|
842 if( pOutFlags ){ |
|
843 *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; |
|
844 } |
|
845 |
|
846 pFile->pMethod = &os2IoMethod; |
|
847 pFile->h = h; |
|
848 OpenCounter(+1); |
|
849 OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ); |
|
850 return SQLITE_OK; |
|
851 } |
|
852 |
|
853 /* |
|
854 ** Delete the named file. |
|
855 */ |
|
856 static int os2Delete( |
|
857 sqlite3_vfs *pVfs, /* Not used on os2 */ |
|
858 const char *zFilename, /* Name of file to delete */ |
|
859 int syncDir /* Not used on os2 */ |
|
860 ){ |
|
861 APIRET rc = NO_ERROR; |
|
862 char *zFilenameCp = convertUtf8PathToCp( zFilename ); |
|
863 SimulateIOError( return SQLITE_IOERR_DELETE ); |
|
864 rc = DosDelete( (PSZ)zFilenameCp ); |
|
865 free( zFilenameCp ); |
|
866 OSTRACE2( "DELETE \"%s\"\n", zFilename ); |
|
867 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE; |
|
868 } |
|
869 |
|
870 /* |
|
871 ** Check the existance and status of a file. |
|
872 */ |
|
873 static int os2Access( |
|
874 sqlite3_vfs *pVfs, /* Not used on os2 */ |
|
875 const char *zFilename, /* Name of file to check */ |
|
876 int flags, /* Type of test to make on this file */ |
|
877 int *pOut /* Write results here */ |
|
878 ){ |
|
879 FILESTATUS3 fsts3ConfigInfo; |
|
880 APIRET rc = NO_ERROR; |
|
881 char *zFilenameCp = convertUtf8PathToCp( zFilename ); |
|
882 |
|
883 memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) ); |
|
884 rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, |
|
885 &fsts3ConfigInfo, sizeof(FILESTATUS3) ); |
|
886 free( zFilenameCp ); |
|
887 OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", |
|
888 fsts3ConfigInfo.attrFile, flags, rc ); |
|
889 switch( flags ){ |
|
890 case SQLITE_ACCESS_READ: |
|
891 case SQLITE_ACCESS_EXISTS: |
|
892 rc = (rc == NO_ERROR); |
|
893 OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc ); |
|
894 break; |
|
895 case SQLITE_ACCESS_READWRITE: |
|
896 rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 ); |
|
897 OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc ); |
|
898 break; |
|
899 default: |
|
900 assert( !"Invalid flags argument" ); |
|
901 } |
|
902 *pOut = rc; |
|
903 return SQLITE_OK; |
|
904 } |
|
905 |
|
906 |
|
907 #ifndef SQLITE_OMIT_LOAD_EXTENSION |
|
908 /* |
|
909 ** Interfaces for opening a shared library, finding entry points |
|
910 ** within the shared library, and closing the shared library. |
|
911 */ |
|
912 /* |
|
913 ** Interfaces for opening a shared library, finding entry points |
|
914 ** within the shared library, and closing the shared library. |
|
915 */ |
|
916 static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
|
917 UCHAR loadErr[256]; |
|
918 HMODULE hmod; |
|
919 APIRET rc; |
|
920 char *zFilenameCp = convertUtf8PathToCp(zFilename); |
|
921 rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod); |
|
922 free(zFilenameCp); |
|
923 return rc != NO_ERROR ? 0 : (void*)hmod; |
|
924 } |
|
925 /* |
|
926 ** A no-op since the error code is returned on the DosLoadModule call. |
|
927 ** os2Dlopen returns zero if DosLoadModule is not successful. |
|
928 */ |
|
929 static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ |
|
930 /* no-op */ |
|
931 } |
|
932 static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ |
|
933 PFN pfn; |
|
934 APIRET rc; |
|
935 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); |
|
936 if( rc != NO_ERROR ){ |
|
937 /* if the symbol itself was not found, search again for the same |
|
938 * symbol with an extra underscore, that might be needed depending |
|
939 * on the calling convention */ |
|
940 char _zSymbol[256] = "_"; |
|
941 strncat(_zSymbol, zSymbol, 255); |
|
942 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); |
|
943 } |
|
944 return rc != NO_ERROR ? 0 : (void*)pfn; |
|
945 } |
|
946 static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ |
|
947 DosFreeModule((HMODULE)pHandle); |
|
948 } |
|
949 #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ |
|
950 #define os2DlOpen 0 |
|
951 #define os2DlError 0 |
|
952 #define os2DlSym 0 |
|
953 #define os2DlClose 0 |
|
954 #endif |
|
955 |
|
956 |
|
957 /* |
|
958 ** Write up to nBuf bytes of randomness into zBuf. |
|
959 */ |
|
960 static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){ |
|
961 ULONG sizeofULong = sizeof(ULONG); |
|
962 int n = 0; |
|
963 if( sizeof(DATETIME) <= nBuf - n ){ |
|
964 DATETIME x; |
|
965 DosGetDateTime(&x); |
|
966 memcpy(&zBuf[n], &x, sizeof(x)); |
|
967 n += sizeof(x); |
|
968 } |
|
969 |
|
970 if( sizeofULong <= nBuf - n ){ |
|
971 PPIB ppib; |
|
972 DosGetInfoBlocks(NULL, &ppib); |
|
973 memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong); |
|
974 n += sizeofULong; |
|
975 } |
|
976 |
|
977 if( sizeofULong <= nBuf - n ){ |
|
978 PTIB ptib; |
|
979 DosGetInfoBlocks(&ptib, NULL); |
|
980 memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong); |
|
981 n += sizeofULong; |
|
982 } |
|
983 |
|
984 /* if we still haven't filled the buffer yet the following will */ |
|
985 /* grab everything once instead of making several calls for a single item */ |
|
986 if( sizeofULong <= nBuf - n ){ |
|
987 ULONG ulSysInfo[QSV_MAX]; |
|
988 DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX); |
|
989 |
|
990 memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong); |
|
991 n += sizeofULong; |
|
992 |
|
993 if( sizeofULong <= nBuf - n ){ |
|
994 memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong); |
|
995 n += sizeofULong; |
|
996 } |
|
997 if( sizeofULong <= nBuf - n ){ |
|
998 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong); |
|
999 n += sizeofULong; |
|
1000 } |
|
1001 if( sizeofULong <= nBuf - n ){ |
|
1002 memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong); |
|
1003 n += sizeofULong; |
|
1004 } |
|
1005 if( sizeofULong <= nBuf - n ){ |
|
1006 memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong); |
|
1007 n += sizeofULong; |
|
1008 } |
|
1009 } |
|
1010 |
|
1011 return n; |
|
1012 } |
|
1013 |
|
1014 /* |
|
1015 ** Sleep for a little while. Return the amount of time slept. |
|
1016 ** The argument is the number of microseconds we want to sleep. |
|
1017 ** The return value is the number of microseconds of sleep actually |
|
1018 ** requested from the underlying operating system, a number which |
|
1019 ** might be greater than or equal to the argument, but not less |
|
1020 ** than the argument. |
|
1021 */ |
|
1022 static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){ |
|
1023 DosSleep( (microsec/1000) ); |
|
1024 return microsec; |
|
1025 } |
|
1026 |
|
1027 /* |
|
1028 ** The following variable, if set to a non-zero value, becomes the result |
|
1029 ** returned from sqlite3OsCurrentTime(). This is used for testing. |
|
1030 */ |
|
1031 #ifdef SQLITE_TEST |
|
1032 int sqlite3_current_time = 0; |
|
1033 #endif |
|
1034 |
|
1035 /* |
|
1036 ** Find the current time (in Universal Coordinated Time). Write the |
|
1037 ** current time and date as a Julian Day number into *prNow and |
|
1038 ** return 0. Return 1 if the time and date cannot be found. |
|
1039 */ |
|
1040 int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ |
|
1041 double now; |
|
1042 SHORT minute; /* needs to be able to cope with negative timezone offset */ |
|
1043 USHORT second, hour, |
|
1044 day, month, year; |
|
1045 DATETIME dt; |
|
1046 DosGetDateTime( &dt ); |
|
1047 second = (USHORT)dt.seconds; |
|
1048 minute = (SHORT)dt.minutes + dt.timezone; |
|
1049 hour = (USHORT)dt.hours; |
|
1050 day = (USHORT)dt.day; |
|
1051 month = (USHORT)dt.month; |
|
1052 year = (USHORT)dt.year; |
|
1053 |
|
1054 /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html |
|
1055 http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ |
|
1056 /* Calculate the Julian days */ |
|
1057 now = day - 32076 + |
|
1058 1461*(year + 4800 + (month - 14)/12)/4 + |
|
1059 367*(month - 2 - (month - 14)/12*12)/12 - |
|
1060 3*((year + 4900 + (month - 14)/12)/100)/4; |
|
1061 |
|
1062 /* Add the fractional hours, mins and seconds */ |
|
1063 now += (hour + 12.0)/24.0; |
|
1064 now += minute/1440.0; |
|
1065 now += second/86400.0; |
|
1066 *prNow = now; |
|
1067 #ifdef SQLITE_TEST |
|
1068 if( sqlite3_current_time ){ |
|
1069 *prNow = sqlite3_current_time/86400.0 + 2440587.5; |
|
1070 } |
|
1071 #endif |
|
1072 return 0; |
|
1073 } |
|
1074 |
|
1075 static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
|
1076 return 0; |
|
1077 } |
|
1078 |
|
1079 /* |
|
1080 ** Initialize and deinitialize the operating system interface. |
|
1081 */ |
|
1082 int sqlite3_os_init(void){ |
|
1083 static sqlite3_vfs os2Vfs = { |
|
1084 1, /* iVersion */ |
|
1085 sizeof(os2File), /* szOsFile */ |
|
1086 CCHMAXPATH, /* mxPathname */ |
|
1087 0, /* pNext */ |
|
1088 "os2", /* zName */ |
|
1089 0, /* pAppData */ |
|
1090 |
|
1091 os2Open, /* xOpen */ |
|
1092 os2Delete, /* xDelete */ |
|
1093 os2Access, /* xAccess */ |
|
1094 os2FullPathname, /* xFullPathname */ |
|
1095 os2DlOpen, /* xDlOpen */ |
|
1096 os2DlError, /* xDlError */ |
|
1097 os2DlSym, /* xDlSym */ |
|
1098 os2DlClose, /* xDlClose */ |
|
1099 os2Randomness, /* xRandomness */ |
|
1100 os2Sleep, /* xSleep */ |
|
1101 os2CurrentTime, /* xCurrentTime */ |
|
1102 os2GetLastError /* xGetLastError */ |
|
1103 }; |
|
1104 sqlite3_vfs_register(&os2Vfs, 1); |
|
1105 initUconvObjects(); |
|
1106 return SQLITE_OK; |
|
1107 } |
|
1108 int sqlite3_os_end(void){ |
|
1109 freeUconvObjects(); |
|
1110 return SQLITE_OK; |
|
1111 } |
|
1112 |
|
1113 #endif /* SQLITE_OS_OS2 */ |