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