Annotation of embedaddon/sqlite3/src/os_os2.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** 2006 Feb 14
3: **
4: ** The author disclaims copyright to this source code. In place of
5: ** a legal notice, here is a blessing:
6: **
7: ** May you do good and not evil.
8: ** May you find forgiveness for yourself and forgive others.
9: ** May you share freely, never taking more than you give.
10: **
11: ******************************************************************************
12: **
13: ** This file contains code that is specific to OS/2.
14: */
15:
16: #include "sqliteInt.h"
17:
18: #if SQLITE_OS_OS2
19:
20: /*
21: ** A Note About Memory Allocation:
22: **
23: ** This driver uses malloc()/free() directly rather than going through
24: ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers
25: ** are designed for use on embedded systems where memory is scarce and
26: ** malloc failures happen frequently. OS/2 does not typically run on
27: ** embedded systems, and when it does the developers normally have bigger
28: ** problems to worry about than running out of memory. So there is not
29: ** a compelling need to use the wrappers.
30: **
31: ** But there is a good reason to not use the wrappers. If we use the
32: ** wrappers then we will get simulated malloc() failures within this
33: ** driver. And that causes all kinds of problems for our tests. We
34: ** could enhance SQLite to deal with simulated malloc failures within
35: ** the OS driver, but the code to deal with those failure would not
36: ** be exercised on Linux (which does not need to malloc() in the driver)
37: ** and so we would have difficulty writing coverage tests for that
38: ** code. Better to leave the code out, we think.
39: **
40: ** The point of this discussion is as follows: When creating a new
41: ** OS layer for an embedded system, if you use this file as an example,
42: ** avoid the use of malloc()/free(). Those routines work ok on OS/2
43: ** desktops but not so well in embedded systems.
44: */
45:
46: /*
47: ** Macros used to determine whether or not to use threads.
48: */
49: #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE
50: # define SQLITE_OS2_THREADS 1
51: #endif
52:
53: /*
54: ** Include code that is common to all os_*.c files
55: */
56: #include "os_common.h"
57:
58: /* Forward references */
59: typedef struct os2File os2File; /* The file structure */
60: typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */
61: typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */
62:
63: /*
64: ** The os2File structure is subclass of sqlite3_file specific for the OS/2
65: ** protability layer.
66: */
67: struct os2File {
68: const sqlite3_io_methods *pMethod; /* Always the first entry */
69: HFILE h; /* Handle for accessing the file */
70: int flags; /* Flags provided to os2Open() */
71: int locktype; /* Type of lock currently held on this file */
72: int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
73: char *zFullPathCp; /* Full path name of this file */
74: os2ShmLink *pShmLink; /* Instance of shared memory on this file */
75: };
76:
77: #define LOCK_TIMEOUT 10L /* the default locking timeout */
78:
79: /*
80: ** Missing from some versions of the OS/2 toolkit -
81: ** used to allocate from high memory if possible
82: */
83: #ifndef OBJ_ANY
84: # define OBJ_ANY 0x00000400
85: #endif
86:
87: /*****************************************************************************
88: ** The next group of routines implement the I/O methods specified
89: ** by the sqlite3_io_methods object.
90: ******************************************************************************/
91:
92: /*
93: ** Close a file.
94: */
95: static int os2Close( sqlite3_file *id ){
96: APIRET rc;
97: os2File *pFile = (os2File*)id;
98:
99: assert( id!=0 );
100: OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp ));
101:
102: rc = DosClose( pFile->h );
103:
104: if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE )
105: DosForceDelete( (PSZ)pFile->zFullPathCp );
106:
107: free( pFile->zFullPathCp );
108: pFile->zFullPathCp = NULL;
109: pFile->locktype = NO_LOCK;
110: pFile->h = (HFILE)-1;
111: pFile->flags = 0;
112:
113: OpenCounter( -1 );
114: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
115: }
116:
117: /*
118: ** Read data from a file into a buffer. Return SQLITE_OK if all
119: ** bytes were read successfully and SQLITE_IOERR if anything goes
120: ** wrong.
121: */
122: static int os2Read(
123: sqlite3_file *id, /* File to read from */
124: void *pBuf, /* Write content into this buffer */
125: int amt, /* Number of bytes to read */
126: sqlite3_int64 offset /* Begin reading at this offset */
127: ){
128: ULONG fileLocation = 0L;
129: ULONG got;
130: os2File *pFile = (os2File*)id;
131: assert( id!=0 );
132: SimulateIOError( return SQLITE_IOERR_READ );
133: OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype ));
134: if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
135: return SQLITE_IOERR;
136: }
137: if( DosRead( pFile->h, pBuf, amt, &got ) != NO_ERROR ){
138: return SQLITE_IOERR_READ;
139: }
140: if( got == (ULONG)amt )
141: return SQLITE_OK;
142: else {
143: /* Unread portions of the input buffer must be zero-filled */
144: memset(&((char*)pBuf)[got], 0, amt-got);
145: return SQLITE_IOERR_SHORT_READ;
146: }
147: }
148:
149: /*
150: ** Write data from a buffer into a file. Return SQLITE_OK on success
151: ** or some other error code on failure.
152: */
153: static int os2Write(
154: sqlite3_file *id, /* File to write into */
155: const void *pBuf, /* The bytes to be written */
156: int amt, /* Number of bytes to write */
157: sqlite3_int64 offset /* Offset into the file to begin writing at */
158: ){
159: ULONG fileLocation = 0L;
160: APIRET rc = NO_ERROR;
161: ULONG wrote;
162: os2File *pFile = (os2File*)id;
163: assert( id!=0 );
164: SimulateIOError( return SQLITE_IOERR_WRITE );
165: SimulateDiskfullError( return SQLITE_FULL );
166: OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ));
167: if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
168: return SQLITE_IOERR;
169: }
170: assert( amt>0 );
171: while( amt > 0 &&
172: ( rc = DosWrite( pFile->h, (PVOID)pBuf, amt, &wrote ) ) == NO_ERROR &&
173: wrote > 0
174: ){
175: amt -= wrote;
176: pBuf = &((char*)pBuf)[wrote];
177: }
178:
179: return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
180: }
181:
182: /*
183: ** Truncate an open file to a specified size
184: */
185: static int os2Truncate( sqlite3_file *id, i64 nByte ){
186: APIRET rc;
187: os2File *pFile = (os2File*)id;
188: assert( id!=0 );
189: OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
190: SimulateIOError( return SQLITE_IOERR_TRUNCATE );
191:
192: /* If the user has configured a chunk-size for this file, truncate the
193: ** file so that it consists of an integer number of chunks (i.e. the
194: ** actual file size after the operation may be larger than the requested
195: ** size).
196: */
197: if( pFile->szChunk ){
198: nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
199: }
200:
201: rc = DosSetFileSize( pFile->h, nByte );
202: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
203: }
204:
205: #ifdef SQLITE_TEST
206: /*
207: ** Count the number of fullsyncs and normal syncs. This is used to test
208: ** that syncs and fullsyncs are occuring at the right times.
209: */
210: int sqlite3_sync_count = 0;
211: int sqlite3_fullsync_count = 0;
212: #endif
213:
214: /*
215: ** Make sure all writes to a particular file are committed to disk.
216: */
217: static int os2Sync( sqlite3_file *id, int flags ){
218: os2File *pFile = (os2File*)id;
219: OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ));
220: #ifdef SQLITE_TEST
221: if( flags & SQLITE_SYNC_FULL){
222: sqlite3_fullsync_count++;
223: }
224: sqlite3_sync_count++;
225: #endif
226: /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
227: ** no-op
228: */
229: #ifdef SQLITE_NO_SYNC
230: UNUSED_PARAMETER(pFile);
231: return SQLITE_OK;
232: #else
233: return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
234: #endif
235: }
236:
237: /*
238: ** Determine the current size of a file in bytes
239: */
240: static int os2FileSize( sqlite3_file *id, sqlite3_int64 *pSize ){
241: APIRET rc = NO_ERROR;
242: FILESTATUS3 fsts3FileInfo;
243: memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo));
244: assert( id!=0 );
245: SimulateIOError( return SQLITE_IOERR_FSTAT );
246: rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) );
247: if( rc == NO_ERROR ){
248: *pSize = fsts3FileInfo.cbFile;
249: return SQLITE_OK;
250: }else{
251: return SQLITE_IOERR_FSTAT;
252: }
253: }
254:
255: /*
256: ** Acquire a reader lock.
257: */
258: static int getReadLock( os2File *pFile ){
259: FILELOCK LockArea,
260: UnlockArea;
261: APIRET res;
262: memset(&LockArea, 0, sizeof(LockArea));
263: memset(&UnlockArea, 0, sizeof(UnlockArea));
264: LockArea.lOffset = SHARED_FIRST;
265: LockArea.lRange = SHARED_SIZE;
266: UnlockArea.lOffset = 0L;
267: UnlockArea.lRange = 0L;
268: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
269: OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res ));
270: return res;
271: }
272:
273: /*
274: ** Undo a readlock
275: */
276: static int unlockReadLock( os2File *id ){
277: FILELOCK LockArea,
278: UnlockArea;
279: APIRET res;
280: memset(&LockArea, 0, sizeof(LockArea));
281: memset(&UnlockArea, 0, sizeof(UnlockArea));
282: LockArea.lOffset = 0L;
283: LockArea.lRange = 0L;
284: UnlockArea.lOffset = SHARED_FIRST;
285: UnlockArea.lRange = SHARED_SIZE;
286: res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
287: OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ));
288: return res;
289: }
290:
291: /*
292: ** Lock the file with the lock specified by parameter locktype - one
293: ** of the following:
294: **
295: ** (1) SHARED_LOCK
296: ** (2) RESERVED_LOCK
297: ** (3) PENDING_LOCK
298: ** (4) EXCLUSIVE_LOCK
299: **
300: ** Sometimes when requesting one lock state, additional lock states
301: ** are inserted in between. The locking might fail on one of the later
302: ** transitions leaving the lock state different from what it started but
303: ** still short of its goal. The following chart shows the allowed
304: ** transitions and the inserted intermediate states:
305: **
306: ** UNLOCKED -> SHARED
307: ** SHARED -> RESERVED
308: ** SHARED -> (PENDING) -> EXCLUSIVE
309: ** RESERVED -> (PENDING) -> EXCLUSIVE
310: ** PENDING -> EXCLUSIVE
311: **
312: ** This routine will only increase a lock. The os2Unlock() routine
313: ** erases all locks at once and returns us immediately to locking level 0.
314: ** It is not possible to lower the locking level one step at a time. You
315: ** must go straight to locking level 0.
316: */
317: static int os2Lock( sqlite3_file *id, int locktype ){
318: int rc = SQLITE_OK; /* Return code from subroutines */
319: APIRET res = NO_ERROR; /* Result of an OS/2 lock call */
320: int newLocktype; /* Set pFile->locktype to this value before exiting */
321: int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
322: FILELOCK LockArea,
323: UnlockArea;
324: os2File *pFile = (os2File*)id;
325: memset(&LockArea, 0, sizeof(LockArea));
326: memset(&UnlockArea, 0, sizeof(UnlockArea));
327: assert( pFile!=0 );
328: OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ));
329:
330: /* If there is already a lock of this type or more restrictive on the
331: ** os2File, do nothing. Don't use the end_lock: exit path, as
332: ** sqlite3_mutex_enter() hasn't been called yet.
333: */
334: if( pFile->locktype>=locktype ){
335: OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype ));
336: return SQLITE_OK;
337: }
338:
339: /* Make sure the locking sequence is correct
340: */
341: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
342: assert( locktype!=PENDING_LOCK );
343: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
344:
345: /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
346: ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
347: ** the PENDING_LOCK byte is temporary.
348: */
349: newLocktype = pFile->locktype;
350: if( pFile->locktype==NO_LOCK
351: || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
352: ){
353: LockArea.lOffset = PENDING_BYTE;
354: LockArea.lRange = 1L;
355: UnlockArea.lOffset = 0L;
356: UnlockArea.lRange = 0L;
357:
358: /* wait longer than LOCK_TIMEOUT here not to have to try multiple times */
359: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
360: if( res == NO_ERROR ){
361: gotPendingLock = 1;
362: OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ));
363: }
364: }
365:
366: /* Acquire a shared lock
367: */
368: if( locktype==SHARED_LOCK && res == NO_ERROR ){
369: assert( pFile->locktype==NO_LOCK );
370: res = getReadLock(pFile);
371: if( res == NO_ERROR ){
372: newLocktype = SHARED_LOCK;
373: }
374: OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ));
375: }
376:
377: /* Acquire a RESERVED lock
378: */
379: if( locktype==RESERVED_LOCK && res == NO_ERROR ){
380: assert( pFile->locktype==SHARED_LOCK );
381: LockArea.lOffset = RESERVED_BYTE;
382: LockArea.lRange = 1L;
383: UnlockArea.lOffset = 0L;
384: UnlockArea.lRange = 0L;
385: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
386: if( res == NO_ERROR ){
387: newLocktype = RESERVED_LOCK;
388: }
389: OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ));
390: }
391:
392: /* Acquire a PENDING lock
393: */
394: if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
395: newLocktype = PENDING_LOCK;
396: gotPendingLock = 0;
397: OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n",
398: pFile->h ));
399: }
400:
401: /* Acquire an EXCLUSIVE lock
402: */
403: if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
404: assert( pFile->locktype>=SHARED_LOCK );
405: res = unlockReadLock(pFile);
406: OSTRACE(( "unreadlock = %d\n", res ));
407: LockArea.lOffset = SHARED_FIRST;
408: LockArea.lRange = SHARED_SIZE;
409: UnlockArea.lOffset = 0L;
410: UnlockArea.lRange = 0L;
411: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
412: if( res == NO_ERROR ){
413: newLocktype = EXCLUSIVE_LOCK;
414: }else{
415: OSTRACE(( "OS/2 error-code = %d\n", res ));
416: getReadLock(pFile);
417: }
418: OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ));
419: }
420:
421: /* If we are holding a PENDING lock that ought to be released, then
422: ** release it now.
423: */
424: if( gotPendingLock && locktype==SHARED_LOCK ){
425: int r;
426: LockArea.lOffset = 0L;
427: LockArea.lRange = 0L;
428: UnlockArea.lOffset = PENDING_BYTE;
429: UnlockArea.lRange = 1L;
430: r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
431: OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ));
432: }
433:
434: /* Update the state of the lock has held in the file descriptor then
435: ** return the appropriate result code.
436: */
437: if( res == NO_ERROR ){
438: rc = SQLITE_OK;
439: }else{
440: OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
441: locktype, newLocktype ));
442: rc = SQLITE_BUSY;
443: }
444: pFile->locktype = newLocktype;
445: OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype ));
446: return rc;
447: }
448:
449: /*
450: ** This routine checks if there is a RESERVED lock held on the specified
451: ** file by this or any other process. If such a lock is held, return
452: ** non-zero, otherwise zero.
453: */
454: static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
455: int r = 0;
456: os2File *pFile = (os2File*)id;
457: assert( pFile!=0 );
458: if( pFile->locktype>=RESERVED_LOCK ){
459: r = 1;
460: OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ));
461: }else{
462: FILELOCK LockArea,
463: UnlockArea;
464: APIRET rc = NO_ERROR;
465: memset(&LockArea, 0, sizeof(LockArea));
466: memset(&UnlockArea, 0, sizeof(UnlockArea));
467: LockArea.lOffset = RESERVED_BYTE;
468: LockArea.lRange = 1L;
469: UnlockArea.lOffset = 0L;
470: UnlockArea.lRange = 0L;
471: rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
472: OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ));
473: if( rc == NO_ERROR ){
474: APIRET rcu = NO_ERROR; /* return code for unlocking */
475: LockArea.lOffset = 0L;
476: LockArea.lRange = 0L;
477: UnlockArea.lOffset = RESERVED_BYTE;
478: UnlockArea.lRange = 1L;
479: rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
480: OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ));
481: }
482: r = !(rc == NO_ERROR);
483: OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ));
484: }
485: *pOut = r;
486: return SQLITE_OK;
487: }
488:
489: /*
490: ** Lower the locking level on file descriptor id to locktype. locktype
491: ** must be either NO_LOCK or SHARED_LOCK.
492: **
493: ** If the locking level of the file descriptor is already at or below
494: ** the requested locking level, this routine is a no-op.
495: **
496: ** It is not possible for this routine to fail if the second argument
497: ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
498: ** might return SQLITE_IOERR;
499: */
500: static int os2Unlock( sqlite3_file *id, int locktype ){
501: int type;
502: os2File *pFile = (os2File*)id;
503: APIRET rc = SQLITE_OK;
504: APIRET res = NO_ERROR;
505: FILELOCK LockArea,
506: UnlockArea;
507: memset(&LockArea, 0, sizeof(LockArea));
508: memset(&UnlockArea, 0, sizeof(UnlockArea));
509: assert( pFile!=0 );
510: assert( locktype<=SHARED_LOCK );
511: OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ));
512: type = pFile->locktype;
513: if( type>=EXCLUSIVE_LOCK ){
514: LockArea.lOffset = 0L;
515: LockArea.lRange = 0L;
516: UnlockArea.lOffset = SHARED_FIRST;
517: UnlockArea.lRange = SHARED_SIZE;
518: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
519: OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ));
520: if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
521: /* This should never happen. We should always be able to
522: ** reacquire the read lock */
523: OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ));
524: rc = SQLITE_IOERR_UNLOCK;
525: }
526: }
527: if( type>=RESERVED_LOCK ){
528: LockArea.lOffset = 0L;
529: LockArea.lRange = 0L;
530: UnlockArea.lOffset = RESERVED_BYTE;
531: UnlockArea.lRange = 1L;
532: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
533: OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res ));
534: }
535: if( locktype==NO_LOCK && type>=SHARED_LOCK ){
536: res = unlockReadLock(pFile);
537: OSTRACE(( "UNLOCK %d is %d want %d res=%d\n",
538: pFile->h, type, locktype, res ));
539: }
540: if( type>=PENDING_LOCK ){
541: LockArea.lOffset = 0L;
542: LockArea.lRange = 0L;
543: UnlockArea.lOffset = PENDING_BYTE;
544: UnlockArea.lRange = 1L;
545: res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
546: OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res ));
547: }
548: pFile->locktype = locktype;
549: OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ));
550: return rc;
551: }
552:
553: /*
554: ** Control and query of the open file handle.
555: */
556: static int os2FileControl(sqlite3_file *id, int op, void *pArg){
557: switch( op ){
558: case SQLITE_FCNTL_LOCKSTATE: {
559: *(int*)pArg = ((os2File*)id)->locktype;
560: OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
561: ((os2File*)id)->h, ((os2File*)id)->locktype ));
562: return SQLITE_OK;
563: }
564: case SQLITE_FCNTL_CHUNK_SIZE: {
565: ((os2File*)id)->szChunk = *(int*)pArg;
566: return SQLITE_OK;
567: }
568: case SQLITE_FCNTL_SIZE_HINT: {
569: sqlite3_int64 sz = *(sqlite3_int64*)pArg;
570: SimulateIOErrorBenign(1);
571: os2Truncate(id, sz);
572: SimulateIOErrorBenign(0);
573: return SQLITE_OK;
574: }
575: case SQLITE_FCNTL_SYNC_OMITTED: {
576: return SQLITE_OK;
577: }
578: }
579: return SQLITE_NOTFOUND;
580: }
581:
582: /*
583: ** Return the sector size in bytes of the underlying block device for
584: ** the specified file. This is almost always 512 bytes, but may be
585: ** larger for some devices.
586: **
587: ** SQLite code assumes this function cannot fail. It also assumes that
588: ** if two files are created in the same file-system directory (i.e.
589: ** a database and its journal file) that the sector size will be the
590: ** same for both.
591: */
592: static int os2SectorSize(sqlite3_file *id){
593: UNUSED_PARAMETER(id);
594: return SQLITE_DEFAULT_SECTOR_SIZE;
595: }
596:
597: /*
598: ** Return a vector of device characteristics.
599: */
600: static int os2DeviceCharacteristics(sqlite3_file *id){
601: UNUSED_PARAMETER(id);
602: return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
603: }
604:
605:
606: /*
607: ** Character set conversion objects used by conversion routines.
608: */
609: static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
610: static UconvObject uclCp = NULL; /* convert between local codepage and UCS-2 */
611:
612: /*
613: ** Helper function to initialize the conversion objects from and to UTF-8.
614: */
615: static void initUconvObjects( void ){
616: if( UniCreateUconvObject( UTF_8, &ucUtf8 ) != ULS_SUCCESS )
617: ucUtf8 = NULL;
618: if ( UniCreateUconvObject( (UniChar *)L"@path=yes", &uclCp ) != ULS_SUCCESS )
619: uclCp = NULL;
620: }
621:
622: /*
623: ** Helper function to free the conversion objects from and to UTF-8.
624: */
625: static void freeUconvObjects( void ){
626: if ( ucUtf8 )
627: UniFreeUconvObject( ucUtf8 );
628: if ( uclCp )
629: UniFreeUconvObject( uclCp );
630: ucUtf8 = NULL;
631: uclCp = NULL;
632: }
633:
634: /*
635: ** Helper function to convert UTF-8 filenames to local OS/2 codepage.
636: ** The two-step process: first convert the incoming UTF-8 string
637: ** into UCS-2 and then from UCS-2 to the current codepage.
638: ** The returned char pointer has to be freed.
639: */
640: static char *convertUtf8PathToCp( const char *in ){
641: UniChar tempPath[CCHMAXPATH];
642: char *out = (char *)calloc( CCHMAXPATH, 1 );
643:
644: if( !out )
645: return NULL;
646:
647: if( !ucUtf8 || !uclCp )
648: initUconvObjects();
649:
650: /* determine string for the conversion of UTF-8 which is CP1208 */
651: if( UniStrToUcs( ucUtf8, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
652: return out; /* if conversion fails, return the empty string */
653:
654: /* conversion for current codepage which can be used for paths */
655: UniStrFromUcs( uclCp, out, tempPath, CCHMAXPATH );
656:
657: return out;
658: }
659:
660: /*
661: ** Helper function to convert filenames from local codepage to UTF-8.
662: ** The two-step process: first convert the incoming codepage-specific
663: ** string into UCS-2 and then from UCS-2 to the codepage of UTF-8.
664: ** The returned char pointer has to be freed.
665: **
666: ** This function is non-static to be able to use this in shell.c and
667: ** similar applications that take command line arguments.
668: */
669: char *convertCpPathToUtf8( const char *in ){
670: UniChar tempPath[CCHMAXPATH];
671: char *out = (char *)calloc( CCHMAXPATH, 1 );
672:
673: if( !out )
674: return NULL;
675:
676: if( !ucUtf8 || !uclCp )
677: initUconvObjects();
678:
679: /* conversion for current codepage which can be used for paths */
680: if( UniStrToUcs( uclCp, tempPath, (char *)in, CCHMAXPATH ) != ULS_SUCCESS )
681: return out; /* if conversion fails, return the empty string */
682:
683: /* determine string for the conversion of UTF-8 which is CP1208 */
684: UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );
685:
686: return out;
687: }
688:
689:
690: #ifndef SQLITE_OMIT_WAL
691:
692: /*
693: ** Use main database file for interprocess locking. If un-defined
694: ** a separate file is created for this purpose. The file will be
695: ** used only to set file locks. There will be no data written to it.
696: */
697: #define SQLITE_OS2_NO_WAL_LOCK_FILE
698:
699: #if 0
700: static void _ERR_TRACE( const char *fmt, ... ) {
701: va_list ap;
702: va_start(ap, fmt);
703: vfprintf(stderr, fmt, ap);
704: fflush(stderr);
705: }
706: #define ERR_TRACE(rc, msg) \
707: if( (rc) != SQLITE_OK ) _ERR_TRACE msg;
708: #else
709: #define ERR_TRACE(rc, msg)
710: #endif
711:
712: /*
713: ** Helper functions to obtain and relinquish the global mutex. The
714: ** global mutex is used to protect os2ShmNodeList.
715: **
716: ** Function os2ShmMutexHeld() is used to assert() that the global mutex
717: ** is held when required. This function is only used as part of assert()
718: ** statements. e.g.
719: **
720: ** os2ShmEnterMutex()
721: ** assert( os2ShmMutexHeld() );
722: ** os2ShmLeaveMutex()
723: */
724: static void os2ShmEnterMutex(void){
725: sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
726: }
727: static void os2ShmLeaveMutex(void){
728: sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
729: }
730: #ifdef SQLITE_DEBUG
731: static int os2ShmMutexHeld(void) {
732: return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
733: }
734: int GetCurrentProcessId(void) {
735: PPIB pib;
736: DosGetInfoBlocks(NULL, &pib);
737: return (int)pib->pib_ulpid;
738: }
739: #endif
740:
741: /*
742: ** Object used to represent a the shared memory area for a single log file.
743: ** When multiple threads all reference the same log-summary, each thread has
744: ** its own os2File object, but they all point to a single instance of this
745: ** object. In other words, each log-summary is opened only once per process.
746: **
747: ** os2ShmMutexHeld() must be true when creating or destroying
748: ** this object or while reading or writing the following fields:
749: **
750: ** nRef
751: ** pNext
752: **
753: ** The following fields are read-only after the object is created:
754: **
755: ** szRegion
756: ** hLockFile
757: ** shmBaseName
758: **
759: ** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and
760: ** os2ShmMutexHeld() is true when reading or writing any other field
761: ** in this structure.
762: **
763: */
764: struct os2ShmNode {
765: sqlite3_mutex *mutex; /* Mutex to access this object */
766: os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */
767:
768: int szRegion; /* Size of shared-memory regions */
769:
770: int nRegion; /* Size of array apRegion */
771: void **apRegion; /* Array of pointers to shared-memory regions */
772:
773: int nRef; /* Number of os2ShmLink objects pointing to this */
774: os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */
775:
776: HFILE hLockFile; /* File used for inter-process memory locking */
777: char shmBaseName[1]; /* Name of the memory object !!! must last !!! */
778: };
779:
780:
781: /*
782: ** Structure used internally by this VFS to record the state of an
783: ** open shared memory connection.
784: **
785: ** The following fields are initialized when this object is created and
786: ** are read-only thereafter:
787: **
788: ** os2Shm.pShmNode
789: ** os2Shm.id
790: **
791: ** All other fields are read/write. The os2Shm.pShmNode->mutex must be held
792: ** while accessing any read/write fields.
793: */
794: struct os2ShmLink {
795: os2ShmNode *pShmNode; /* The underlying os2ShmNode object */
796: os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */
797: u32 sharedMask; /* Mask of shared locks held */
798: u32 exclMask; /* Mask of exclusive locks held */
799: #ifdef SQLITE_DEBUG
800: u8 id; /* Id of this connection with its os2ShmNode */
801: #endif
802: };
803:
804:
805: /*
806: ** A global list of all os2ShmNode objects.
807: **
808: ** The os2ShmMutexHeld() must be true while reading or writing this list.
809: */
810: static os2ShmNode *os2ShmNodeList = NULL;
811:
812: /*
813: ** Constants used for locking
814: */
815: #ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
816: #define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */
817: #else
818: #define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
819: #endif
820:
821: #define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
822:
823: /*
824: ** Apply advisory locks for all n bytes beginning at ofst.
825: */
826: #define _SHM_UNLCK 1 /* no lock */
827: #define _SHM_RDLCK 2 /* shared lock, no wait */
828: #define _SHM_WRLCK 3 /* exlusive lock, no wait */
829: #define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */
830: static int os2ShmSystemLock(
831: os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */
832: int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */
833: int ofst, /* Offset to first byte to be locked/unlocked */
834: int nByte /* Number of bytes to lock or unlock */
835: ){
836: APIRET rc;
837: FILELOCK area;
838: ULONG mode, timeout;
839:
840: /* Access to the os2ShmNode object is serialized by the caller */
841: assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 );
842:
843: mode = 1; /* shared lock */
844: timeout = 0; /* no wait */
845: area.lOffset = ofst;
846: area.lRange = nByte;
847:
848: switch( lockType ) {
849: case _SHM_WRLCK_WAIT:
850: timeout = (ULONG)-1; /* wait forever */
851: case _SHM_WRLCK:
852: mode = 0; /* exclusive lock */
853: case _SHM_RDLCK:
854: rc = DosSetFileLocks(pNode->hLockFile,
855: NULL, &area, timeout, mode);
856: break;
857: /* case _SHM_UNLCK: */
858: default:
859: rc = DosSetFileLocks(pNode->hLockFile,
860: &area, NULL, 0, 0);
861: break;
862: }
863:
864: OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
865: pNode->hLockFile,
866: rc==SQLITE_OK ? "ok" : "failed",
867: lockType==_SHM_UNLCK ? "Unlock" : "Lock",
868: rc));
869:
870: ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName))
871:
872: return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY;
873: }
874:
875: /*
876: ** Find an os2ShmNode in global list or allocate a new one, if not found.
877: **
878: ** This is not a VFS shared-memory method; it is a utility function called
879: ** by VFS shared-memory methods.
880: */
881: static int os2OpenSharedMemory( os2File *fd, int szRegion ) {
882: os2ShmLink *pLink;
883: os2ShmNode *pNode;
884: int cbShmName, rc = SQLITE_OK;
885: char shmName[CCHMAXPATH + 30];
886: #ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
887: ULONG action;
888: #endif
889:
890: /* We need some additional space at the end to append the region number */
891: cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp );
892: if( cbShmName >= CCHMAXPATH-8 )
893: return SQLITE_IOERR_SHMOPEN;
894:
895: /* Replace colon in file name to form a valid shared memory name */
896: shmName[10+1] = '!';
897:
898: /* Allocate link object (we free it later in case of failure) */
899: pLink = sqlite3_malloc( sizeof(*pLink) );
900: if( !pLink )
901: return SQLITE_NOMEM;
902:
903: /* Access node list */
904: os2ShmEnterMutex();
905:
906: /* Find node by it's shared memory base name */
907: for( pNode = os2ShmNodeList;
908: pNode && stricmp(shmName, pNode->shmBaseName) != 0;
909: pNode = pNode->pNext ) ;
910:
911: /* Not found: allocate a new node */
912: if( !pNode ) {
913: pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName );
914: if( pNode ) {
915: memset(pNode, 0, sizeof(*pNode) );
916: pNode->szRegion = szRegion;
917: pNode->hLockFile = (HFILE)-1;
918: strcpy(pNode->shmBaseName, shmName);
919:
920: #ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
921: if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) {
922: #else
923: sprintf(shmName, "%s-lck", fd->zFullPathCp);
924: if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL,
925: OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
926: OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE |
927: OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR,
928: NULL) != 0 ) {
929: #endif
930: sqlite3_free(pNode);
931: rc = SQLITE_IOERR;
932: } else {
933: pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
934: if( !pNode->mutex ) {
935: sqlite3_free(pNode);
936: rc = SQLITE_NOMEM;
937: }
938: }
939: } else {
940: rc = SQLITE_NOMEM;
941: }
942:
943: if( rc == SQLITE_OK ) {
944: pNode->pNext = os2ShmNodeList;
945: os2ShmNodeList = pNode;
946: } else {
947: pNode = NULL;
948: }
949: } else if( pNode->szRegion != szRegion ) {
950: rc = SQLITE_IOERR_SHMSIZE;
951: pNode = NULL;
952: }
953:
954: if( pNode ) {
955: sqlite3_mutex_enter(pNode->mutex);
956:
957: memset(pLink, 0, sizeof(*pLink));
958:
959: pLink->pShmNode = pNode;
960: pLink->pNext = pNode->pFirst;
961: pNode->pFirst = pLink;
962: pNode->nRef++;
963:
964: fd->pShmLink = pLink;
965:
966: sqlite3_mutex_leave(pNode->mutex);
967:
968: } else {
969: /* Error occured. Free our link object. */
970: sqlite3_free(pLink);
971: }
972:
973: os2ShmLeaveMutex();
974:
975: ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp))
976:
977: return rc;
978: }
979:
980: /*
981: ** Purge the os2ShmNodeList list of all entries with nRef==0.
982: **
983: ** This is not a VFS shared-memory method; it is a utility function called
984: ** by VFS shared-memory methods.
985: */
986: static void os2PurgeShmNodes( int deleteFlag ) {
987: os2ShmNode *pNode;
988: os2ShmNode **ppNode;
989:
990: os2ShmEnterMutex();
991:
992: ppNode = &os2ShmNodeList;
993:
994: while( *ppNode ) {
995: pNode = *ppNode;
996:
997: if( pNode->nRef == 0 ) {
998: *ppNode = pNode->pNext;
999:
1000: if( pNode->apRegion ) {
1001: /* Prevent other processes from resizing the shared memory */
1002: os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);
1003:
1004: while( pNode->nRegion-- ) {
1005: #ifdef SQLITE_DEBUG
1006: int rc =
1007: #endif
1008: DosFreeMem(pNode->apRegion[pNode->nRegion]);
1009:
1010: OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
1011: (int)GetCurrentProcessId(), pNode->nRegion,
1012: rc == 0 ? "ok" : "failed"));
1013: }
1014:
1015: /* Allow other processes to resize the shared memory */
1016: os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
1017:
1018: sqlite3_free(pNode->apRegion);
1019: }
1020:
1021: DosClose(pNode->hLockFile);
1022:
1023: #ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
1024: if( deleteFlag ) {
1025: char fileName[CCHMAXPATH];
1026: /* Skip "\\SHAREMEM\\" */
1027: sprintf(fileName, "%s-lck", pNode->shmBaseName + 10);
1028: /* restore colon */
1029: fileName[1] = ':';
1030:
1031: DosForceDelete(fileName);
1032: }
1033: #endif
1034:
1035: sqlite3_mutex_free(pNode->mutex);
1036:
1037: sqlite3_free(pNode);
1038:
1039: } else {
1040: ppNode = &pNode->pNext;
1041: }
1042: }
1043:
1044: os2ShmLeaveMutex();
1045: }
1046:
1047: /*
1048: ** This function is called to obtain a pointer to region iRegion of the
1049: ** shared-memory associated with the database file id. Shared-memory regions
1050: ** are numbered starting from zero. Each shared-memory region is szRegion
1051: ** bytes in size.
1052: **
1053: ** If an error occurs, an error code is returned and *pp is set to NULL.
1054: **
1055: ** Otherwise, if the bExtend parameter is 0 and the requested shared-memory
1056: ** region has not been allocated (by any client, including one running in a
1057: ** separate process), then *pp is set to NULL and SQLITE_OK returned. If
1058: ** bExtend is non-zero and the requested shared-memory region has not yet
1059: ** been allocated, it is allocated by this function.
1060: **
1061: ** If the shared-memory region has already been allocated or is allocated by
1062: ** this call as described above, then it is mapped into this processes
1063: ** address space (if it is not already), *pp is set to point to the mapped
1064: ** memory and SQLITE_OK returned.
1065: */
1066: static int os2ShmMap(
1067: sqlite3_file *id, /* Handle open on database file */
1068: int iRegion, /* Region to retrieve */
1069: int szRegion, /* Size of regions */
1070: int bExtend, /* True to extend block if necessary */
1071: void volatile **pp /* OUT: Mapped memory */
1072: ){
1073: PVOID pvTemp;
1074: void **apRegion;
1075: os2ShmNode *pNode;
1076: int n, rc = SQLITE_OK;
1077: char shmName[CCHMAXPATH];
1078: os2File *pFile = (os2File*)id;
1079:
1080: *pp = NULL;
1081:
1082: if( !pFile->pShmLink )
1083: rc = os2OpenSharedMemory( pFile, szRegion );
1084:
1085: if( rc == SQLITE_OK ) {
1086: pNode = pFile->pShmLink->pShmNode ;
1087:
1088: sqlite3_mutex_enter(pNode->mutex);
1089:
1090: assert( szRegion==pNode->szRegion );
1091:
1092: /* Unmapped region ? */
1093: if( iRegion >= pNode->nRegion ) {
1094: /* Prevent other processes from resizing the shared memory */
1095: os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);
1096:
1097: apRegion = sqlite3_realloc(
1098: pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0]));
1099:
1100: if( apRegion ) {
1101: pNode->apRegion = apRegion;
1102:
1103: while( pNode->nRegion <= iRegion ) {
1104: sprintf(shmName, "%s-%u",
1105: pNode->shmBaseName, pNode->nRegion);
1106:
1107: if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName,
1108: PAG_READ | PAG_WRITE) != NO_ERROR ) {
1109: if( !bExtend )
1110: break;
1111:
1112: if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
1113: PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR &&
1114: DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
1115: PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) {
1116: rc = SQLITE_NOMEM;
1117: break;
1118: }
1119: }
1120:
1121: apRegion[pNode->nRegion++] = pvTemp;
1122: }
1123:
1124: /* zero out remaining entries */
1125: for( n = pNode->nRegion; n <= iRegion; n++ )
1126: pNode->apRegion[n] = NULL;
1127:
1128: /* Return this region (maybe zero) */
1129: *pp = pNode->apRegion[iRegion];
1130: } else {
1131: rc = SQLITE_NOMEM;
1132: }
1133:
1134: /* Allow other processes to resize the shared memory */
1135: os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
1136:
1137: } else {
1138: /* Region has been mapped previously */
1139: *pp = pNode->apRegion[iRegion];
1140: }
1141:
1142: sqlite3_mutex_leave(pNode->mutex);
1143: }
1144:
1145: ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n",
1146: pFile->zFullPathCp, iRegion, szRegion, bExtend, rc))
1147:
1148: return rc;
1149: }
1150:
1151: /*
1152: ** Close a connection to shared-memory. Delete the underlying
1153: ** storage if deleteFlag is true.
1154: **
1155: ** If there is no shared memory associated with the connection then this
1156: ** routine is a harmless no-op.
1157: */
1158: static int os2ShmUnmap(
1159: sqlite3_file *id, /* The underlying database file */
1160: int deleteFlag /* Delete shared-memory if true */
1161: ){
1162: os2File *pFile = (os2File*)id;
1163: os2ShmLink *pLink = pFile->pShmLink;
1164:
1165: if( pLink ) {
1166: int nRef = -1;
1167: os2ShmLink **ppLink;
1168: os2ShmNode *pNode = pLink->pShmNode;
1169:
1170: sqlite3_mutex_enter(pNode->mutex);
1171:
1172: for( ppLink = &pNode->pFirst;
1173: *ppLink && *ppLink != pLink;
1174: ppLink = &(*ppLink)->pNext ) ;
1175:
1176: assert(*ppLink);
1177:
1178: if( *ppLink ) {
1179: *ppLink = pLink->pNext;
1180: nRef = --pNode->nRef;
1181: } else {
1182: ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n",
1183: pNode->shmBaseName))
1184: }
1185:
1186: pFile->pShmLink = NULL;
1187: sqlite3_free(pLink);
1188:
1189: sqlite3_mutex_leave(pNode->mutex);
1190:
1191: if( nRef == 0 )
1192: os2PurgeShmNodes( deleteFlag );
1193: }
1194:
1195: return SQLITE_OK;
1196: }
1197:
1198: /*
1199: ** Change the lock state for a shared-memory segment.
1200: **
1201: ** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
1202: ** different here than in posix. In xShmLock(), one can go from unlocked
1203: ** to shared and back or from unlocked to exclusive and back. But one may
1204: ** not go from shared to exclusive or from exclusive to shared.
1205: */
1206: static int os2ShmLock(
1207: sqlite3_file *id, /* Database file holding the shared memory */
1208: int ofst, /* First lock to acquire or release */
1209: int n, /* Number of locks to acquire or release */
1210: int flags /* What to do with the lock */
1211: ){
1212: u32 mask; /* Mask of locks to take or release */
1213: int rc = SQLITE_OK; /* Result code */
1214: os2File *pFile = (os2File*)id;
1215: os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */
1216: os2ShmLink *pX; /* For looping over all siblings */
1217: os2ShmNode *pShmNode = p->pShmNode; /* Our node */
1218:
1219: assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
1220: assert( n>=1 );
1221: assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
1222: || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
1223: || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
1224: || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
1225: assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
1226:
1227: mask = (u32)((1U<<(ofst+n)) - (1U<<ofst));
1228: assert( n>1 || mask==(1<<ofst) );
1229:
1230:
1231: sqlite3_mutex_enter(pShmNode->mutex);
1232:
1233: if( flags & SQLITE_SHM_UNLOCK ){
1234: u32 allMask = 0; /* Mask of locks held by siblings */
1235:
1236: /* See if any siblings hold this same lock */
1237: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
1238: if( pX==p ) continue;
1239: assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
1240: allMask |= pX->sharedMask;
1241: }
1242:
1243: /* Unlock the system-level locks */
1244: if( (mask & allMask)==0 ){
1245: rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n);
1246: }else{
1247: rc = SQLITE_OK;
1248: }
1249:
1250: /* Undo the local locks */
1251: if( rc==SQLITE_OK ){
1252: p->exclMask &= ~mask;
1253: p->sharedMask &= ~mask;
1254: }
1255: }else if( flags & SQLITE_SHM_SHARED ){
1256: u32 allShared = 0; /* Union of locks held by connections other than "p" */
1257:
1258: /* Find out which shared locks are already held by sibling connections.
1259: ** If any sibling already holds an exclusive lock, go ahead and return
1260: ** SQLITE_BUSY.
1261: */
1262: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
1263: if( (pX->exclMask & mask)!=0 ){
1264: rc = SQLITE_BUSY;
1265: break;
1266: }
1267: allShared |= pX->sharedMask;
1268: }
1269:
1270: /* Get shared locks at the system level, if necessary */
1271: if( rc==SQLITE_OK ){
1272: if( (allShared & mask)==0 ){
1273: rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n);
1274: }else{
1275: rc = SQLITE_OK;
1276: }
1277: }
1278:
1279: /* Get the local shared locks */
1280: if( rc==SQLITE_OK ){
1281: p->sharedMask |= mask;
1282: }
1283: }else{
1284: /* Make sure no sibling connections hold locks that will block this
1285: ** lock. If any do, return SQLITE_BUSY right away.
1286: */
1287: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
1288: if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
1289: rc = SQLITE_BUSY;
1290: break;
1291: }
1292: }
1293:
1294: /* Get the exclusive locks at the system level. Then if successful
1295: ** also mark the local connection as being locked.
1296: */
1297: if( rc==SQLITE_OK ){
1298: rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n);
1299: if( rc==SQLITE_OK ){
1300: assert( (p->sharedMask & mask)==0 );
1301: p->exclMask |= mask;
1302: }
1303: }
1304: }
1305:
1306: sqlite3_mutex_leave(pShmNode->mutex);
1307:
1308: OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
1309: p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
1310: rc ? "failed" : "ok"));
1311:
1312: ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n",
1313: ofst, n, flags, rc))
1314:
1315: return rc;
1316: }
1317:
1318: /*
1319: ** Implement a memory barrier or memory fence on shared memory.
1320: **
1321: ** All loads and stores begun before the barrier must complete before
1322: ** any load or store begun after the barrier.
1323: */
1324: static void os2ShmBarrier(
1325: sqlite3_file *id /* Database file holding the shared memory */
1326: ){
1327: UNUSED_PARAMETER(id);
1328: os2ShmEnterMutex();
1329: os2ShmLeaveMutex();
1330: }
1331:
1332: #else
1333: # define os2ShmMap 0
1334: # define os2ShmLock 0
1335: # define os2ShmBarrier 0
1336: # define os2ShmUnmap 0
1337: #endif /* #ifndef SQLITE_OMIT_WAL */
1338:
1339:
1340: /*
1341: ** This vector defines all the methods that can operate on an
1342: ** sqlite3_file for os2.
1343: */
1344: static const sqlite3_io_methods os2IoMethod = {
1345: 2, /* iVersion */
1346: os2Close, /* xClose */
1347: os2Read, /* xRead */
1348: os2Write, /* xWrite */
1349: os2Truncate, /* xTruncate */
1350: os2Sync, /* xSync */
1351: os2FileSize, /* xFileSize */
1352: os2Lock, /* xLock */
1353: os2Unlock, /* xUnlock */
1354: os2CheckReservedLock, /* xCheckReservedLock */
1355: os2FileControl, /* xFileControl */
1356: os2SectorSize, /* xSectorSize */
1357: os2DeviceCharacteristics, /* xDeviceCharacteristics */
1358: os2ShmMap, /* xShmMap */
1359: os2ShmLock, /* xShmLock */
1360: os2ShmBarrier, /* xShmBarrier */
1361: os2ShmUnmap /* xShmUnmap */
1362: };
1363:
1364:
1365: /***************************************************************************
1366: ** Here ends the I/O methods that form the sqlite3_io_methods object.
1367: **
1368: ** The next block of code implements the VFS methods.
1369: ****************************************************************************/
1370:
1371: /*
1372: ** Create a temporary file name in zBuf. zBuf must be big enough to
1373: ** hold at pVfs->mxPathname characters.
1374: */
1375: static int getTempname(int nBuf, char *zBuf ){
1376: static const char zChars[] =
1377: "abcdefghijklmnopqrstuvwxyz"
1378: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1379: "0123456789";
1380: int i, j;
1381: PSZ zTempPathCp;
1382: char zTempPath[CCHMAXPATH];
1383: ULONG ulDriveNum, ulDriveMap;
1384:
1385: /* It's odd to simulate an io-error here, but really this is just
1386: ** using the io-error infrastructure to test that SQLite handles this
1387: ** function failing.
1388: */
1389: SimulateIOError( return SQLITE_IOERR );
1390:
1391: if( sqlite3_temp_directory ) {
1392: sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory);
1393: } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR ||
1394: DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR ||
1395: DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) {
1396: char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp );
1397: sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF);
1398: free( zTempPathUTF );
1399: } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) {
1400: zTempPath[0] = (char)('A' + ulDriveNum - 1);
1401: zTempPath[1] = ':';
1402: zTempPath[2] = '\0';
1403: } else {
1404: zTempPath[0] = '\0';
1405: }
1406:
1407: /* Strip off a trailing slashes or backslashes, otherwise we would get *
1408: * multiple (back)slashes which causes DosOpen() to fail. *
1409: * Trailing spaces are not allowed, either. */
1410: j = sqlite3Strlen30(zTempPath);
1411: while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' ||
1412: zTempPath[j-1] == ' ' ) ){
1413: j--;
1414: }
1415: zTempPath[j] = '\0';
1416:
1417: /* We use 20 bytes to randomize the name */
1418: sqlite3_snprintf(nBuf-22, zBuf,
1419: "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
1420: j = sqlite3Strlen30(zBuf);
1421: sqlite3_randomness( 20, &zBuf[j] );
1422: for( i = 0; i < 20; i++, j++ ){
1423: zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
1424: }
1425: zBuf[j] = 0;
1426:
1427: OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
1428: return SQLITE_OK;
1429: }
1430:
1431:
1432: /*
1433: ** Turn a relative pathname into a full pathname. Write the full
1434: ** pathname into zFull[]. zFull[] will be at least pVfs->mxPathname
1435: ** bytes in size.
1436: */
1437: static int os2FullPathname(
1438: sqlite3_vfs *pVfs, /* Pointer to vfs object */
1439: const char *zRelative, /* Possibly relative input path */
1440: int nFull, /* Size of output buffer in bytes */
1441: char *zFull /* Output buffer */
1442: ){
1443: char *zRelativeCp = convertUtf8PathToCp( zRelative );
1444: char zFullCp[CCHMAXPATH] = "\0";
1445: char *zFullUTF;
1446: APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME,
1447: zFullCp, CCHMAXPATH );
1448: free( zRelativeCp );
1449: zFullUTF = convertCpPathToUtf8( zFullCp );
1450: sqlite3_snprintf( nFull, zFull, zFullUTF );
1451: free( zFullUTF );
1452: return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
1453: }
1454:
1455:
1456: /*
1457: ** Open a file.
1458: */
1459: static int os2Open(
1460: sqlite3_vfs *pVfs, /* Not used */
1461: const char *zName, /* Name of the file (UTF-8) */
1462: sqlite3_file *id, /* Write the SQLite file handle here */
1463: int flags, /* Open mode flags */
1464: int *pOutFlags /* Status return flags */
1465: ){
1466: HFILE h;
1467: ULONG ulOpenFlags = 0;
1468: ULONG ulOpenMode = 0;
1469: ULONG ulAction = 0;
1470: ULONG rc;
1471: os2File *pFile = (os2File*)id;
1472: const char *zUtf8Name = zName;
1473: char *zNameCp;
1474: char zTmpname[CCHMAXPATH];
1475:
1476: int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
1477: int isCreate = (flags & SQLITE_OPEN_CREATE);
1478: int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
1479: #ifndef NDEBUG
1480: int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
1481: int isReadonly = (flags & SQLITE_OPEN_READONLY);
1482: int eType = (flags & 0xFFFFFF00);
1483: int isOpenJournal = (isCreate && (
1484: eType==SQLITE_OPEN_MASTER_JOURNAL
1485: || eType==SQLITE_OPEN_MAIN_JOURNAL
1486: || eType==SQLITE_OPEN_WAL
1487: ));
1488: #endif
1489:
1490: UNUSED_PARAMETER(pVfs);
1491: assert( id!=0 );
1492:
1493: /* Check the following statements are true:
1494: **
1495: ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
1496: ** (b) if CREATE is set, then READWRITE must also be set, and
1497: ** (c) if EXCLUSIVE is set, then CREATE must also be set.
1498: ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
1499: */
1500: assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
1501: assert(isCreate==0 || isReadWrite);
1502: assert(isExclusive==0 || isCreate);
1503: assert(isDelete==0 || isCreate);
1504:
1505: /* The main DB, main journal, WAL file and master journal are never
1506: ** automatically deleted. Nor are they ever temporary files. */
1507: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
1508: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
1509: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
1510: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
1511:
1512: /* Assert that the upper layer has set one of the "file-type" flags. */
1513: assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
1514: || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
1515: || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
1516: || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
1517: );
1518:
1519: memset( pFile, 0, sizeof(*pFile) );
1520: pFile->h = (HFILE)-1;
1521:
1522: /* If the second argument to this function is NULL, generate a
1523: ** temporary file name to use
1524: */
1525: if( !zUtf8Name ){
1526: assert(isDelete && !isOpenJournal);
1527: rc = getTempname(CCHMAXPATH, zTmpname);
1528: if( rc!=SQLITE_OK ){
1529: return rc;
1530: }
1531: zUtf8Name = zTmpname;
1532: }
1533:
1534: if( isReadWrite ){
1535: ulOpenMode |= OPEN_ACCESS_READWRITE;
1536: }else{
1537: ulOpenMode |= OPEN_ACCESS_READONLY;
1538: }
1539:
1540: /* Open in random access mode for possibly better speed. Allow full
1541: ** sharing because file locks will provide exclusive access when needed.
1542: ** The handle should not be inherited by child processes and we don't
1543: ** want popups from the critical error handler.
1544: */
1545: ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE |
1546: OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR;
1547:
1548: /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
1549: ** created. SQLite doesn't use it to indicate "exclusive access"
1550: ** as it is usually understood.
1551: */
1552: if( isExclusive ){
1553: /* Creates a new file, only if it does not already exist. */
1554: /* If the file exists, it fails. */
1555: ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
1556: }else if( isCreate ){
1557: /* Open existing file, or create if it doesn't exist */
1558: ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
1559: }else{
1560: /* Opens a file, only if it exists. */
1561: ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
1562: }
1563:
1564: zNameCp = convertUtf8PathToCp( zUtf8Name );
1565: rc = DosOpen( (PSZ)zNameCp,
1566: &h,
1567: &ulAction,
1568: 0L,
1569: FILE_NORMAL,
1570: ulOpenFlags,
1571: ulOpenMode,
1572: (PEAOP2)NULL );
1573: free( zNameCp );
1574:
1575: if( rc != NO_ERROR ){
1576: OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
1577: rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
1578:
1579: if( isReadWrite ){
1580: return os2Open( pVfs, zName, id,
1581: ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
1582: pOutFlags );
1583: }else{
1584: return SQLITE_CANTOPEN;
1585: }
1586: }
1587:
1588: if( pOutFlags ){
1589: *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
1590: }
1591:
1592: os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname );
1593: pFile->zFullPathCp = convertUtf8PathToCp( zTmpname );
1594: pFile->pMethod = &os2IoMethod;
1595: pFile->flags = flags;
1596: pFile->h = h;
1597:
1598: OpenCounter(+1);
1599: OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
1600: return SQLITE_OK;
1601: }
1602:
1603: /*
1604: ** Delete the named file.
1605: */
1606: static int os2Delete(
1607: sqlite3_vfs *pVfs, /* Not used on os2 */
1608: const char *zFilename, /* Name of file to delete */
1609: int syncDir /* Not used on os2 */
1610: ){
1611: APIRET rc;
1612: char *zFilenameCp;
1613: SimulateIOError( return SQLITE_IOERR_DELETE );
1614: zFilenameCp = convertUtf8PathToCp( zFilename );
1615: rc = DosDelete( (PSZ)zFilenameCp );
1616: free( zFilenameCp );
1617: OSTRACE(( "DELETE \"%s\"\n", zFilename ));
1618: return (rc == NO_ERROR ||
1619: rc == ERROR_FILE_NOT_FOUND ||
1620: rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
1621: }
1622:
1623: /*
1624: ** Check the existance and status of a file.
1625: */
1626: static int os2Access(
1627: sqlite3_vfs *pVfs, /* Not used on os2 */
1628: const char *zFilename, /* Name of file to check */
1629: int flags, /* Type of test to make on this file */
1630: int *pOut /* Write results here */
1631: ){
1632: APIRET rc;
1633: FILESTATUS3 fsts3ConfigInfo;
1634: char *zFilenameCp;
1635:
1636: UNUSED_PARAMETER(pVfs);
1637: SimulateIOError( return SQLITE_IOERR_ACCESS; );
1638:
1639: zFilenameCp = convertUtf8PathToCp( zFilename );
1640: rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
1641: &fsts3ConfigInfo, sizeof(FILESTATUS3) );
1642: free( zFilenameCp );
1643: OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
1644: fsts3ConfigInfo.attrFile, flags, rc ));
1645:
1646: switch( flags ){
1647: case SQLITE_ACCESS_EXISTS:
1648: /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
1649: ** as if it does not exist.
1650: */
1651: if( fsts3ConfigInfo.cbFile == 0 )
1652: rc = ERROR_FILE_NOT_FOUND;
1653: break;
1654: case SQLITE_ACCESS_READ:
1655: break;
1656: case SQLITE_ACCESS_READWRITE:
1657: if( fsts3ConfigInfo.attrFile & FILE_READONLY )
1658: rc = ERROR_ACCESS_DENIED;
1659: break;
1660: default:
1661: rc = ERROR_FILE_NOT_FOUND;
1662: assert( !"Invalid flags argument" );
1663: }
1664:
1665: *pOut = (rc == NO_ERROR);
1666: OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut ));
1667:
1668: return SQLITE_OK;
1669: }
1670:
1671:
1672: #ifndef SQLITE_OMIT_LOAD_EXTENSION
1673: /*
1674: ** Interfaces for opening a shared library, finding entry points
1675: ** within the shared library, and closing the shared library.
1676: */
1677: /*
1678: ** Interfaces for opening a shared library, finding entry points
1679: ** within the shared library, and closing the shared library.
1680: */
1681: static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
1682: HMODULE hmod;
1683: APIRET rc;
1684: char *zFilenameCp = convertUtf8PathToCp(zFilename);
1685: rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod);
1686: free(zFilenameCp);
1687: return rc != NO_ERROR ? 0 : (void*)hmod;
1688: }
1689: /*
1690: ** A no-op since the error code is returned on the DosLoadModule call.
1691: ** os2Dlopen returns zero if DosLoadModule is not successful.
1692: */
1693: static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
1694: /* no-op */
1695: }
1696: static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
1697: PFN pfn;
1698: APIRET rc;
1699: rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn);
1700: if( rc != NO_ERROR ){
1701: /* if the symbol itself was not found, search again for the same
1702: * symbol with an extra underscore, that might be needed depending
1703: * on the calling convention */
1704: char _zSymbol[256] = "_";
1705: strncat(_zSymbol, zSymbol, 254);
1706: rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn);
1707: }
1708: return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
1709: }
1710: static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
1711: DosFreeModule((HMODULE)pHandle);
1712: }
1713: #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
1714: #define os2DlOpen 0
1715: #define os2DlError 0
1716: #define os2DlSym 0
1717: #define os2DlClose 0
1718: #endif
1719:
1720:
1721: /*
1722: ** Write up to nBuf bytes of randomness into zBuf.
1723: */
1724: static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
1725: int n = 0;
1726: #if defined(SQLITE_TEST)
1727: n = nBuf;
1728: memset(zBuf, 0, nBuf);
1729: #else
1730: int i;
1731: PPIB ppib;
1732: PTIB ptib;
1733: DATETIME dt;
1734: static unsigned c = 0;
1735: /* Ordered by variation probability */
1736: static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW,
1737: QSV_MAXPRMEM, QSV_MAXSHMEM,
1738: QSV_TOTAVAILMEM, QSV_TOTRESMEM };
1739:
1740: /* 8 bytes; timezone and weekday don't increase the randomness much */
1741: if( (int)sizeof(dt)-3 <= nBuf - n ){
1742: c += 0x0100;
1743: DosGetDateTime(&dt);
1744: dt.year = (USHORT)((dt.year - 1900) | c);
1745: memcpy(&zBuf[n], &dt, sizeof(dt)-3);
1746: n += sizeof(dt)-3;
1747: }
1748:
1749: /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */
1750: if( (int)sizeof(ULONG) <= nBuf - n ){
1751: DosGetInfoBlocks(&ptib, &ppib);
1752: *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid,
1753: ptib->tib_ptib2->tib2_ultid);
1754: n += sizeof(ULONG);
1755: }
1756:
1757: /* Up to 6 * 4 bytes; variables depend on the system state */
1758: for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){
1759: DosQuerySysInfo(svIdx[i], svIdx[i],
1760: (PULONG)&zBuf[n], sizeof(ULONG));
1761: n += sizeof(ULONG);
1762: }
1763: #endif
1764:
1765: return n;
1766: }
1767:
1768: /*
1769: ** Sleep for a little while. Return the amount of time slept.
1770: ** The argument is the number of microseconds we want to sleep.
1771: ** The return value is the number of microseconds of sleep actually
1772: ** requested from the underlying operating system, a number which
1773: ** might be greater than or equal to the argument, but not less
1774: ** than the argument.
1775: */
1776: static int os2Sleep( sqlite3_vfs *pVfs, int microsec ){
1777: DosSleep( (microsec/1000) );
1778: return microsec;
1779: }
1780:
1781: /*
1782: ** The following variable, if set to a non-zero value, becomes the result
1783: ** returned from sqlite3OsCurrentTime(). This is used for testing.
1784: */
1785: #ifdef SQLITE_TEST
1786: int sqlite3_current_time = 0;
1787: #endif
1788:
1789: /*
1790: ** Find the current time (in Universal Coordinated Time). Write into *piNow
1791: ** the current time and date as a Julian Day number times 86_400_000. In
1792: ** other words, write into *piNow the number of milliseconds since the Julian
1793: ** epoch of noon in Greenwich on November 24, 4714 B.C according to the
1794: ** proleptic Gregorian calendar.
1795: **
1796: ** On success, return 0. Return 1 if the time and date cannot be found.
1797: */
1798: static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
1799: #ifdef SQLITE_TEST
1800: static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
1801: #endif
1802: int year, month, datepart, timepart;
1803:
1804: DATETIME dt;
1805: DosGetDateTime( &dt );
1806:
1807: year = dt.year;
1808: month = dt.month;
1809:
1810: /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
1811: ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c
1812: ** Calculate the Julian days
1813: */
1814: datepart = (int)dt.day - 32076 +
1815: 1461*(year + 4800 + (month - 14)/12)/4 +
1816: 367*(month - 2 - (month - 14)/12*12)/12 -
1817: 3*((year + 4900 + (month - 14)/12)/100)/4;
1818:
1819: /* Time in milliseconds, hours to noon added */
1820: timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 +
1821: ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000;
1822:
1823: *piNow = (sqlite3_int64)datepart*86400*1000 + timepart;
1824:
1825: #ifdef SQLITE_TEST
1826: if( sqlite3_current_time ){
1827: *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
1828: }
1829: #endif
1830:
1831: UNUSED_PARAMETER(pVfs);
1832: return 0;
1833: }
1834:
1835: /*
1836: ** Find the current time (in Universal Coordinated Time). Write the
1837: ** current time and date as a Julian Day number into *prNow and
1838: ** return 0. Return 1 if the time and date cannot be found.
1839: */
1840: static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
1841: int rc;
1842: sqlite3_int64 i;
1843: rc = os2CurrentTimeInt64(pVfs, &i);
1844: if( !rc ){
1845: *prNow = i/86400000.0;
1846: }
1847: return rc;
1848: }
1849:
1850: /*
1851: ** The idea is that this function works like a combination of
1852: ** GetLastError() and FormatMessage() on windows (or errno and
1853: ** strerror_r() on unix). After an error is returned by an OS
1854: ** function, SQLite calls this function with zBuf pointing to
1855: ** a buffer of nBuf bytes. The OS layer should populate the
1856: ** buffer with a nul-terminated UTF-8 encoded error message
1857: ** describing the last IO error to have occurred within the calling
1858: ** thread.
1859: **
1860: ** If the error message is too large for the supplied buffer,
1861: ** it should be truncated. The return value of xGetLastError
1862: ** is zero if the error message fits in the buffer, or non-zero
1863: ** otherwise (if the message was truncated). If non-zero is returned,
1864: ** then it is not necessary to include the nul-terminator character
1865: ** in the output buffer.
1866: **
1867: ** Not supplying an error message will have no adverse effect
1868: ** on SQLite. It is fine to have an implementation that never
1869: ** returns an error message:
1870: **
1871: ** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
1872: ** assert(zBuf[0]=='\0');
1873: ** return 0;
1874: ** }
1875: **
1876: ** However if an error message is supplied, it will be incorporated
1877: ** by sqlite into the error message available to the user using
1878: ** sqlite3_errmsg(), possibly making IO errors easier to debug.
1879: */
1880: static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
1881: assert(zBuf[0]=='\0');
1882: return 0;
1883: }
1884:
1885: /*
1886: ** Initialize and deinitialize the operating system interface.
1887: */
1888: int sqlite3_os_init(void){
1889: static sqlite3_vfs os2Vfs = {
1890: 3, /* iVersion */
1891: sizeof(os2File), /* szOsFile */
1892: CCHMAXPATH, /* mxPathname */
1893: 0, /* pNext */
1894: "os2", /* zName */
1895: 0, /* pAppData */
1896:
1897: os2Open, /* xOpen */
1898: os2Delete, /* xDelete */
1899: os2Access, /* xAccess */
1900: os2FullPathname, /* xFullPathname */
1901: os2DlOpen, /* xDlOpen */
1902: os2DlError, /* xDlError */
1903: os2DlSym, /* xDlSym */
1904: os2DlClose, /* xDlClose */
1905: os2Randomness, /* xRandomness */
1906: os2Sleep, /* xSleep */
1907: os2CurrentTime, /* xCurrentTime */
1908: os2GetLastError, /* xGetLastError */
1909: os2CurrentTimeInt64, /* xCurrentTimeInt64 */
1910: 0, /* xSetSystemCall */
1911: 0, /* xGetSystemCall */
1912: 0 /* xNextSystemCall */
1913: };
1914: sqlite3_vfs_register(&os2Vfs, 1);
1915: initUconvObjects();
1916: /* sqlite3OSTrace = 1; */
1917: return SQLITE_OK;
1918: }
1919: int sqlite3_os_end(void){
1920: freeUconvObjects();
1921: return SQLITE_OK;
1922: }
1923:
1924: #endif /* SQLITE_OS_OS2 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>