|
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 #include "sqliteInt.h" |
|
16 #include "os.h" |
|
17 |
|
18 #if OS_OS2 |
|
19 |
|
20 /* |
|
21 ** Macros used to determine whether or not to use threads. |
|
22 */ |
|
23 #if defined(THREADSAFE) && THREADSAFE |
|
24 # define SQLITE_OS2_THREADS 1 |
|
25 #endif |
|
26 |
|
27 /* |
|
28 ** Include code that is common to all os_*.c files |
|
29 */ |
|
30 #include "os_common.h" |
|
31 |
|
32 /* |
|
33 ** The os2File structure is subclass of OsFile specific for the OS/2 |
|
34 ** protability layer. |
|
35 */ |
|
36 typedef struct os2File os2File; |
|
37 struct os2File { |
|
38 IoMethod const *pMethod; /* Always the first entry */ |
|
39 HFILE h; /* Handle for accessing the file */ |
|
40 int delOnClose; /* True if file is to be deleted on close */ |
|
41 char* pathToDel; /* Name of file to delete on close */ |
|
42 unsigned char locktype; /* Type of lock currently held on this file */ |
|
43 }; |
|
44 |
|
45 /* |
|
46 ** Do not include any of the File I/O interface procedures if the |
|
47 ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database |
|
48 ** will be in-memory only) |
|
49 */ |
|
50 #ifndef SQLITE_OMIT_DISKIO |
|
51 |
|
52 /* |
|
53 ** Delete the named file |
|
54 */ |
|
55 int sqlite3Os2Delete( const char *zFilename ){ |
|
56 APIRET rc = NO_ERROR; |
|
57 |
|
58 rc = DosDelete( (PSZ)zFilename ); |
|
59 TRACE2( "DELETE \"%s\"\n", zFilename ); |
|
60 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
61 } |
|
62 |
|
63 /* |
|
64 ** Return TRUE if the named file exists. |
|
65 */ |
|
66 int sqlite3Os2FileExists( const char *zFilename ){ |
|
67 FILESTATUS3 fsts3ConfigInfo; |
|
68 memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); |
|
69 return DosQueryPathInfo( (PSZ)zFilename, FIL_STANDARD, |
|
70 &fsts3ConfigInfo, sizeof(FILESTATUS3) ) == NO_ERROR; |
|
71 } |
|
72 |
|
73 /* Forward declaration */ |
|
74 int allocateOs2File( os2File *pInit, OsFile **pld ); |
|
75 |
|
76 /* |
|
77 ** Attempt to open a file for both reading and writing. If that |
|
78 ** fails, try opening it read-only. If the file does not exist, |
|
79 ** try to create it. |
|
80 ** |
|
81 ** On success, a handle for the open file is written to *id |
|
82 ** and *pReadonly is set to 0 if the file was opened for reading and |
|
83 ** writing or 1 if the file was opened read-only. The function returns |
|
84 ** SQLITE_OK. |
|
85 ** |
|
86 ** On failure, the function returns SQLITE_CANTOPEN and leaves |
|
87 ** *id and *pReadonly unchanged. |
|
88 */ |
|
89 int sqlite3Os2OpenReadWrite( |
|
90 const char *zFilename, |
|
91 OsFile **pld, |
|
92 int *pReadonly |
|
93 ){ |
|
94 os2File f; |
|
95 HFILE hf; |
|
96 ULONG ulAction; |
|
97 APIRET rc = NO_ERROR; |
|
98 |
|
99 assert( *pld == 0 ); |
|
100 rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, |
|
101 FILE_ARCHIVED | FILE_NORMAL, |
|
102 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, |
|
103 OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | |
|
104 OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); |
|
105 if( rc != NO_ERROR ){ |
|
106 rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, |
|
107 FILE_ARCHIVED | FILE_NORMAL, |
|
108 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, |
|
109 OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | |
|
110 OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); |
|
111 if( rc != NO_ERROR ){ |
|
112 return SQLITE_CANTOPEN; |
|
113 } |
|
114 *pReadonly = 1; |
|
115 } |
|
116 else{ |
|
117 *pReadonly = 0; |
|
118 } |
|
119 f.h = hf; |
|
120 f.locktype = NO_LOCK; |
|
121 f.delOnClose = 0; |
|
122 f.pathToDel = NULL; |
|
123 OpenCounter(+1); |
|
124 TRACE3( "OPEN R/W %d \"%s\"\n", hf, zFilename ); |
|
125 return allocateOs2File( &f, pld ); |
|
126 } |
|
127 |
|
128 |
|
129 /* |
|
130 ** Attempt to open a new file for exclusive access by this process. |
|
131 ** The file will be opened for both reading and writing. To avoid |
|
132 ** a potential security problem, we do not allow the file to have |
|
133 ** previously existed. Nor do we allow the file to be a symbolic |
|
134 ** link. |
|
135 ** |
|
136 ** If delFlag is true, then make arrangements to automatically delete |
|
137 ** the file when it is closed. |
|
138 ** |
|
139 ** On success, write the file handle into *id and return SQLITE_OK. |
|
140 ** |
|
141 ** On failure, return SQLITE_CANTOPEN. |
|
142 */ |
|
143 int sqlite3Os2OpenExclusive( const char *zFilename, OsFile **pld, int delFlag ){ |
|
144 os2File f; |
|
145 HFILE hf; |
|
146 ULONG ulAction; |
|
147 APIRET rc = NO_ERROR; |
|
148 |
|
149 assert( *pld == 0 ); |
|
150 rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL, |
|
151 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, |
|
152 OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | |
|
153 OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); |
|
154 if( rc != NO_ERROR ){ |
|
155 return SQLITE_CANTOPEN; |
|
156 } |
|
157 |
|
158 f.h = hf; |
|
159 f.locktype = NO_LOCK; |
|
160 f.delOnClose = delFlag ? 1 : 0; |
|
161 f.pathToDel = delFlag ? sqlite3OsFullPathname( zFilename ) : NULL; |
|
162 OpenCounter( +1 ); |
|
163 if( delFlag ) DosForceDelete( sqlite3OsFullPathname( zFilename ) ); |
|
164 TRACE3( "OPEN EX %d \"%s\"\n", hf, sqlite3OsFullPathname ( zFilename ) ); |
|
165 return allocateOs2File( &f, pld ); |
|
166 } |
|
167 |
|
168 /* |
|
169 ** Attempt to open a new file for read-only access. |
|
170 ** |
|
171 ** On success, write the file handle into *id and return SQLITE_OK. |
|
172 ** |
|
173 ** On failure, return SQLITE_CANTOPEN. |
|
174 */ |
|
175 int sqlite3Os2OpenReadOnly( const char *zFilename, OsFile **pld ){ |
|
176 os2File f; |
|
177 HFILE hf; |
|
178 ULONG ulAction; |
|
179 APIRET rc = NO_ERROR; |
|
180 |
|
181 assert( *pld == 0 ); |
|
182 rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, |
|
183 FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, |
|
184 OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | |
|
185 OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); |
|
186 if( rc != NO_ERROR ){ |
|
187 return SQLITE_CANTOPEN; |
|
188 } |
|
189 f.h = hf; |
|
190 f.locktype = NO_LOCK; |
|
191 f.delOnClose = 0; |
|
192 f.pathToDel = NULL; |
|
193 OpenCounter( +1 ); |
|
194 TRACE3( "OPEN RO %d \"%s\"\n", hf, zFilename ); |
|
195 return allocateOs2File( &f, pld ); |
|
196 } |
|
197 |
|
198 /* |
|
199 ** Attempt to open a file descriptor for the directory that contains a |
|
200 ** file. This file descriptor can be used to fsync() the directory |
|
201 ** in order to make sure the creation of a new file is actually written |
|
202 ** to disk. |
|
203 ** |
|
204 ** This routine is only meaningful for Unix. It is a no-op under |
|
205 ** OS/2 since OS/2 does not support hard links. |
|
206 ** |
|
207 ** On success, a handle for a previously open file is at *id is |
|
208 ** updated with the new directory file descriptor and SQLITE_OK is |
|
209 ** returned. |
|
210 ** |
|
211 ** On failure, the function returns SQLITE_CANTOPEN and leaves |
|
212 ** *id unchanged. |
|
213 */ |
|
214 int os2OpenDirectory( |
|
215 OsFile *id, |
|
216 const char *zDirname |
|
217 ){ |
|
218 return SQLITE_OK; |
|
219 } |
|
220 |
|
221 /* |
|
222 ** If the following global variable points to a string which is the |
|
223 ** name of a directory, then that directory will be used to store |
|
224 ** temporary files. |
|
225 */ |
|
226 char *sqlite3_temp_directory = 0; |
|
227 |
|
228 /* |
|
229 ** Create a temporary file name in zBuf. zBuf must be big enough to |
|
230 ** hold at least SQLITE_TEMPNAME_SIZE characters. |
|
231 */ |
|
232 int sqlite3Os2TempFileName( char *zBuf ){ |
|
233 static const unsigned char zChars[] = |
|
234 "abcdefghijklmnopqrstuvwxyz" |
|
235 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
236 "0123456789"; |
|
237 int i, j; |
|
238 PSZ zTempPath = 0; |
|
239 if( DosScanEnv( "TEMP", &zTempPath ) ){ |
|
240 if( DosScanEnv( "TMP", &zTempPath ) ){ |
|
241 if( DosScanEnv( "TMPDIR", &zTempPath ) ){ |
|
242 ULONG ulDriveNum = 0, ulDriveMap = 0; |
|
243 DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); |
|
244 sprintf( zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); |
|
245 } |
|
246 } |
|
247 } |
|
248 for(;;){ |
|
249 sprintf( zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath ); |
|
250 j = strlen( zBuf ); |
|
251 sqlite3Randomness( 15, &zBuf[j] ); |
|
252 for( i = 0; i < 15; i++, j++ ){ |
|
253 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
|
254 } |
|
255 zBuf[j] = 0; |
|
256 if( !sqlite3OsFileExists( zBuf ) ) break; |
|
257 } |
|
258 TRACE2( "TEMP FILENAME: %s\n", zBuf ); |
|
259 return SQLITE_OK; |
|
260 } |
|
261 |
|
262 /* |
|
263 ** Close a file. |
|
264 */ |
|
265 int os2Close( OsFile **pld ){ |
|
266 os2File *pFile; |
|
267 APIRET rc = NO_ERROR; |
|
268 if( pld && (pFile = (os2File*)*pld) != 0 ){ |
|
269 TRACE2( "CLOSE %d\n", pFile->h ); |
|
270 rc = DosClose( pFile->h ); |
|
271 pFile->locktype = NO_LOCK; |
|
272 if( pFile->delOnClose != 0 ){ |
|
273 rc = DosForceDelete( pFile->pathToDel ); |
|
274 } |
|
275 *pld = 0; |
|
276 OpenCounter( -1 ); |
|
277 } |
|
278 |
|
279 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
280 } |
|
281 |
|
282 /* |
|
283 ** Read data from a file into a buffer. Return SQLITE_OK if all |
|
284 ** bytes were read successfully and SQLITE_IOERR if anything goes |
|
285 ** wrong. |
|
286 */ |
|
287 int os2Read( OsFile *id, void *pBuf, int amt ){ |
|
288 ULONG got; |
|
289 assert( id!=0 ); |
|
290 SimulateIOError( SQLITE_IOERR ); |
|
291 TRACE3( "READ %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); |
|
292 DosRead( ((os2File*)id)->h, pBuf, amt, &got ); |
|
293 return (got == (ULONG)amt) ? SQLITE_OK : SQLITE_IOERR; |
|
294 } |
|
295 |
|
296 /* |
|
297 ** Write data from a buffer into a file. Return SQLITE_OK on success |
|
298 ** or some other error code on failure. |
|
299 */ |
|
300 int os2Write( OsFile *id, const void *pBuf, int amt ){ |
|
301 APIRET rc = NO_ERROR; |
|
302 ULONG wrote; |
|
303 assert( id!=0 ); |
|
304 SimulateIOError( SQLITE_IOERR ); |
|
305 SimulateDiskfullError; |
|
306 TRACE3( "WRITE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); |
|
307 while( amt > 0 && |
|
308 (rc = DosWrite( ((os2File*)id)->h, (PVOID)pBuf, amt, &wrote )) && wrote > 0 ){ |
|
309 amt -= wrote; |
|
310 pBuf = &((char*)pBuf)[wrote]; |
|
311 } |
|
312 |
|
313 return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; |
|
314 } |
|
315 |
|
316 /* |
|
317 ** Move the read/write pointer in a file. |
|
318 */ |
|
319 int os2Seek( OsFile *id, i64 offset ){ |
|
320 APIRET rc = NO_ERROR; |
|
321 ULONG filePointer = 0L; |
|
322 assert( id!=0 ); |
|
323 rc = DosSetFilePtr( ((os2File*)id)->h, offset, FILE_BEGIN, &filePointer ); |
|
324 TRACE3( "SEEK %d %lld\n", ((os2File*)id)->h, offset ); |
|
325 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
326 } |
|
327 |
|
328 /* |
|
329 ** Make sure all writes to a particular file are committed to disk. |
|
330 */ |
|
331 int os2Sync( OsFile *id, int dataOnly ){ |
|
332 assert( id!=0 ); |
|
333 TRACE3( "SYNC %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); |
|
334 return DosResetBuffer( ((os2File*)id)->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
335 } |
|
336 |
|
337 /* |
|
338 ** Sync the directory zDirname. This is a no-op on operating systems other |
|
339 ** than UNIX. |
|
340 */ |
|
341 int sqlite3Os2SyncDirectory( const char *zDirname ){ |
|
342 SimulateIOError( SQLITE_IOERR ); |
|
343 return SQLITE_OK; |
|
344 } |
|
345 |
|
346 /* |
|
347 ** Truncate an open file to a specified size |
|
348 */ |
|
349 int os2Truncate( OsFile *id, i64 nByte ){ |
|
350 APIRET rc = NO_ERROR; |
|
351 ULONG upperBits = nByte>>32; |
|
352 assert( id!=0 ); |
|
353 TRACE3( "TRUNCATE %d %lld\n", ((os2File*)id)->h, nByte ); |
|
354 SimulateIOError( SQLITE_IOERR ); |
|
355 rc = DosSetFilePtr( ((os2File*)id)->h, nByte, FILE_BEGIN, &upperBits ); |
|
356 if( rc != NO_ERROR ){ |
|
357 return SQLITE_IOERR; |
|
358 } |
|
359 rc = DosSetFilePtr( ((os2File*)id)->h, 0L, FILE_END, &upperBits ); |
|
360 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
|
361 } |
|
362 |
|
363 /* |
|
364 ** Determine the current size of a file in bytes |
|
365 */ |
|
366 int os2FileSize( OsFile *id, i64 *pSize ){ |
|
367 APIRET rc = NO_ERROR; |
|
368 FILESTATUS3 fsts3FileInfo; |
|
369 memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); |
|
370 assert( id!=0 ); |
|
371 SimulateIOError( SQLITE_IOERR ); |
|
372 rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); |
|
373 if( rc == NO_ERROR ){ |
|
374 *pSize = fsts3FileInfo.cbFile; |
|
375 return SQLITE_OK; |
|
376 } |
|
377 else{ |
|
378 return SQLITE_IOERR; |
|
379 } |
|
380 } |
|
381 |
|
382 /* |
|
383 ** Acquire a reader lock. |
|
384 */ |
|
385 static int getReadLock( os2File *id ){ |
|
386 FILELOCK LockArea, |
|
387 UnlockArea; |
|
388 memset(&LockArea, 0, sizeof(LockArea)); |
|
389 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
390 LockArea.lOffset = SHARED_FIRST; |
|
391 LockArea.lRange = SHARED_SIZE; |
|
392 UnlockArea.lOffset = 0L; |
|
393 UnlockArea.lRange = 0L; |
|
394 return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
395 } |
|
396 |
|
397 /* |
|
398 ** Undo a readlock |
|
399 */ |
|
400 static int unlockReadLock( os2File *id ){ |
|
401 FILELOCK LockArea, |
|
402 UnlockArea; |
|
403 memset(&LockArea, 0, sizeof(LockArea)); |
|
404 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
405 LockArea.lOffset = 0L; |
|
406 LockArea.lRange = 0L; |
|
407 UnlockArea.lOffset = SHARED_FIRST; |
|
408 UnlockArea.lRange = SHARED_SIZE; |
|
409 return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
410 } |
|
411 |
|
412 #ifndef SQLITE_OMIT_PAGER_PRAGMAS |
|
413 /* |
|
414 ** Check that a given pathname is a directory and is writable |
|
415 ** |
|
416 */ |
|
417 int sqlite3Os2IsDirWritable( char *zDirname ){ |
|
418 FILESTATUS3 fsts3ConfigInfo; |
|
419 APIRET rc = NO_ERROR; |
|
420 memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); |
|
421 if( zDirname==0 ) return 0; |
|
422 if( strlen(zDirname)>CCHMAXPATH ) return 0; |
|
423 rc = DosQueryPathInfo( (PSZ)zDirname, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ); |
|
424 if( rc != NO_ERROR ) return 0; |
|
425 if( (fsts3ConfigInfo.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY ) return 0; |
|
426 |
|
427 return 1; |
|
428 } |
|
429 #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ |
|
430 |
|
431 /* |
|
432 ** Lock the file with the lock specified by parameter locktype - one |
|
433 ** of the following: |
|
434 ** |
|
435 ** (1) SHARED_LOCK |
|
436 ** (2) RESERVED_LOCK |
|
437 ** (3) PENDING_LOCK |
|
438 ** (4) EXCLUSIVE_LOCK |
|
439 ** |
|
440 ** Sometimes when requesting one lock state, additional lock states |
|
441 ** are inserted in between. The locking might fail on one of the later |
|
442 ** transitions leaving the lock state different from what it started but |
|
443 ** still short of its goal. The following chart shows the allowed |
|
444 ** transitions and the inserted intermediate states: |
|
445 ** |
|
446 ** UNLOCKED -> SHARED |
|
447 ** SHARED -> RESERVED |
|
448 ** SHARED -> (PENDING) -> EXCLUSIVE |
|
449 ** RESERVED -> (PENDING) -> EXCLUSIVE |
|
450 ** PENDING -> EXCLUSIVE |
|
451 ** |
|
452 ** This routine will only increase a lock. The os2Unlock() routine |
|
453 ** erases all locks at once and returns us immediately to locking level 0. |
|
454 ** It is not possible to lower the locking level one step at a time. You |
|
455 ** must go straight to locking level 0. |
|
456 */ |
|
457 int os2Lock( OsFile *id, int locktype ){ |
|
458 APIRET rc = SQLITE_OK; /* Return code from subroutines */ |
|
459 APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ |
|
460 int newLocktype; /* Set id->locktype to this value before exiting */ |
|
461 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ |
|
462 FILELOCK LockArea, |
|
463 UnlockArea; |
|
464 os2File *pFile = (os2File*)id; |
|
465 memset(&LockArea, 0, sizeof(LockArea)); |
|
466 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
467 assert( pFile!=0 ); |
|
468 TRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); |
|
469 |
|
470 /* If there is already a lock of this type or more restrictive on the |
|
471 ** OsFile, do nothing. Don't use the end_lock: exit path, as |
|
472 ** sqlite3OsEnterMutex() hasn't been called yet. |
|
473 */ |
|
474 if( pFile->locktype>=locktype ){ |
|
475 return SQLITE_OK; |
|
476 } |
|
477 |
|
478 /* Make sure the locking sequence is correct |
|
479 */ |
|
480 assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); |
|
481 assert( locktype!=PENDING_LOCK ); |
|
482 assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); |
|
483 |
|
484 /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or |
|
485 ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of |
|
486 ** the PENDING_LOCK byte is temporary. |
|
487 */ |
|
488 newLocktype = pFile->locktype; |
|
489 if( pFile->locktype==NO_LOCK |
|
490 || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) |
|
491 ){ |
|
492 int cnt = 3; |
|
493 |
|
494 LockArea.lOffset = PENDING_BYTE; |
|
495 LockArea.lRange = 1L; |
|
496 UnlockArea.lOffset = 0L; |
|
497 UnlockArea.lRange = 0L; |
|
498 |
|
499 while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){ |
|
500 /* Try 3 times to get the pending lock. The pending lock might be |
|
501 ** held by another reader process who will release it momentarily. |
|
502 */ |
|
503 TRACE2( "could not get a PENDING lock. cnt=%d\n", cnt ); |
|
504 DosSleep(1); |
|
505 } |
|
506 gotPendingLock = res; |
|
507 } |
|
508 |
|
509 /* Acquire a shared lock |
|
510 */ |
|
511 if( locktype==SHARED_LOCK && res ){ |
|
512 assert( pFile->locktype==NO_LOCK ); |
|
513 res = getReadLock(pFile); |
|
514 if( res == NO_ERROR ){ |
|
515 newLocktype = SHARED_LOCK; |
|
516 } |
|
517 } |
|
518 |
|
519 /* Acquire a RESERVED lock |
|
520 */ |
|
521 if( locktype==RESERVED_LOCK && res ){ |
|
522 assert( pFile->locktype==SHARED_LOCK ); |
|
523 LockArea.lOffset = RESERVED_BYTE; |
|
524 LockArea.lRange = 1L; |
|
525 UnlockArea.lOffset = 0L; |
|
526 UnlockArea.lRange = 0L; |
|
527 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
528 if( res == NO_ERROR ){ |
|
529 newLocktype = RESERVED_LOCK; |
|
530 } |
|
531 } |
|
532 |
|
533 /* Acquire a PENDING lock |
|
534 */ |
|
535 if( locktype==EXCLUSIVE_LOCK && res ){ |
|
536 newLocktype = PENDING_LOCK; |
|
537 gotPendingLock = 0; |
|
538 } |
|
539 |
|
540 /* Acquire an EXCLUSIVE lock |
|
541 */ |
|
542 if( locktype==EXCLUSIVE_LOCK && res ){ |
|
543 assert( pFile->locktype>=SHARED_LOCK ); |
|
544 res = unlockReadLock(pFile); |
|
545 TRACE2( "unreadlock = %d\n", res ); |
|
546 LockArea.lOffset = SHARED_FIRST; |
|
547 LockArea.lRange = SHARED_SIZE; |
|
548 UnlockArea.lOffset = 0L; |
|
549 UnlockArea.lRange = 0L; |
|
550 res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
551 if( res == NO_ERROR ){ |
|
552 newLocktype = EXCLUSIVE_LOCK; |
|
553 }else{ |
|
554 TRACE2( "error-code = %d\n", res ); |
|
555 } |
|
556 } |
|
557 |
|
558 /* If we are holding a PENDING lock that ought to be released, then |
|
559 ** release it now. |
|
560 */ |
|
561 if( gotPendingLock && locktype==SHARED_LOCK ){ |
|
562 LockArea.lOffset = 0L; |
|
563 LockArea.lRange = 0L; |
|
564 UnlockArea.lOffset = PENDING_BYTE; |
|
565 UnlockArea.lRange = 1L; |
|
566 DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
567 } |
|
568 |
|
569 /* Update the state of the lock has held in the file descriptor then |
|
570 ** return the appropriate result code. |
|
571 */ |
|
572 if( res == NO_ERROR ){ |
|
573 rc = SQLITE_OK; |
|
574 }else{ |
|
575 TRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, |
|
576 locktype, newLocktype ); |
|
577 rc = SQLITE_BUSY; |
|
578 } |
|
579 pFile->locktype = newLocktype; |
|
580 return rc; |
|
581 } |
|
582 |
|
583 /* |
|
584 ** This routine checks if there is a RESERVED lock held on the specified |
|
585 ** file by this or any other process. If such a lock is held, return |
|
586 ** non-zero, otherwise zero. |
|
587 */ |
|
588 int os2CheckReservedLock( OsFile *id ){ |
|
589 APIRET rc = NO_ERROR; |
|
590 os2File *pFile = (os2File*)id; |
|
591 assert( pFile!=0 ); |
|
592 if( pFile->locktype>=RESERVED_LOCK ){ |
|
593 rc = 1; |
|
594 TRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, rc ); |
|
595 }else{ |
|
596 FILELOCK LockArea, |
|
597 UnlockArea; |
|
598 memset(&LockArea, 0, sizeof(LockArea)); |
|
599 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
600 LockArea.lOffset = RESERVED_BYTE; |
|
601 LockArea.lRange = 1L; |
|
602 UnlockArea.lOffset = 0L; |
|
603 UnlockArea.lRange = 0L; |
|
604 rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
605 if( rc == NO_ERROR ){ |
|
606 LockArea.lOffset = 0L; |
|
607 LockArea.lRange = 0L; |
|
608 UnlockArea.lOffset = RESERVED_BYTE; |
|
609 UnlockArea.lRange = 1L; |
|
610 rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
611 } |
|
612 TRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, rc ); |
|
613 } |
|
614 return rc; |
|
615 } |
|
616 |
|
617 /* |
|
618 ** Lower the locking level on file descriptor id to locktype. locktype |
|
619 ** must be either NO_LOCK or SHARED_LOCK. |
|
620 ** |
|
621 ** If the locking level of the file descriptor is already at or below |
|
622 ** the requested locking level, this routine is a no-op. |
|
623 ** |
|
624 ** It is not possible for this routine to fail if the second argument |
|
625 ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine |
|
626 ** might return SQLITE_IOERR; |
|
627 */ |
|
628 int os2Unlock( OsFile *id, int locktype ){ |
|
629 int type; |
|
630 APIRET rc = SQLITE_OK; |
|
631 os2File *pFile = (os2File*)id; |
|
632 FILELOCK LockArea, |
|
633 UnlockArea; |
|
634 memset(&LockArea, 0, sizeof(LockArea)); |
|
635 memset(&UnlockArea, 0, sizeof(UnlockArea)); |
|
636 assert( pFile!=0 ); |
|
637 assert( locktype<=SHARED_LOCK ); |
|
638 TRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ); |
|
639 type = pFile->locktype; |
|
640 if( type>=EXCLUSIVE_LOCK ){ |
|
641 LockArea.lOffset = 0L; |
|
642 LockArea.lRange = 0L; |
|
643 UnlockArea.lOffset = SHARED_FIRST; |
|
644 UnlockArea.lRange = SHARED_SIZE; |
|
645 DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
646 if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ |
|
647 /* This should never happen. We should always be able to |
|
648 ** reacquire the read lock */ |
|
649 rc = SQLITE_IOERR; |
|
650 } |
|
651 } |
|
652 if( type>=RESERVED_LOCK ){ |
|
653 LockArea.lOffset = 0L; |
|
654 LockArea.lRange = 0L; |
|
655 UnlockArea.lOffset = RESERVED_BYTE; |
|
656 UnlockArea.lRange = 1L; |
|
657 DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
658 } |
|
659 if( locktype==NO_LOCK && type>=SHARED_LOCK ){ |
|
660 unlockReadLock(pFile); |
|
661 } |
|
662 if( type>=PENDING_LOCK ){ |
|
663 LockArea.lOffset = 0L; |
|
664 LockArea.lRange = 0L; |
|
665 UnlockArea.lOffset = PENDING_BYTE; |
|
666 UnlockArea.lRange = 1L; |
|
667 DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); |
|
668 } |
|
669 pFile->locktype = locktype; |
|
670 return rc; |
|
671 } |
|
672 |
|
673 /* |
|
674 ** Turn a relative pathname into a full pathname. Return a pointer |
|
675 ** to the full pathname stored in space obtained from sqliteMalloc(). |
|
676 ** The calling function is responsible for freeing this space once it |
|
677 ** is no longer needed. |
|
678 */ |
|
679 char *sqlite3Os2FullPathname( const char *zRelative ){ |
|
680 char *zFull = 0; |
|
681 if( strchr(zRelative, ':') ){ |
|
682 sqlite3SetString( &zFull, zRelative, (char*)0 ); |
|
683 }else{ |
|
684 char zBuff[SQLITE_TEMPNAME_SIZE - 2] = {0}; |
|
685 char zDrive[1] = {0}; |
|
686 ULONG cbzFullLen = SQLITE_TEMPNAME_SIZE; |
|
687 ULONG ulDriveNum = 0; |
|
688 ULONG ulDriveMap = 0; |
|
689 DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); |
|
690 DosQueryCurrentDir( 0L, zBuff, &cbzFullLen ); |
|
691 zFull = sqliteMalloc( cbzFullLen ); |
|
692 sprintf( zDrive, "%c", (char)('A' + ulDriveNum - 1) ); |
|
693 sqlite3SetString( &zFull, zDrive, ":\\", zBuff, "\\", zRelative, (char*)0 ); |
|
694 } |
|
695 return zFull; |
|
696 } |
|
697 |
|
698 /* |
|
699 ** The fullSync option is meaningless on os2, or correct me if I'm wrong. This is a no-op. |
|
700 ** From os_unix.c: Change the value of the fullsync flag in the given file descriptor. |
|
701 ** From os_unix.c: ((unixFile*)id)->fullSync = v; |
|
702 */ |
|
703 static void os2SetFullSync( OsFile *id, int v ){ |
|
704 return; |
|
705 } |
|
706 |
|
707 /* |
|
708 ** Return the underlying file handle for an OsFile |
|
709 */ |
|
710 static int os2FileHandle( OsFile *id ){ |
|
711 return (int)((os2File*)id)->h; |
|
712 } |
|
713 |
|
714 /* |
|
715 ** Return an integer that indices the type of lock currently held |
|
716 ** by this handle. (Used for testing and analysis only.) |
|
717 */ |
|
718 static int os2LockState( OsFile *id ){ |
|
719 return ((os2File*)id)->locktype; |
|
720 } |
|
721 |
|
722 /* |
|
723 ** This vector defines all the methods that can operate on an OsFile |
|
724 ** for os2. |
|
725 */ |
|
726 static const IoMethod sqlite3Os2IoMethod = { |
|
727 os2Close, |
|
728 os2OpenDirectory, |
|
729 os2Read, |
|
730 os2Write, |
|
731 os2Seek, |
|
732 os2Truncate, |
|
733 os2Sync, |
|
734 os2SetFullSync, |
|
735 os2FileHandle, |
|
736 os2FileSize, |
|
737 os2Lock, |
|
738 os2Unlock, |
|
739 os2LockState, |
|
740 os2CheckReservedLock, |
|
741 }; |
|
742 |
|
743 /* |
|
744 ** Allocate memory for an OsFile. Initialize the new OsFile |
|
745 ** to the value given in pInit and return a pointer to the new |
|
746 ** OsFile. If we run out of memory, close the file and return NULL. |
|
747 */ |
|
748 int allocateOs2File( os2File *pInit, OsFile **pld ){ |
|
749 os2File *pNew; |
|
750 pNew = sqliteMalloc( sizeof(*pNew) ); |
|
751 if( pNew==0 ){ |
|
752 DosClose( pInit->h ); |
|
753 *pld = 0; |
|
754 return SQLITE_NOMEM; |
|
755 }else{ |
|
756 *pNew = *pInit; |
|
757 pNew->pMethod = &sqlite3Os2IoMethod; |
|
758 pNew->locktype = NO_LOCK; |
|
759 *pld = (OsFile*)pNew; |
|
760 OpenCounter(+1); |
|
761 return SQLITE_OK; |
|
762 } |
|
763 } |
|
764 |
|
765 #endif /* SQLITE_OMIT_DISKIO */ |
|
766 /*************************************************************************** |
|
767 ** Everything above deals with file I/O. Everything that follows deals |
|
768 ** with other miscellanous aspects of the operating system interface |
|
769 ****************************************************************************/ |
|
770 |
|
771 /* |
|
772 ** Get information to seed the random number generator. The seed |
|
773 ** is written into the buffer zBuf[256]. The calling function must |
|
774 ** supply a sufficiently large buffer. |
|
775 */ |
|
776 int sqlite3Os2RandomSeed( char *zBuf ){ |
|
777 /* We have to initialize zBuf to prevent valgrind from reporting |
|
778 ** errors. The reports issued by valgrind are incorrect - we would |
|
779 ** prefer that the randomness be increased by making use of the |
|
780 ** uninitialized space in zBuf - but valgrind errors tend to worry |
|
781 ** some users. Rather than argue, it seems easier just to initialize |
|
782 ** the whole array and silence valgrind, even if that means less randomness |
|
783 ** in the random seed. |
|
784 ** |
|
785 ** When testing, initializing zBuf[] to zero is all we do. That means |
|
786 ** that we always use the same random number sequence. This makes the |
|
787 ** tests repeatable. |
|
788 */ |
|
789 memset( zBuf, 0, 256 ); |
|
790 DosGetDateTime( (PDATETIME)zBuf ); |
|
791 return SQLITE_OK; |
|
792 } |
|
793 |
|
794 /* |
|
795 ** Sleep for a little while. Return the amount of time slept. |
|
796 */ |
|
797 int sqlite3Os2Sleep( int ms ){ |
|
798 DosSleep( ms ); |
|
799 return ms; |
|
800 } |
|
801 |
|
802 /* |
|
803 ** Static variables used for thread synchronization |
|
804 */ |
|
805 static int inMutex = 0; |
|
806 #ifdef SQLITE_OS2_THREADS |
|
807 static ULONG mutexOwner; |
|
808 #endif |
|
809 |
|
810 /* |
|
811 ** The following pair of routines implement mutual exclusion for |
|
812 ** multi-threaded processes. Only a single thread is allowed to |
|
813 ** executed code that is surrounded by EnterMutex() and LeaveMutex(). |
|
814 ** |
|
815 ** SQLite uses only a single Mutex. There is not much critical |
|
816 ** code and what little there is executes quickly and without blocking. |
|
817 */ |
|
818 void sqlite3Os2EnterMutex(){ |
|
819 PTIB ptib; |
|
820 #ifdef SQLITE_OS2_THREADS |
|
821 DosEnterCritSec(); |
|
822 DosGetInfoBlocks( &ptib, NULL ); |
|
823 mutexOwner = ptib->tib_ptib2->tib2_ultid; |
|
824 #endif |
|
825 assert( !inMutex ); |
|
826 inMutex = 1; |
|
827 } |
|
828 void sqlite3Os2LeaveMutex(){ |
|
829 PTIB ptib; |
|
830 assert( inMutex ); |
|
831 inMutex = 0; |
|
832 #ifdef SQLITE_OS2_THREADS |
|
833 DosGetInfoBlocks( &ptib, NULL ); |
|
834 assert( mutexOwner == ptib->tib_ptib2->tib2_ultid ); |
|
835 DosExitCritSec(); |
|
836 #endif |
|
837 } |
|
838 |
|
839 /* |
|
840 ** Return TRUE if the mutex is currently held. |
|
841 ** |
|
842 ** If the thisThreadOnly parameter is true, return true if and only if the |
|
843 ** calling thread holds the mutex. If the parameter is false, return |
|
844 ** true if any thread holds the mutex. |
|
845 */ |
|
846 int sqlite3Os2InMutex( int thisThreadOnly ){ |
|
847 #ifdef SQLITE_OS2_THREADS |
|
848 PTIB ptib; |
|
849 DosGetInfoBlocks( &ptib, NULL ); |
|
850 return inMutex>0 && (thisThreadOnly==0 || mutexOwner==ptib->tib_ptib2->tib2_ultid); |
|
851 #else |
|
852 return inMutex>0; |
|
853 #endif |
|
854 } |
|
855 |
|
856 /* |
|
857 ** The following variable, if set to a non-zero value, becomes the result |
|
858 ** returned from sqlite3OsCurrentTime(). This is used for testing. |
|
859 */ |
|
860 #ifdef SQLITE_TEST |
|
861 int sqlite3_current_time = 0; |
|
862 #endif |
|
863 |
|
864 /* |
|
865 ** Find the current time (in Universal Coordinated Time). Write the |
|
866 ** current time and date as a Julian Day number into *prNow and |
|
867 ** return 0. Return 1 if the time and date cannot be found. |
|
868 */ |
|
869 int sqlite3Os2CurrentTime( double *prNow ){ |
|
870 double now; |
|
871 USHORT second, minute, hour, |
|
872 day, month, year; |
|
873 DATETIME dt; |
|
874 DosGetDateTime( &dt ); |
|
875 second = (USHORT)dt.seconds; |
|
876 minute = (USHORT)dt.minutes + dt.timezone; |
|
877 hour = (USHORT)dt.hours; |
|
878 day = (USHORT)dt.day; |
|
879 month = (USHORT)dt.month; |
|
880 year = (USHORT)dt.year; |
|
881 |
|
882 /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html |
|
883 http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ |
|
884 /* Calculate the Julian days */ |
|
885 now = day - 32076 + |
|
886 1461*(year + 4800 + (month - 14)/12)/4 + |
|
887 367*(month - 2 - (month - 14)/12*12)/12 - |
|
888 3*((year + 4900 + (month - 14)/12)/100)/4; |
|
889 |
|
890 /* Add the fractional hours, mins and seconds */ |
|
891 now += (hour + 12.0)/24.0; |
|
892 now += minute/1440.0; |
|
893 now += second/86400.0; |
|
894 *prNow = now; |
|
895 #ifdef SQLITE_TEST |
|
896 if( sqlite3_current_time ){ |
|
897 *prNow = sqlite3_current_time/86400.0 + 2440587.5; |
|
898 } |
|
899 #endif |
|
900 return 0; |
|
901 } |
|
902 |
|
903 /* |
|
904 ** Remember the number of thread-specific-data blocks allocated. |
|
905 ** Use this to verify that we are not leaking thread-specific-data. |
|
906 ** Ticket #1601 |
|
907 */ |
|
908 #ifdef SQLITE_TEST |
|
909 int sqlite3_tsd_count = 0; |
|
910 # define TSD_COUNTER_INCR InterlockedIncrement( &sqlite3_tsd_count ) |
|
911 # define TSD_COUNTER_DECR InterlockedDecrement( &sqlite3_tsd_count ) |
|
912 #else |
|
913 # define TSD_COUNTER_INCR /* no-op */ |
|
914 # define TSD_COUNTER_DECR /* no-op */ |
|
915 #endif |
|
916 |
|
917 /* |
|
918 ** If called with allocateFlag>1, then return a pointer to thread |
|
919 ** specific data for the current thread. Allocate and zero the |
|
920 ** thread-specific data if it does not already exist necessary. |
|
921 ** |
|
922 ** If called with allocateFlag==0, then check the current thread |
|
923 ** specific data. Return it if it exists. If it does not exist, |
|
924 ** then return NULL. |
|
925 ** |
|
926 ** If called with allocateFlag<0, check to see if the thread specific |
|
927 ** data is allocated and is all zero. If it is then deallocate it. |
|
928 ** Return a pointer to the thread specific data or NULL if it is |
|
929 ** unallocated or gets deallocated. |
|
930 */ |
|
931 ThreadData *sqlite3Os2ThreadSpecificData( int allocateFlag ){ |
|
932 static ThreadData **s_ppTsd = NULL; |
|
933 static const ThreadData zeroData = {0, 0, 0}; |
|
934 ThreadData *pTsd; |
|
935 |
|
936 if( !s_ppTsd ){ |
|
937 sqlite3OsEnterMutex(); |
|
938 if( !s_ppTsd ){ |
|
939 PULONG pul; |
|
940 APIRET rc = DosAllocThreadLocalMemory(1, &pul); |
|
941 if( rc != NO_ERROR ){ |
|
942 sqlite3OsLeaveMutex(); |
|
943 return 0; |
|
944 } |
|
945 s_ppTsd = (ThreadData **)pul; |
|
946 } |
|
947 sqlite3OsLeaveMutex(); |
|
948 } |
|
949 pTsd = *s_ppTsd; |
|
950 if( allocateFlag>0 ){ |
|
951 if( !pTsd ){ |
|
952 pTsd = sqlite3OsMalloc( sizeof(zeroData) ); |
|
953 if( pTsd ){ |
|
954 *pTsd = zeroData; |
|
955 *s_ppTsd = pTsd; |
|
956 TSD_COUNTER_INCR; |
|
957 } |
|
958 } |
|
959 }else if( pTsd!=0 && allocateFlag<0 |
|
960 && memcmp( pTsd, &zeroData, sizeof(ThreadData) )==0 ){ |
|
961 sqlite3OsFree(pTsd); |
|
962 *s_ppTsd = NULL; |
|
963 TSD_COUNTER_DECR; |
|
964 pTsd = 0; |
|
965 } |
|
966 return pTsd; |
|
967 } |
|
968 #endif /* OS_OS2 */ |