Annotation of embedaddon/php/ext/sqlite/libsqlite/src/os.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** 2001 September 16
! 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 particular operating
! 14: ** systems. The purpose of this file is to provide a uniform abstraction
! 15: ** on which the rest of SQLite can operate.
! 16: */
! 17: #include "os.h" /* Must be first to enable large file support */
! 18: #include "sqliteInt.h"
! 19:
! 20: #if OS_UNIX
! 21: # include <time.h>
! 22: # include <errno.h>
! 23: # include <unistd.h>
! 24: # ifndef O_LARGEFILE
! 25: # define O_LARGEFILE 0
! 26: # endif
! 27: # ifdef SQLITE_DISABLE_LFS
! 28: # undef O_LARGEFILE
! 29: # define O_LARGEFILE 0
! 30: # endif
! 31: # ifndef O_NOFOLLOW
! 32: # define O_NOFOLLOW 0
! 33: # endif
! 34: # ifndef O_BINARY
! 35: # define O_BINARY 0
! 36: # endif
! 37: #endif
! 38:
! 39:
! 40: #if OS_WIN
! 41: # include <winbase.h>
! 42: #endif
! 43:
! 44: #if OS_MAC
! 45: # include <extras.h>
! 46: # include <path2fss.h>
! 47: # include <TextUtils.h>
! 48: # include <FinderRegistry.h>
! 49: # include <Folders.h>
! 50: # include <Timer.h>
! 51: # include <OSUtils.h>
! 52: #endif
! 53:
! 54: /*
! 55: ** The DJGPP compiler environment looks mostly like Unix, but it
! 56: ** lacks the fcntl() system call. So redefine fcntl() to be something
! 57: ** that always succeeds. This means that locking does not occur under
! 58: ** DJGPP. But its DOS - what did you expect?
! 59: */
! 60: #ifdef __DJGPP__
! 61: # define fcntl(A,B,C) 0
! 62: #endif
! 63:
! 64: /*
! 65: ** Macros used to determine whether or not to use threads. The
! 66: ** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
! 67: ** Posix threads and SQLITE_W32_THREADS is defined if we are
! 68: ** synchronizing using Win32 threads.
! 69: */
! 70: #if OS_UNIX && defined(THREADSAFE) && THREADSAFE
! 71: # include <pthread.h>
! 72: # define SQLITE_UNIX_THREADS 1
! 73: #endif
! 74: #if OS_WIN && defined(THREADSAFE) && THREADSAFE
! 75: # define SQLITE_W32_THREADS 1
! 76: #endif
! 77: #if OS_MAC && defined(THREADSAFE) && THREADSAFE
! 78: # include <Multiprocessing.h>
! 79: # define SQLITE_MACOS_MULTITASKING 1
! 80: #endif
! 81:
! 82: /*
! 83: ** Macros for performance tracing. Normally turned off
! 84: */
! 85: #if 0
! 86: static int last_page = 0;
! 87: __inline__ unsigned long long int hwtime(void){
! 88: unsigned long long int x;
! 89: __asm__("rdtsc\n\t"
! 90: "mov %%edx, %%ecx\n\t"
! 91: :"=A" (x));
! 92: return x;
! 93: }
! 94: static unsigned long long int g_start;
! 95: static unsigned int elapse;
! 96: #define TIMER_START g_start=hwtime()
! 97: #define TIMER_END elapse=hwtime()-g_start
! 98: #define SEEK(X) last_page=(X)
! 99: #define TRACE1(X) fprintf(stderr,X)
! 100: #define TRACE2(X,Y) fprintf(stderr,X,Y)
! 101: #define TRACE3(X,Y,Z) fprintf(stderr,X,Y,Z)
! 102: #define TRACE4(X,Y,Z,A) fprintf(stderr,X,Y,Z,A)
! 103: #define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B)
! 104: #else
! 105: #define TIMER_START
! 106: #define TIMER_END
! 107: #define SEEK(X)
! 108: #define TRACE1(X)
! 109: #define TRACE2(X,Y)
! 110: #define TRACE3(X,Y,Z)
! 111: #define TRACE4(X,Y,Z,A)
! 112: #define TRACE5(X,Y,Z,A,B)
! 113: #endif
! 114:
! 115:
! 116: #if OS_UNIX
! 117: /*
! 118: ** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996)
! 119: ** section 6.5.2.2 lines 483 through 490 specify that when a process
! 120: ** sets or clears a lock, that operation overrides any prior locks set
! 121: ** by the same process. It does not explicitly say so, but this implies
! 122: ** that it overrides locks set by the same process using a different
! 123: ** file descriptor. Consider this test case:
! 124: **
! 125: ** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
! 126: ** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
! 127: **
! 128: ** Suppose ./file1 and ./file2 are really the same file (because
! 129: ** one is a hard or symbolic link to the other) then if you set
! 130: ** an exclusive lock on fd1, then try to get an exclusive lock
! 131: ** on fd2, it works. I would have expected the second lock to
! 132: ** fail since there was already a lock on the file due to fd1.
! 133: ** But not so. Since both locks came from the same process, the
! 134: ** second overrides the first, even though they were on different
! 135: ** file descriptors opened on different file names.
! 136: **
! 137: ** Bummer. If you ask me, this is broken. Badly broken. It means
! 138: ** that we cannot use POSIX locks to synchronize file access among
! 139: ** competing threads of the same process. POSIX locks will work fine
! 140: ** to synchronize access for threads in separate processes, but not
! 141: ** threads within the same process.
! 142: **
! 143: ** To work around the problem, SQLite has to manage file locks internally
! 144: ** on its own. Whenever a new database is opened, we have to find the
! 145: ** specific inode of the database file (the inode is determined by the
! 146: ** st_dev and st_ino fields of the stat structure that fstat() fills in)
! 147: ** and check for locks already existing on that inode. When locks are
! 148: ** created or removed, we have to look at our own internal record of the
! 149: ** locks to see if another thread has previously set a lock on that same
! 150: ** inode.
! 151: **
! 152: ** The OsFile structure for POSIX is no longer just an integer file
! 153: ** descriptor. It is now a structure that holds the integer file
! 154: ** descriptor and a pointer to a structure that describes the internal
! 155: ** locks on the corresponding inode. There is one locking structure
! 156: ** per inode, so if the same inode is opened twice, both OsFile structures
! 157: ** point to the same locking structure. The locking structure keeps
! 158: ** a reference count (so we will know when to delete it) and a "cnt"
! 159: ** field that tells us its internal lock status. cnt==0 means the
! 160: ** file is unlocked. cnt==-1 means the file has an exclusive lock.
! 161: ** cnt>0 means there are cnt shared locks on the file.
! 162: **
! 163: ** Any attempt to lock or unlock a file first checks the locking
! 164: ** structure. The fcntl() system call is only invoked to set a
! 165: ** POSIX lock if the internal lock structure transitions between
! 166: ** a locked and an unlocked state.
! 167: **
! 168: ** 2004-Jan-11:
! 169: ** More recent discoveries about POSIX advisory locks. (The more
! 170: ** I discover, the more I realize the a POSIX advisory locks are
! 171: ** an abomination.)
! 172: **
! 173: ** If you close a file descriptor that points to a file that has locks,
! 174: ** all locks on that file that are owned by the current process are
! 175: ** released. To work around this problem, each OsFile structure contains
! 176: ** a pointer to an openCnt structure. There is one openCnt structure
! 177: ** per open inode, which means that multiple OsFiles can point to a single
! 178: ** openCnt. When an attempt is made to close an OsFile, if there are
! 179: ** other OsFiles open on the same inode that are holding locks, the call
! 180: ** to close() the file descriptor is deferred until all of the locks clear.
! 181: ** The openCnt structure keeps a list of file descriptors that need to
! 182: ** be closed and that list is walked (and cleared) when the last lock
! 183: ** clears.
! 184: **
! 185: ** First, under Linux threads, because each thread has a separate
! 186: ** process ID, lock operations in one thread do not override locks
! 187: ** to the same file in other threads. Linux threads behave like
! 188: ** separate processes in this respect. But, if you close a file
! 189: ** descriptor in linux threads, all locks are cleared, even locks
! 190: ** on other threads and even though the other threads have different
! 191: ** process IDs. Linux threads is inconsistent in this respect.
! 192: ** (I'm beginning to think that linux threads is an abomination too.)
! 193: ** The consequence of this all is that the hash table for the lockInfo
! 194: ** structure has to include the process id as part of its key because
! 195: ** locks in different threads are treated as distinct. But the
! 196: ** openCnt structure should not include the process id in its
! 197: ** key because close() clears lock on all threads, not just the current
! 198: ** thread. Were it not for this goofiness in linux threads, we could
! 199: ** combine the lockInfo and openCnt structures into a single structure.
! 200: */
! 201:
! 202: /*
! 203: ** An instance of the following structure serves as the key used
! 204: ** to locate a particular lockInfo structure given its inode. Note
! 205: ** that we have to include the process ID as part of the key. On some
! 206: ** threading implementations (ex: linux), each thread has a separate
! 207: ** process ID.
! 208: */
! 209: struct lockKey {
! 210: dev_t dev; /* Device number */
! 211: ino_t ino; /* Inode number */
! 212: pid_t pid; /* Process ID */
! 213: };
! 214:
! 215: /*
! 216: ** An instance of the following structure is allocated for each open
! 217: ** inode on each thread with a different process ID. (Threads have
! 218: ** different process IDs on linux, but not on most other unixes.)
! 219: **
! 220: ** A single inode can have multiple file descriptors, so each OsFile
! 221: ** structure contains a pointer to an instance of this object and this
! 222: ** object keeps a count of the number of OsFiles pointing to it.
! 223: */
! 224: struct lockInfo {
! 225: struct lockKey key; /* The lookup key */
! 226: int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */
! 227: int nRef; /* Number of pointers to this structure */
! 228: };
! 229:
! 230: /*
! 231: ** An instance of the following structure serves as the key used
! 232: ** to locate a particular openCnt structure given its inode. This
! 233: ** is the same as the lockKey except that the process ID is omitted.
! 234: */
! 235: struct openKey {
! 236: dev_t dev; /* Device number */
! 237: ino_t ino; /* Inode number */
! 238: };
! 239:
! 240: /*
! 241: ** An instance of the following structure is allocated for each open
! 242: ** inode. This structure keeps track of the number of locks on that
! 243: ** inode. If a close is attempted against an inode that is holding
! 244: ** locks, the close is deferred until all locks clear by adding the
! 245: ** file descriptor to be closed to the pending list.
! 246: */
! 247: struct openCnt {
! 248: struct openKey key; /* The lookup key */
! 249: int nRef; /* Number of pointers to this structure */
! 250: int nLock; /* Number of outstanding locks */
! 251: int nPending; /* Number of pending close() operations */
! 252: int *aPending; /* Malloced space holding fd's awaiting a close() */
! 253: };
! 254:
! 255: /*
! 256: ** These hash table maps inodes and process IDs into lockInfo and openCnt
! 257: ** structures. Access to these hash tables must be protected by a mutex.
! 258: */
! 259: static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
! 260: static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
! 261:
! 262: /*
! 263: ** Release a lockInfo structure previously allocated by findLockInfo().
! 264: */
! 265: static void releaseLockInfo(struct lockInfo *pLock){
! 266: pLock->nRef--;
! 267: if( pLock->nRef==0 ){
! 268: sqliteHashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
! 269: sqliteFree(pLock);
! 270: }
! 271: }
! 272:
! 273: /*
! 274: ** Release a openCnt structure previously allocated by findLockInfo().
! 275: */
! 276: static void releaseOpenCnt(struct openCnt *pOpen){
! 277: pOpen->nRef--;
! 278: if( pOpen->nRef==0 ){
! 279: sqliteHashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
! 280: sqliteFree(pOpen->aPending);
! 281: sqliteFree(pOpen);
! 282: }
! 283: }
! 284:
! 285: /*
! 286: ** Given a file descriptor, locate lockInfo and openCnt structures that
! 287: ** describes that file descriptor. Create a new ones if necessary. The
! 288: ** return values might be unset if an error occurs.
! 289: **
! 290: ** Return the number of errors.
! 291: */
! 292: int findLockInfo(
! 293: int fd, /* The file descriptor used in the key */
! 294: struct lockInfo **ppLock, /* Return the lockInfo structure here */
! 295: struct openCnt **ppOpen /* Return the openCnt structure here */
! 296: ){
! 297: int rc;
! 298: struct lockKey key1;
! 299: struct openKey key2;
! 300: struct stat statbuf;
! 301: struct lockInfo *pLock;
! 302: struct openCnt *pOpen;
! 303: rc = fstat(fd, &statbuf);
! 304: if( rc!=0 ) return 1;
! 305: memset(&key1, 0, sizeof(key1));
! 306: key1.dev = statbuf.st_dev;
! 307: key1.ino = statbuf.st_ino;
! 308: key1.pid = getpid();
! 309: memset(&key2, 0, sizeof(key2));
! 310: key2.dev = statbuf.st_dev;
! 311: key2.ino = statbuf.st_ino;
! 312: pLock = (struct lockInfo*)sqliteHashFind(&lockHash, &key1, sizeof(key1));
! 313: if( pLock==0 ){
! 314: struct lockInfo *pOld;
! 315: pLock = sqliteMallocRaw( sizeof(*pLock) );
! 316: if( pLock==0 ) return 1;
! 317: pLock->key = key1;
! 318: pLock->nRef = 1;
! 319: pLock->cnt = 0;
! 320: pOld = sqliteHashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
! 321: if( pOld!=0 ){
! 322: assert( pOld==pLock );
! 323: sqliteFree(pLock);
! 324: return 1;
! 325: }
! 326: }else{
! 327: pLock->nRef++;
! 328: }
! 329: *ppLock = pLock;
! 330: pOpen = (struct openCnt*)sqliteHashFind(&openHash, &key2, sizeof(key2));
! 331: if( pOpen==0 ){
! 332: struct openCnt *pOld;
! 333: pOpen = sqliteMallocRaw( sizeof(*pOpen) );
! 334: if( pOpen==0 ){
! 335: releaseLockInfo(pLock);
! 336: return 1;
! 337: }
! 338: pOpen->key = key2;
! 339: pOpen->nRef = 1;
! 340: pOpen->nLock = 0;
! 341: pOpen->nPending = 0;
! 342: pOpen->aPending = 0;
! 343: pOld = sqliteHashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
! 344: if( pOld!=0 ){
! 345: assert( pOld==pOpen );
! 346: sqliteFree(pOpen);
! 347: releaseLockInfo(pLock);
! 348: return 1;
! 349: }
! 350: }else{
! 351: pOpen->nRef++;
! 352: }
! 353: *ppOpen = pOpen;
! 354: return 0;
! 355: }
! 356:
! 357: #endif /** POSIX advisory lock work-around **/
! 358:
! 359: /*
! 360: ** If we compile with the SQLITE_TEST macro set, then the following block
! 361: ** of code will give us the ability to simulate a disk I/O error. This
! 362: ** is used for testing the I/O recovery logic.
! 363: */
! 364: #ifdef SQLITE_TEST
! 365: int sqlite_io_error_pending = 0;
! 366: #define SimulateIOError(A) \
! 367: if( sqlite_io_error_pending ) \
! 368: if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; }
! 369: static void local_ioerr(){
! 370: sqlite_io_error_pending = 0; /* Really just a place to set a breakpoint */
! 371: }
! 372: #else
! 373: #define SimulateIOError(A)
! 374: #endif
! 375:
! 376: /*
! 377: ** When testing, keep a count of the number of open files.
! 378: */
! 379: #ifdef SQLITE_TEST
! 380: int sqlite_open_file_count = 0;
! 381: #define OpenCounter(X) sqlite_open_file_count+=(X)
! 382: #else
! 383: #define OpenCounter(X)
! 384: #endif
! 385:
! 386:
! 387: /*
! 388: ** Delete the named file
! 389: */
! 390: int sqliteOsDelete(const char *zFilename){
! 391: #if OS_UNIX
! 392: unlink(zFilename);
! 393: #endif
! 394: #if OS_WIN
! 395: DeleteFile(zFilename);
! 396: #endif
! 397: #if OS_MAC
! 398: unlink(zFilename);
! 399: #endif
! 400: return SQLITE_OK;
! 401: }
! 402:
! 403: /*
! 404: ** Return TRUE if the named file exists.
! 405: */
! 406: int sqliteOsFileExists(const char *zFilename){
! 407: #if OS_UNIX
! 408: return access(zFilename, 0)==0;
! 409: #endif
! 410: #if OS_WIN
! 411: return GetFileAttributes(zFilename) != 0xffffffff;
! 412: #endif
! 413: #if OS_MAC
! 414: return access(zFilename, 0)==0;
! 415: #endif
! 416: }
! 417:
! 418:
! 419: #if 0 /* NOT USED */
! 420: /*
! 421: ** Change the name of an existing file.
! 422: */
! 423: int sqliteOsFileRename(const char *zOldName, const char *zNewName){
! 424: #if OS_UNIX
! 425: if( link(zOldName, zNewName) ){
! 426: return SQLITE_ERROR;
! 427: }
! 428: unlink(zOldName);
! 429: return SQLITE_OK;
! 430: #endif
! 431: #if OS_WIN
! 432: if( !MoveFile(zOldName, zNewName) ){
! 433: return SQLITE_ERROR;
! 434: }
! 435: return SQLITE_OK;
! 436: #endif
! 437: #if OS_MAC
! 438: /**** FIX ME ***/
! 439: return SQLITE_ERROR;
! 440: #endif
! 441: }
! 442: #endif /* NOT USED */
! 443:
! 444: /*
! 445: ** Attempt to open a file for both reading and writing. If that
! 446: ** fails, try opening it read-only. If the file does not exist,
! 447: ** try to create it.
! 448: **
! 449: ** On success, a handle for the open file is written to *id
! 450: ** and *pReadonly is set to 0 if the file was opened for reading and
! 451: ** writing or 1 if the file was opened read-only. The function returns
! 452: ** SQLITE_OK.
! 453: **
! 454: ** On failure, the function returns SQLITE_CANTOPEN and leaves
! 455: ** *id and *pReadonly unchanged.
! 456: */
! 457: int sqliteOsOpenReadWrite(
! 458: const char *zFilename,
! 459: OsFile *id,
! 460: int *pReadonly
! 461: ){
! 462: #if OS_UNIX
! 463: int rc;
! 464: id->dirfd = -1;
! 465: id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
! 466: if( id->fd<0 ){
! 467: #ifdef EISDIR
! 468: if( errno==EISDIR ){
! 469: return SQLITE_CANTOPEN;
! 470: }
! 471: #endif
! 472: id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
! 473: if( id->fd<0 ){
! 474: return SQLITE_CANTOPEN;
! 475: }
! 476: *pReadonly = 1;
! 477: }else{
! 478: *pReadonly = 0;
! 479: }
! 480: sqliteOsEnterMutex();
! 481: rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
! 482: sqliteOsLeaveMutex();
! 483: if( rc ){
! 484: close(id->fd);
! 485: return SQLITE_NOMEM;
! 486: }
! 487: id->locked = 0;
! 488: TRACE3("OPEN %-3d %s\n", id->fd, zFilename);
! 489: OpenCounter(+1);
! 490: return SQLITE_OK;
! 491: #endif
! 492: #if OS_WIN
! 493: HANDLE h = CreateFile(zFilename,
! 494: GENERIC_READ | GENERIC_WRITE,
! 495: FILE_SHARE_READ | FILE_SHARE_WRITE,
! 496: NULL,
! 497: OPEN_ALWAYS,
! 498: FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
! 499: NULL
! 500: );
! 501: if( h==INVALID_HANDLE_VALUE ){
! 502: h = CreateFile(zFilename,
! 503: GENERIC_READ,
! 504: FILE_SHARE_READ,
! 505: NULL,
! 506: OPEN_ALWAYS,
! 507: FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
! 508: NULL
! 509: );
! 510: if( h==INVALID_HANDLE_VALUE ){
! 511: return SQLITE_CANTOPEN;
! 512: }
! 513: *pReadonly = 1;
! 514: }else{
! 515: *pReadonly = 0;
! 516: }
! 517: id->h = h;
! 518: id->locked = 0;
! 519: OpenCounter(+1);
! 520: return SQLITE_OK;
! 521: #endif
! 522: #if OS_MAC
! 523: FSSpec fsSpec;
! 524: # ifdef _LARGE_FILE
! 525: HFSUniStr255 dfName;
! 526: FSRef fsRef;
! 527: if( __path2fss(zFilename, &fsSpec) != noErr ){
! 528: if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
! 529: return SQLITE_CANTOPEN;
! 530: }
! 531: if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
! 532: return SQLITE_CANTOPEN;
! 533: FSGetDataForkName(&dfName);
! 534: if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
! 535: fsRdWrShPerm, &(id->refNum)) != noErr ){
! 536: if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
! 537: fsRdWrPerm, &(id->refNum)) != noErr ){
! 538: if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
! 539: fsRdPerm, &(id->refNum)) != noErr )
! 540: return SQLITE_CANTOPEN;
! 541: else
! 542: *pReadonly = 1;
! 543: } else
! 544: *pReadonly = 0;
! 545: } else
! 546: *pReadonly = 0;
! 547: # else
! 548: __path2fss(zFilename, &fsSpec);
! 549: if( !sqliteOsFileExists(zFilename) ){
! 550: if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
! 551: return SQLITE_CANTOPEN;
! 552: }
! 553: if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
! 554: if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
! 555: if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
! 556: return SQLITE_CANTOPEN;
! 557: else
! 558: *pReadonly = 1;
! 559: } else
! 560: *pReadonly = 0;
! 561: } else
! 562: *pReadonly = 0;
! 563: # endif
! 564: if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
! 565: id->refNumRF = -1;
! 566: }
! 567: id->locked = 0;
! 568: id->delOnClose = 0;
! 569: OpenCounter(+1);
! 570: return SQLITE_OK;
! 571: #endif
! 572: }
! 573:
! 574:
! 575: /*
! 576: ** Attempt to open a new file for exclusive access by this process.
! 577: ** The file will be opened for both reading and writing. To avoid
! 578: ** a potential security problem, we do not allow the file to have
! 579: ** previously existed. Nor do we allow the file to be a symbolic
! 580: ** link.
! 581: **
! 582: ** If delFlag is true, then make arrangements to automatically delete
! 583: ** the file when it is closed.
! 584: **
! 585: ** On success, write the file handle into *id and return SQLITE_OK.
! 586: **
! 587: ** On failure, return SQLITE_CANTOPEN.
! 588: */
! 589: int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
! 590: #if OS_UNIX
! 591: int rc;
! 592: if( access(zFilename, 0)==0 ){
! 593: return SQLITE_CANTOPEN;
! 594: }
! 595: id->dirfd = -1;
! 596: id->fd = open(zFilename,
! 597: O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
! 598: if( id->fd<0 ){
! 599: return SQLITE_CANTOPEN;
! 600: }
! 601: sqliteOsEnterMutex();
! 602: rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
! 603: sqliteOsLeaveMutex();
! 604: if( rc ){
! 605: close(id->fd);
! 606: unlink(zFilename);
! 607: return SQLITE_NOMEM;
! 608: }
! 609: id->locked = 0;
! 610: if( delFlag ){
! 611: unlink(zFilename);
! 612: }
! 613: TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename);
! 614: OpenCounter(+1);
! 615: return SQLITE_OK;
! 616: #endif
! 617: #if OS_WIN
! 618: HANDLE h;
! 619: int fileflags;
! 620: if( delFlag ){
! 621: fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
! 622: | FILE_FLAG_DELETE_ON_CLOSE;
! 623: }else{
! 624: fileflags = FILE_FLAG_RANDOM_ACCESS;
! 625: }
! 626: h = CreateFile(zFilename,
! 627: GENERIC_READ | GENERIC_WRITE,
! 628: 0,
! 629: NULL,
! 630: CREATE_ALWAYS,
! 631: fileflags,
! 632: NULL
! 633: );
! 634: if( h==INVALID_HANDLE_VALUE ){
! 635: return SQLITE_CANTOPEN;
! 636: }
! 637: id->h = h;
! 638: id->locked = 0;
! 639: OpenCounter(+1);
! 640: return SQLITE_OK;
! 641: #endif
! 642: #if OS_MAC
! 643: FSSpec fsSpec;
! 644: # ifdef _LARGE_FILE
! 645: HFSUniStr255 dfName;
! 646: FSRef fsRef;
! 647: __path2fss(zFilename, &fsSpec);
! 648: if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
! 649: return SQLITE_CANTOPEN;
! 650: if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
! 651: return SQLITE_CANTOPEN;
! 652: FSGetDataForkName(&dfName);
! 653: if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
! 654: fsRdWrPerm, &(id->refNum)) != noErr )
! 655: return SQLITE_CANTOPEN;
! 656: # else
! 657: __path2fss(zFilename, &fsSpec);
! 658: if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
! 659: return SQLITE_CANTOPEN;
! 660: if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
! 661: return SQLITE_CANTOPEN;
! 662: # endif
! 663: id->refNumRF = -1;
! 664: id->locked = 0;
! 665: id->delOnClose = delFlag;
! 666: if (delFlag)
! 667: id->pathToDel = sqliteOsFullPathname(zFilename);
! 668: OpenCounter(+1);
! 669: return SQLITE_OK;
! 670: #endif
! 671: }
! 672:
! 673: /*
! 674: ** Attempt to open a new file for read-only access.
! 675: **
! 676: ** On success, write the file handle into *id and return SQLITE_OK.
! 677: **
! 678: ** On failure, return SQLITE_CANTOPEN.
! 679: */
! 680: int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){
! 681: #if OS_UNIX
! 682: int rc;
! 683: id->dirfd = -1;
! 684: id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
! 685: if( id->fd<0 ){
! 686: return SQLITE_CANTOPEN;
! 687: }
! 688: sqliteOsEnterMutex();
! 689: rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
! 690: sqliteOsLeaveMutex();
! 691: if( rc ){
! 692: close(id->fd);
! 693: return SQLITE_NOMEM;
! 694: }
! 695: id->locked = 0;
! 696: TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename);
! 697: OpenCounter(+1);
! 698: return SQLITE_OK;
! 699: #endif
! 700: #if OS_WIN
! 701: HANDLE h = CreateFile(zFilename,
! 702: GENERIC_READ,
! 703: 0,
! 704: NULL,
! 705: OPEN_EXISTING,
! 706: FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
! 707: NULL
! 708: );
! 709: if( h==INVALID_HANDLE_VALUE ){
! 710: return SQLITE_CANTOPEN;
! 711: }
! 712: id->h = h;
! 713: id->locked = 0;
! 714: OpenCounter(+1);
! 715: return SQLITE_OK;
! 716: #endif
! 717: #if OS_MAC
! 718: FSSpec fsSpec;
! 719: # ifdef _LARGE_FILE
! 720: HFSUniStr255 dfName;
! 721: FSRef fsRef;
! 722: if( __path2fss(zFilename, &fsSpec) != noErr )
! 723: return SQLITE_CANTOPEN;
! 724: if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
! 725: return SQLITE_CANTOPEN;
! 726: FSGetDataForkName(&dfName);
! 727: if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
! 728: fsRdPerm, &(id->refNum)) != noErr )
! 729: return SQLITE_CANTOPEN;
! 730: # else
! 731: __path2fss(zFilename, &fsSpec);
! 732: if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
! 733: return SQLITE_CANTOPEN;
! 734: # endif
! 735: if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
! 736: id->refNumRF = -1;
! 737: }
! 738: id->locked = 0;
! 739: id->delOnClose = 0;
! 740: OpenCounter(+1);
! 741: return SQLITE_OK;
! 742: #endif
! 743: }
! 744:
! 745: /*
! 746: ** Attempt to open a file descriptor for the directory that contains a
! 747: ** file. This file descriptor can be used to fsync() the directory
! 748: ** in order to make sure the creation of a new file is actually written
! 749: ** to disk.
! 750: **
! 751: ** This routine is only meaningful for Unix. It is a no-op under
! 752: ** windows since windows does not support hard links.
! 753: **
! 754: ** On success, a handle for a previously open file is at *id is
! 755: ** updated with the new directory file descriptor and SQLITE_OK is
! 756: ** returned.
! 757: **
! 758: ** On failure, the function returns SQLITE_CANTOPEN and leaves
! 759: ** *id unchanged.
! 760: */
! 761: int sqliteOsOpenDirectory(
! 762: const char *zDirname,
! 763: OsFile *id
! 764: ){
! 765: #if OS_UNIX
! 766: if( id->fd<0 ){
! 767: /* Do not open the directory if the corresponding file is not already
! 768: ** open. */
! 769: return SQLITE_CANTOPEN;
! 770: }
! 771: assert( id->dirfd<0 );
! 772: id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644);
! 773: if( id->dirfd<0 ){
! 774: return SQLITE_CANTOPEN;
! 775: }
! 776: TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
! 777: #endif
! 778: return SQLITE_OK;
! 779: }
! 780:
! 781: /*
! 782: ** If the following global variable points to a string which is the
! 783: ** name of a directory, then that directory will be used to store
! 784: ** temporary files.
! 785: */
! 786: const char *sqlite_temp_directory = 0;
! 787:
! 788: /*
! 789: ** Create a temporary file name in zBuf. zBuf must be big enough to
! 790: ** hold at least SQLITE_TEMPNAME_SIZE characters.
! 791: */
! 792: int sqliteOsTempFileName(char *zBuf){
! 793: #if OS_UNIX
! 794: static const char *azDirs[] = {
! 795: 0,
! 796: "/var/tmp",
! 797: "/usr/tmp",
! 798: "/tmp",
! 799: ".",
! 800: };
! 801: static unsigned char zChars[] =
! 802: "abcdefghijklmnopqrstuvwxyz"
! 803: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
! 804: "0123456789";
! 805: int i, j;
! 806: struct stat buf;
! 807: const char *zDir = ".";
! 808: azDirs[0] = sqlite_temp_directory;
! 809: for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
! 810: if( azDirs[i]==0 ) continue;
! 811: if( stat(azDirs[i], &buf) ) continue;
! 812: if( !S_ISDIR(buf.st_mode) ) continue;
! 813: if( access(azDirs[i], 07) ) continue;
! 814: zDir = azDirs[i];
! 815: break;
! 816: }
! 817: do{
! 818: sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir);
! 819: j = strlen(zBuf);
! 820: sqliteRandomness(15, &zBuf[j]);
! 821: for(i=0; i<15; i++, j++){
! 822: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
! 823: }
! 824: zBuf[j] = 0;
! 825: }while( access(zBuf,0)==0 );
! 826: #endif
! 827: #if OS_WIN
! 828: static char zChars[] =
! 829: "abcdefghijklmnopqrstuvwxyz"
! 830: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
! 831: "0123456789";
! 832: int i, j;
! 833: const char *zDir;
! 834: char zTempPath[SQLITE_TEMPNAME_SIZE];
! 835: if( sqlite_temp_directory==0 ){
! 836: GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
! 837: for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
! 838: zTempPath[i] = 0;
! 839: zDir = zTempPath;
! 840: }else{
! 841: zDir = sqlite_temp_directory;
! 842: }
! 843: for(;;){
! 844: sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zDir);
! 845: j = strlen(zBuf);
! 846: sqliteRandomness(15, &zBuf[j]);
! 847: for(i=0; i<15; i++, j++){
! 848: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
! 849: }
! 850: zBuf[j] = 0;
! 851: if( !sqliteOsFileExists(zBuf) ) break;
! 852: }
! 853: #endif
! 854: #if OS_MAC
! 855: static char zChars[] =
! 856: "abcdefghijklmnopqrstuvwxyz"
! 857: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
! 858: "0123456789";
! 859: int i, j;
! 860: char *zDir;
! 861: char zTempPath[SQLITE_TEMPNAME_SIZE];
! 862: char zdirName[32];
! 863: CInfoPBRec infoRec;
! 864: Str31 dirName;
! 865: memset(&infoRec, 0, sizeof(infoRec));
! 866: memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
! 867: if( sqlite_temp_directory!=0 ){
! 868: zDir = sqlite_temp_directory;
! 869: }else if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
! 870: &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
! 871: infoRec.dirInfo.ioNamePtr = dirName;
! 872: do{
! 873: infoRec.dirInfo.ioFDirIndex = -1;
! 874: infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
! 875: if( PBGetCatInfoSync(&infoRec) == noErr ){
! 876: CopyPascalStringToC(dirName, zdirName);
! 877: i = strlen(zdirName);
! 878: memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
! 879: strcpy(zTempPath, zdirName);
! 880: zTempPath[i] = ':';
! 881: }else{
! 882: *zTempPath = 0;
! 883: break;
! 884: }
! 885: } while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
! 886: zDir = zTempPath;
! 887: }
! 888: if( zDir[0]==0 ){
! 889: getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
! 890: zDir = zTempPath;
! 891: }
! 892: for(;;){
! 893: sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zDir);
! 894: j = strlen(zBuf);
! 895: sqliteRandomness(15, &zBuf[j]);
! 896: for(i=0; i<15; i++, j++){
! 897: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
! 898: }
! 899: zBuf[j] = 0;
! 900: if( !sqliteOsFileExists(zBuf) ) break;
! 901: }
! 902: #endif
! 903: return SQLITE_OK;
! 904: }
! 905:
! 906: /*
! 907: ** Close a file.
! 908: */
! 909: int sqliteOsClose(OsFile *id){
! 910: #if OS_UNIX
! 911: sqliteOsUnlock(id);
! 912: if( id->dirfd>=0 ) close(id->dirfd);
! 913: id->dirfd = -1;
! 914: sqliteOsEnterMutex();
! 915: if( id->pOpen->nLock ){
! 916: /* If there are outstanding locks, do not actually close the file just
! 917: ** yet because that would clear those locks. Instead, add the file
! 918: ** descriptor to pOpen->aPending. It will be automatically closed when
! 919: ** the last lock is cleared.
! 920: */
! 921: int *aNew;
! 922: struct openCnt *pOpen = id->pOpen;
! 923: pOpen->nPending++;
! 924: aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
! 925: if( aNew==0 ){
! 926: /* If a malloc fails, just leak the file descriptor */
! 927: }else{
! 928: pOpen->aPending = aNew;
! 929: pOpen->aPending[pOpen->nPending-1] = id->fd;
! 930: }
! 931: }else{
! 932: /* There are no outstanding locks so we can close the file immediately */
! 933: close(id->fd);
! 934: }
! 935: releaseLockInfo(id->pLock);
! 936: releaseOpenCnt(id->pOpen);
! 937: sqliteOsLeaveMutex();
! 938: TRACE2("CLOSE %-3d\n", id->fd);
! 939: OpenCounter(-1);
! 940: return SQLITE_OK;
! 941: #endif
! 942: #if OS_WIN
! 943: CloseHandle(id->h);
! 944: OpenCounter(-1);
! 945: return SQLITE_OK;
! 946: #endif
! 947: #if OS_MAC
! 948: if( id->refNumRF!=-1 )
! 949: FSClose(id->refNumRF);
! 950: # ifdef _LARGE_FILE
! 951: FSCloseFork(id->refNum);
! 952: # else
! 953: FSClose(id->refNum);
! 954: # endif
! 955: if( id->delOnClose ){
! 956: unlink(id->pathToDel);
! 957: sqliteFree(id->pathToDel);
! 958: }
! 959: OpenCounter(-1);
! 960: return SQLITE_OK;
! 961: #endif
! 962: }
! 963:
! 964: /*
! 965: ** Read data from a file into a buffer. Return SQLITE_OK if all
! 966: ** bytes were read successfully and SQLITE_IOERR if anything goes
! 967: ** wrong.
! 968: */
! 969: int sqliteOsRead(OsFile *id, void *pBuf, int amt){
! 970: #if OS_UNIX
! 971: int got;
! 972: SimulateIOError(SQLITE_IOERR);
! 973: TIMER_START;
! 974: got = read(id->fd, pBuf, amt);
! 975: TIMER_END;
! 976: TRACE4("READ %-3d %7d %d\n", id->fd, last_page, elapse);
! 977: SEEK(0);
! 978: /* if( got<0 ) got = 0; */
! 979: if( got==amt ){
! 980: return SQLITE_OK;
! 981: }else{
! 982: return SQLITE_IOERR;
! 983: }
! 984: #endif
! 985: #if OS_WIN
! 986: DWORD got;
! 987: SimulateIOError(SQLITE_IOERR);
! 988: TRACE2("READ %d\n", last_page);
! 989: if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
! 990: got = 0;
! 991: }
! 992: if( got==(DWORD)amt ){
! 993: return SQLITE_OK;
! 994: }else{
! 995: return SQLITE_IOERR;
! 996: }
! 997: #endif
! 998: #if OS_MAC
! 999: int got;
! 1000: SimulateIOError(SQLITE_IOERR);
! 1001: TRACE2("READ %d\n", last_page);
! 1002: # ifdef _LARGE_FILE
! 1003: FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
! 1004: # else
! 1005: got = amt;
! 1006: FSRead(id->refNum, &got, pBuf);
! 1007: # endif
! 1008: if( got==amt ){
! 1009: return SQLITE_OK;
! 1010: }else{
! 1011: return SQLITE_IOERR;
! 1012: }
! 1013: #endif
! 1014: }
! 1015:
! 1016: /*
! 1017: ** Write data from a buffer into a file. Return SQLITE_OK on success
! 1018: ** or some other error code on failure.
! 1019: */
! 1020: int sqliteOsWrite(OsFile *id, const void *pBuf, int amt){
! 1021: #if OS_UNIX
! 1022: int wrote = 0;
! 1023: SimulateIOError(SQLITE_IOERR);
! 1024: TIMER_START;
! 1025: while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){
! 1026: amt -= wrote;
! 1027: pBuf = &((char*)pBuf)[wrote];
! 1028: }
! 1029: TIMER_END;
! 1030: TRACE4("WRITE %-3d %7d %d\n", id->fd, last_page, elapse);
! 1031: SEEK(0);
! 1032: if( amt>0 ){
! 1033: return SQLITE_FULL;
! 1034: }
! 1035: return SQLITE_OK;
! 1036: #endif
! 1037: #if OS_WIN
! 1038: int rc;
! 1039: DWORD wrote;
! 1040: SimulateIOError(SQLITE_IOERR);
! 1041: TRACE2("WRITE %d\n", last_page);
! 1042: while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
! 1043: amt -= wrote;
! 1044: pBuf = &((char*)pBuf)[wrote];
! 1045: }
! 1046: if( !rc || amt>(int)wrote ){
! 1047: return SQLITE_FULL;
! 1048: }
! 1049: return SQLITE_OK;
! 1050: #endif
! 1051: #if OS_MAC
! 1052: OSErr oserr;
! 1053: int wrote = 0;
! 1054: SimulateIOError(SQLITE_IOERR);
! 1055: TRACE2("WRITE %d\n", last_page);
! 1056: while( amt>0 ){
! 1057: # ifdef _LARGE_FILE
! 1058: oserr = FSWriteFork(id->refNum, fsAtMark, 0,
! 1059: (ByteCount)amt, pBuf, (ByteCount*)&wrote);
! 1060: # else
! 1061: wrote = amt;
! 1062: oserr = FSWrite(id->refNum, &wrote, pBuf);
! 1063: # endif
! 1064: if( wrote == 0 || oserr != noErr)
! 1065: break;
! 1066: amt -= wrote;
! 1067: pBuf = &((char*)pBuf)[wrote];
! 1068: }
! 1069: if( oserr != noErr || amt>wrote ){
! 1070: return SQLITE_FULL;
! 1071: }
! 1072: return SQLITE_OK;
! 1073: #endif
! 1074: }
! 1075:
! 1076: /*
! 1077: ** Move the read/write pointer in a file.
! 1078: */
! 1079: int sqliteOsSeek(OsFile *id, off_t offset){
! 1080: SEEK(offset/1024 + 1);
! 1081: #if OS_UNIX
! 1082: lseek(id->fd, offset, SEEK_SET);
! 1083: return SQLITE_OK;
! 1084: #endif
! 1085: #if OS_WIN
! 1086: {
! 1087: LONG upperBits = offset>>32;
! 1088: LONG lowerBits = offset & 0xffffffff;
! 1089: DWORD rc;
! 1090: rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
! 1091: /* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */
! 1092: }
! 1093: return SQLITE_OK;
! 1094: #endif
! 1095: #if OS_MAC
! 1096: {
! 1097: off_t curSize;
! 1098: if( sqliteOsFileSize(id, &curSize) != SQLITE_OK ){
! 1099: return SQLITE_IOERR;
! 1100: }
! 1101: if( offset >= curSize ){
! 1102: if( sqliteOsTruncate(id, offset+1) != SQLITE_OK ){
! 1103: return SQLITE_IOERR;
! 1104: }
! 1105: }
! 1106: # ifdef _LARGE_FILE
! 1107: if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
! 1108: # else
! 1109: if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
! 1110: # endif
! 1111: return SQLITE_IOERR;
! 1112: }else{
! 1113: return SQLITE_OK;
! 1114: }
! 1115: }
! 1116: #endif
! 1117: }
! 1118:
! 1119: #ifdef SQLITE_NOSYNC
! 1120: # define fsync(X) 0
! 1121: #endif
! 1122:
! 1123: /*
! 1124: ** Make sure all writes to a particular file are committed to disk.
! 1125: **
! 1126: ** Under Unix, also make sure that the directory entry for the file
! 1127: ** has been created by fsync-ing the directory that contains the file.
! 1128: ** If we do not do this and we encounter a power failure, the directory
! 1129: ** entry for the journal might not exist after we reboot. The next
! 1130: ** SQLite to access the file will not know that the journal exists (because
! 1131: ** the directory entry for the journal was never created) and the transaction
! 1132: ** will not roll back - possibly leading to database corruption.
! 1133: */
! 1134: int sqliteOsSync(OsFile *id){
! 1135: #if OS_UNIX
! 1136: SimulateIOError(SQLITE_IOERR);
! 1137: TRACE2("SYNC %-3d\n", id->fd);
! 1138: if( fsync(id->fd) ){
! 1139: return SQLITE_IOERR;
! 1140: }else{
! 1141: if( id->dirfd>=0 ){
! 1142: TRACE2("DIRSYNC %-3d\n", id->dirfd);
! 1143: fsync(id->dirfd);
! 1144: close(id->dirfd); /* Only need to sync once, so close the directory */
! 1145: id->dirfd = -1; /* when we are done. */
! 1146: }
! 1147: return SQLITE_OK;
! 1148: }
! 1149: #endif
! 1150: #if OS_WIN
! 1151: if( FlushFileBuffers(id->h) ){
! 1152: return SQLITE_OK;
! 1153: }else{
! 1154: return SQLITE_IOERR;
! 1155: }
! 1156: #endif
! 1157: #if OS_MAC
! 1158: # ifdef _LARGE_FILE
! 1159: if( FSFlushFork(id->refNum) != noErr ){
! 1160: # else
! 1161: ParamBlockRec params;
! 1162: memset(¶ms, 0, sizeof(ParamBlockRec));
! 1163: params.ioParam.ioRefNum = id->refNum;
! 1164: if( PBFlushFileSync(¶ms) != noErr ){
! 1165: # endif
! 1166: return SQLITE_IOERR;
! 1167: }else{
! 1168: return SQLITE_OK;
! 1169: }
! 1170: #endif
! 1171: }
! 1172:
! 1173: /*
! 1174: ** Truncate an open file to a specified size
! 1175: */
! 1176: int sqliteOsTruncate(OsFile *id, off_t nByte){
! 1177: SimulateIOError(SQLITE_IOERR);
! 1178: #if OS_UNIX
! 1179: return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
! 1180: #endif
! 1181: #if OS_WIN
! 1182: {
! 1183: LONG upperBits = nByte>>32;
! 1184: SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
! 1185: SetEndOfFile(id->h);
! 1186: }
! 1187: return SQLITE_OK;
! 1188: #endif
! 1189: #if OS_MAC
! 1190: # ifdef _LARGE_FILE
! 1191: if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
! 1192: # else
! 1193: if( SetEOF(id->refNum, nByte) != noErr ){
! 1194: # endif
! 1195: return SQLITE_IOERR;
! 1196: }else{
! 1197: return SQLITE_OK;
! 1198: }
! 1199: #endif
! 1200: }
! 1201:
! 1202: /*
! 1203: ** Determine the current size of a file in bytes
! 1204: */
! 1205: int sqliteOsFileSize(OsFile *id, off_t *pSize){
! 1206: #if OS_UNIX
! 1207: struct stat buf;
! 1208: SimulateIOError(SQLITE_IOERR);
! 1209: if( fstat(id->fd, &buf)!=0 ){
! 1210: return SQLITE_IOERR;
! 1211: }
! 1212: *pSize = buf.st_size;
! 1213: return SQLITE_OK;
! 1214: #endif
! 1215: #if OS_WIN
! 1216: DWORD upperBits, lowerBits;
! 1217: SimulateIOError(SQLITE_IOERR);
! 1218: lowerBits = GetFileSize(id->h, &upperBits);
! 1219: *pSize = (((off_t)upperBits)<<32) + lowerBits;
! 1220: return SQLITE_OK;
! 1221: #endif
! 1222: #if OS_MAC
! 1223: # ifdef _LARGE_FILE
! 1224: if( FSGetForkSize(id->refNum, pSize) != noErr){
! 1225: # else
! 1226: if( GetEOF(id->refNum, pSize) != noErr ){
! 1227: # endif
! 1228: return SQLITE_IOERR;
! 1229: }else{
! 1230: return SQLITE_OK;
! 1231: }
! 1232: #endif
! 1233: }
! 1234:
! 1235: #if OS_WIN
! 1236: /*
! 1237: ** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
! 1238: ** Return false (zero) for Win95, Win98, or WinME.
! 1239: **
! 1240: ** Here is an interesting observation: Win95, Win98, and WinME lack
! 1241: ** the LockFileEx() API. But we can still statically link against that
! 1242: ** API as long as we don't call it win running Win95/98/ME. A call to
! 1243: ** this routine is used to determine if the host is Win95/98/ME or
! 1244: ** WinNT/2K/XP so that we will know whether or not we can safely call
! 1245: ** the LockFileEx() API.
! 1246: */
! 1247: int isNT(void){
! 1248: static int osType = 0; /* 0=unknown 1=win95 2=winNT */
! 1249: if( osType==0 ){
! 1250: OSVERSIONINFO sInfo;
! 1251: sInfo.dwOSVersionInfoSize = sizeof(sInfo);
! 1252: GetVersionEx(&sInfo);
! 1253: osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
! 1254: }
! 1255: return osType==2;
! 1256: }
! 1257: #endif
! 1258:
! 1259: /*
! 1260: ** Windows file locking notes: [similar issues apply to MacOS]
! 1261: **
! 1262: ** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
! 1263: ** those functions are not available. So we use only LockFile() and
! 1264: ** UnlockFile().
! 1265: **
! 1266: ** LockFile() prevents not just writing but also reading by other processes.
! 1267: ** (This is a design error on the part of Windows, but there is nothing
! 1268: ** we can do about that.) So the region used for locking is at the
! 1269: ** end of the file where it is unlikely to ever interfere with an
! 1270: ** actual read attempt.
! 1271: **
! 1272: ** A database read lock is obtained by locking a single randomly-chosen
! 1273: ** byte out of a specific range of bytes. The lock byte is obtained at
! 1274: ** random so two separate readers can probably access the file at the
! 1275: ** same time, unless they are unlucky and choose the same lock byte.
! 1276: ** A database write lock is obtained by locking all bytes in the range.
! 1277: ** There can only be one writer.
! 1278: **
! 1279: ** A lock is obtained on the first byte of the lock range before acquiring
! 1280: ** either a read lock or a write lock. This prevents two processes from
! 1281: ** attempting to get a lock at a same time. The semantics of
! 1282: ** sqliteOsReadLock() require that if there is already a write lock, that
! 1283: ** lock is converted into a read lock atomically. The lock on the first
! 1284: ** byte allows us to drop the old write lock and get the read lock without
! 1285: ** another process jumping into the middle and messing us up. The same
! 1286: ** argument applies to sqliteOsWriteLock().
! 1287: **
! 1288: ** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
! 1289: ** which means we can use reader/writer locks. When reader writer locks
! 1290: ** are used, the lock is placed on the same range of bytes that is used
! 1291: ** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
! 1292: ** will support two or more Win95 readers or two or more WinNT readers.
! 1293: ** But a single Win95 reader will lock out all WinNT readers and a single
! 1294: ** WinNT reader will lock out all other Win95 readers.
! 1295: **
! 1296: ** Note: On MacOS we use the resource fork for locking.
! 1297: **
! 1298: ** The following #defines specify the range of bytes used for locking.
! 1299: ** N_LOCKBYTE is the number of bytes available for doing the locking.
! 1300: ** The first byte used to hold the lock while the lock is changing does
! 1301: ** not count toward this number. FIRST_LOCKBYTE is the address of
! 1302: ** the first byte in the range of bytes used for locking.
! 1303: */
! 1304: #define N_LOCKBYTE 10239
! 1305: #if OS_MAC
! 1306: # define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE)
! 1307: #else
! 1308: # define FIRST_LOCKBYTE (0xffffffff - N_LOCKBYTE)
! 1309: #endif
! 1310:
! 1311: /*
! 1312: ** Change the status of the lock on the file "id" to be a readlock.
! 1313: ** If the file was write locked, then this reduces the lock to a read.
! 1314: ** If the file was read locked, then this acquires a new read lock.
! 1315: **
! 1316: ** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this
! 1317: ** library was compiled with large file support (LFS) but LFS is not
! 1318: ** available on the host, then an SQLITE_NOLFS is returned.
! 1319: */
! 1320: int sqliteOsReadLock(OsFile *id){
! 1321: #if OS_UNIX
! 1322: int rc;
! 1323: sqliteOsEnterMutex();
! 1324: if( id->pLock->cnt>0 ){
! 1325: if( !id->locked ){
! 1326: id->pLock->cnt++;
! 1327: id->locked = 1;
! 1328: id->pOpen->nLock++;
! 1329: }
! 1330: rc = SQLITE_OK;
! 1331: }else if( id->locked || id->pLock->cnt==0 ){
! 1332: struct flock lock;
! 1333: int s;
! 1334: lock.l_type = F_RDLCK;
! 1335: lock.l_whence = SEEK_SET;
! 1336: lock.l_start = lock.l_len = 0L;
! 1337: s = fcntl(id->fd, F_SETLK, &lock);
! 1338: if( s!=0 ){
! 1339: rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
! 1340: }else{
! 1341: rc = SQLITE_OK;
! 1342: if( !id->locked ){
! 1343: id->pOpen->nLock++;
! 1344: id->locked = 1;
! 1345: }
! 1346: id->pLock->cnt = 1;
! 1347: }
! 1348: }else{
! 1349: rc = SQLITE_BUSY;
! 1350: }
! 1351: sqliteOsLeaveMutex();
! 1352: return rc;
! 1353: #endif
! 1354: #if OS_WIN
! 1355: int rc;
! 1356: if( id->locked>0 ){
! 1357: rc = SQLITE_OK;
! 1358: }else{
! 1359: int lk;
! 1360: int res;
! 1361: int cnt = 100;
! 1362: sqliteRandomness(sizeof(lk), &lk);
! 1363: lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
! 1364: while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
! 1365: Sleep(1);
! 1366: }
! 1367: if( res ){
! 1368: UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
! 1369: if( isNT() ){
! 1370: OVERLAPPED ovlp;
! 1371: ovlp.Offset = FIRST_LOCKBYTE+1;
! 1372: ovlp.OffsetHigh = 0;
! 1373: ovlp.hEvent = 0;
! 1374: res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY,
! 1375: 0, N_LOCKBYTE, 0, &ovlp);
! 1376: }else{
! 1377: res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0);
! 1378: }
! 1379: UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
! 1380: }
! 1381: if( res ){
! 1382: id->locked = lk;
! 1383: rc = SQLITE_OK;
! 1384: }else{
! 1385: rc = SQLITE_BUSY;
! 1386: }
! 1387: }
! 1388: return rc;
! 1389: #endif
! 1390: #if OS_MAC
! 1391: int rc;
! 1392: if( id->locked>0 || id->refNumRF == -1 ){
! 1393: rc = SQLITE_OK;
! 1394: }else{
! 1395: int lk;
! 1396: OSErr res;
! 1397: int cnt = 5;
! 1398: ParamBlockRec params;
! 1399: sqliteRandomness(sizeof(lk), &lk);
! 1400: lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
! 1401: memset(¶ms, 0, sizeof(params));
! 1402: params.ioParam.ioRefNum = id->refNumRF;
! 1403: params.ioParam.ioPosMode = fsFromStart;
! 1404: params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
! 1405: params.ioParam.ioReqCount = 1;
! 1406: while( cnt-->0 && (res = PBLockRangeSync(¶ms))!=noErr ){
! 1407: UInt32 finalTicks;
! 1408: Delay(1, &finalTicks); /* 1/60 sec */
! 1409: }
! 1410: if( res == noErr ){
! 1411: params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
! 1412: params.ioParam.ioReqCount = N_LOCKBYTE;
! 1413: PBUnlockRangeSync(¶ms);
! 1414: params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
! 1415: params.ioParam.ioReqCount = 1;
! 1416: res = PBLockRangeSync(¶ms);
! 1417: params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
! 1418: params.ioParam.ioReqCount = 1;
! 1419: PBUnlockRangeSync(¶ms);
! 1420: }
! 1421: if( res == noErr ){
! 1422: id->locked = lk;
! 1423: rc = SQLITE_OK;
! 1424: }else{
! 1425: rc = SQLITE_BUSY;
! 1426: }
! 1427: }
! 1428: return rc;
! 1429: #endif
! 1430: }
! 1431:
! 1432: /*
! 1433: ** Change the lock status to be an exclusive or write lock. Return
! 1434: ** SQLITE_OK on success and SQLITE_BUSY on a failure. If this
! 1435: ** library was compiled with large file support (LFS) but LFS is not
! 1436: ** available on the host, then an SQLITE_NOLFS is returned.
! 1437: */
! 1438: int sqliteOsWriteLock(OsFile *id){
! 1439: #if OS_UNIX
! 1440: int rc;
! 1441: sqliteOsEnterMutex();
! 1442: if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){
! 1443: struct flock lock;
! 1444: int s;
! 1445: lock.l_type = F_WRLCK;
! 1446: lock.l_whence = SEEK_SET;
! 1447: lock.l_start = lock.l_len = 0L;
! 1448: s = fcntl(id->fd, F_SETLK, &lock);
! 1449: if( s!=0 ){
! 1450: rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
! 1451: }else{
! 1452: rc = SQLITE_OK;
! 1453: if( !id->locked ){
! 1454: id->pOpen->nLock++;
! 1455: id->locked = 1;
! 1456: }
! 1457: id->pLock->cnt = -1;
! 1458: }
! 1459: }else{
! 1460: rc = SQLITE_BUSY;
! 1461: }
! 1462: sqliteOsLeaveMutex();
! 1463: return rc;
! 1464: #endif
! 1465: #if OS_WIN
! 1466: int rc;
! 1467: if( id->locked<0 ){
! 1468: rc = SQLITE_OK;
! 1469: }else{
! 1470: int res;
! 1471: int cnt = 100;
! 1472: while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
! 1473: Sleep(1);
! 1474: }
! 1475: if( res ){
! 1476: if( id->locked>0 ){
! 1477: if( isNT() ){
! 1478: UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
! 1479: }else{
! 1480: res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0);
! 1481: }
! 1482: }
! 1483: if( res ){
! 1484: res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
! 1485: }else{
! 1486: res = 0;
! 1487: }
! 1488: UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
! 1489: }
! 1490: if( res ){
! 1491: id->locked = -1;
! 1492: rc = SQLITE_OK;
! 1493: }else{
! 1494: rc = SQLITE_BUSY;
! 1495: }
! 1496: }
! 1497: return rc;
! 1498: #endif
! 1499: #if OS_MAC
! 1500: int rc;
! 1501: if( id->locked<0 || id->refNumRF == -1 ){
! 1502: rc = SQLITE_OK;
! 1503: }else{
! 1504: OSErr res;
! 1505: int cnt = 5;
! 1506: ParamBlockRec params;
! 1507: memset(¶ms, 0, sizeof(params));
! 1508: params.ioParam.ioRefNum = id->refNumRF;
! 1509: params.ioParam.ioPosMode = fsFromStart;
! 1510: params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
! 1511: params.ioParam.ioReqCount = 1;
! 1512: while( cnt-->0 && (res = PBLockRangeSync(¶ms))!=noErr ){
! 1513: UInt32 finalTicks;
! 1514: Delay(1, &finalTicks); /* 1/60 sec */
! 1515: }
! 1516: if( res == noErr ){
! 1517: params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
! 1518: params.ioParam.ioReqCount = 1;
! 1519: if( id->locked==0
! 1520: || PBUnlockRangeSync(¶ms)==noErr ){
! 1521: params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
! 1522: params.ioParam.ioReqCount = N_LOCKBYTE;
! 1523: res = PBLockRangeSync(¶ms);
! 1524: }else{
! 1525: res = afpRangeNotLocked;
! 1526: }
! 1527: params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
! 1528: params.ioParam.ioReqCount = 1;
! 1529: PBUnlockRangeSync(¶ms);
! 1530: }
! 1531: if( res == noErr ){
! 1532: id->locked = -1;
! 1533: rc = SQLITE_OK;
! 1534: }else{
! 1535: rc = SQLITE_BUSY;
! 1536: }
! 1537: }
! 1538: return rc;
! 1539: #endif
! 1540: }
! 1541:
! 1542: /*
! 1543: ** Unlock the given file descriptor. If the file descriptor was
! 1544: ** not previously locked, then this routine is a no-op. If this
! 1545: ** library was compiled with large file support (LFS) but LFS is not
! 1546: ** available on the host, then an SQLITE_NOLFS is returned.
! 1547: */
! 1548: int sqliteOsUnlock(OsFile *id){
! 1549: #if OS_UNIX
! 1550: int rc;
! 1551: if( !id->locked ) return SQLITE_OK;
! 1552: sqliteOsEnterMutex();
! 1553: assert( id->pLock->cnt!=0 );
! 1554: if( id->pLock->cnt>1 ){
! 1555: id->pLock->cnt--;
! 1556: rc = SQLITE_OK;
! 1557: }else{
! 1558: struct flock lock;
! 1559: int s;
! 1560: lock.l_type = F_UNLCK;
! 1561: lock.l_whence = SEEK_SET;
! 1562: lock.l_start = lock.l_len = 0L;
! 1563: s = fcntl(id->fd, F_SETLK, &lock);
! 1564: if( s!=0 ){
! 1565: rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
! 1566: }else{
! 1567: rc = SQLITE_OK;
! 1568: id->pLock->cnt = 0;
! 1569: }
! 1570: }
! 1571: if( rc==SQLITE_OK ){
! 1572: /* Decrement the count of locks against this same file. When the
! 1573: ** count reaches zero, close any other file descriptors whose close
! 1574: ** was deferred because of outstanding locks.
! 1575: */
! 1576: struct openCnt *pOpen = id->pOpen;
! 1577: pOpen->nLock--;
! 1578: assert( pOpen->nLock>=0 );
! 1579: if( pOpen->nLock==0 && pOpen->nPending>0 ){
! 1580: int i;
! 1581: for(i=0; i<pOpen->nPending; i++){
! 1582: close(pOpen->aPending[i]);
! 1583: }
! 1584: sqliteFree(pOpen->aPending);
! 1585: pOpen->nPending = 0;
! 1586: pOpen->aPending = 0;
! 1587: }
! 1588: }
! 1589: sqliteOsLeaveMutex();
! 1590: id->locked = 0;
! 1591: return rc;
! 1592: #endif
! 1593: #if OS_WIN
! 1594: int rc;
! 1595: if( id->locked==0 ){
! 1596: rc = SQLITE_OK;
! 1597: }else if( isNT() || id->locked<0 ){
! 1598: UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
! 1599: rc = SQLITE_OK;
! 1600: id->locked = 0;
! 1601: }else{
! 1602: UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0);
! 1603: rc = SQLITE_OK;
! 1604: id->locked = 0;
! 1605: }
! 1606: return rc;
! 1607: #endif
! 1608: #if OS_MAC
! 1609: int rc;
! 1610: ParamBlockRec params;
! 1611: memset(¶ms, 0, sizeof(params));
! 1612: params.ioParam.ioRefNum = id->refNumRF;
! 1613: params.ioParam.ioPosMode = fsFromStart;
! 1614: if( id->locked==0 || id->refNumRF == -1 ){
! 1615: rc = SQLITE_OK;
! 1616: }else if( id->locked<0 ){
! 1617: params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
! 1618: params.ioParam.ioReqCount = N_LOCKBYTE;
! 1619: PBUnlockRangeSync(¶ms);
! 1620: rc = SQLITE_OK;
! 1621: id->locked = 0;
! 1622: }else{
! 1623: params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
! 1624: params.ioParam.ioReqCount = 1;
! 1625: PBUnlockRangeSync(¶ms);
! 1626: rc = SQLITE_OK;
! 1627: id->locked = 0;
! 1628: }
! 1629: return rc;
! 1630: #endif
! 1631: }
! 1632:
! 1633: /*
! 1634: ** Get information to seed the random number generator. The seed
! 1635: ** is written into the buffer zBuf[256]. The calling function must
! 1636: ** supply a sufficiently large buffer.
! 1637: */
! 1638: int sqliteOsRandomSeed(char *zBuf){
! 1639: /* We have to initialize zBuf to prevent valgrind from reporting
! 1640: ** errors. The reports issued by valgrind are incorrect - we would
! 1641: ** prefer that the randomness be increased by making use of the
! 1642: ** uninitialized space in zBuf - but valgrind errors tend to worry
! 1643: ** some users. Rather than argue, it seems easier just to initialize
! 1644: ** the whole array and silence valgrind, even if that means less randomness
! 1645: ** in the random seed.
! 1646: **
! 1647: ** When testing, initializing zBuf[] to zero is all we do. That means
! 1648: ** that we always use the same random number sequence.* This makes the
! 1649: ** tests repeatable.
! 1650: */
! 1651: memset(zBuf, 0, 256);
! 1652: #if OS_UNIX && !defined(SQLITE_TEST)
! 1653: {
! 1654: int pid;
! 1655: time((time_t*)zBuf);
! 1656: pid = getpid();
! 1657: memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
! 1658: }
! 1659: #endif
! 1660: #if OS_WIN && !defined(SQLITE_TEST)
! 1661: GetSystemTime((LPSYSTEMTIME)zBuf);
! 1662: #endif
! 1663: #if OS_MAC
! 1664: {
! 1665: int pid;
! 1666: Microseconds((UnsignedWide*)zBuf);
! 1667: pid = getpid();
! 1668: memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
! 1669: }
! 1670: #endif
! 1671: return SQLITE_OK;
! 1672: }
! 1673:
! 1674: /*
! 1675: ** Sleep for a little while. Return the amount of time slept.
! 1676: */
! 1677: int sqliteOsSleep(int ms){
! 1678: #if OS_UNIX
! 1679: #if defined(HAVE_USLEEP) && HAVE_USLEEP
! 1680: usleep(ms*1000);
! 1681: return ms;
! 1682: #else
! 1683: sleep((ms+999)/1000);
! 1684: return 1000*((ms+999)/1000);
! 1685: #endif
! 1686: #endif
! 1687: #if OS_WIN
! 1688: Sleep(ms);
! 1689: return ms;
! 1690: #endif
! 1691: #if OS_MAC
! 1692: UInt32 finalTicks;
! 1693: UInt32 ticks = (((UInt32)ms+16)*3)/50; /* 1/60 sec per tick */
! 1694: Delay(ticks, &finalTicks);
! 1695: return (int)((ticks*50)/3);
! 1696: #endif
! 1697: }
! 1698:
! 1699: /*
! 1700: ** Static variables used for thread synchronization
! 1701: */
! 1702: static int inMutex = 0;
! 1703: #ifdef SQLITE_UNIX_THREADS
! 1704: static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
! 1705: #endif
! 1706: #ifdef SQLITE_W32_THREADS
! 1707: static CRITICAL_SECTION cs;
! 1708: #endif
! 1709: #ifdef SQLITE_MACOS_MULTITASKING
! 1710: static MPCriticalRegionID criticalRegion;
! 1711: #endif
! 1712:
! 1713: /*
! 1714: ** The following pair of routine implement mutual exclusion for
! 1715: ** multi-threaded processes. Only a single thread is allowed to
! 1716: ** executed code that is surrounded by EnterMutex() and LeaveMutex().
! 1717: **
! 1718: ** SQLite uses only a single Mutex. There is not much critical
! 1719: ** code and what little there is executes quickly and without blocking.
! 1720: */
! 1721: void sqliteOsEnterMutex(){
! 1722: #ifdef SQLITE_UNIX_THREADS
! 1723: pthread_mutex_lock(&mutex);
! 1724: #endif
! 1725: #ifdef SQLITE_W32_THREADS
! 1726: static int isInit = 0;
! 1727: while( !isInit ){
! 1728: static long lock = 0;
! 1729: if( InterlockedIncrement(&lock)==1 ){
! 1730: InitializeCriticalSection(&cs);
! 1731: isInit = 1;
! 1732: }else{
! 1733: Sleep(1);
! 1734: }
! 1735: }
! 1736: EnterCriticalSection(&cs);
! 1737: #endif
! 1738: #ifdef SQLITE_MACOS_MULTITASKING
! 1739: static volatile int notInit = 1;
! 1740: if( notInit ){
! 1741: if( notInit == 2 ) /* as close as you can get to thread safe init */
! 1742: MPYield();
! 1743: else{
! 1744: notInit = 2;
! 1745: MPCreateCriticalRegion(&criticalRegion);
! 1746: notInit = 0;
! 1747: }
! 1748: }
! 1749: MPEnterCriticalRegion(criticalRegion, kDurationForever);
! 1750: #endif
! 1751: assert( !inMutex );
! 1752: inMutex = 1;
! 1753: }
! 1754: void sqliteOsLeaveMutex(){
! 1755: assert( inMutex );
! 1756: inMutex = 0;
! 1757: #ifdef SQLITE_UNIX_THREADS
! 1758: pthread_mutex_unlock(&mutex);
! 1759: #endif
! 1760: #ifdef SQLITE_W32_THREADS
! 1761: LeaveCriticalSection(&cs);
! 1762: #endif
! 1763: #ifdef SQLITE_MACOS_MULTITASKING
! 1764: MPExitCriticalRegion(criticalRegion);
! 1765: #endif
! 1766: }
! 1767:
! 1768: /*
! 1769: ** Turn a relative pathname into a full pathname. Return a pointer
! 1770: ** to the full pathname stored in space obtained from sqliteMalloc().
! 1771: ** The calling function is responsible for freeing this space once it
! 1772: ** is no longer needed.
! 1773: */
! 1774: char *sqliteOsFullPathname(const char *zRelative){
! 1775: #if OS_UNIX
! 1776: char *zFull = 0;
! 1777: if( zRelative[0]=='/' ){
! 1778: sqliteSetString(&zFull, zRelative, (char*)0);
! 1779: }else{
! 1780: char zBuf[5000];
! 1781: zBuf[0] = 0;
! 1782: sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
! 1783: (char*)0);
! 1784: }
! 1785: return zFull;
! 1786: #endif
! 1787: #if OS_WIN
! 1788: char *zNotUsed;
! 1789: char *zFull;
! 1790: int nByte;
! 1791: nByte = GetFullPathName(zRelative, 0, 0, &zNotUsed) + 1;
! 1792: zFull = sqliteMalloc( nByte );
! 1793: if( zFull==0 ) return 0;
! 1794: GetFullPathName(zRelative, nByte, zFull, &zNotUsed);
! 1795: return zFull;
! 1796: #endif
! 1797: #if OS_MAC
! 1798: char *zFull = 0;
! 1799: if( zRelative[0]==':' ){
! 1800: char zBuf[_MAX_PATH+1];
! 1801: sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
! 1802: (char*)0);
! 1803: }else{
! 1804: if( strchr(zRelative, ':') ){
! 1805: sqliteSetString(&zFull, zRelative, (char*)0);
! 1806: }else{
! 1807: char zBuf[_MAX_PATH+1];
! 1808: sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
! 1809: }
! 1810: }
! 1811: return zFull;
! 1812: #endif
! 1813: }
! 1814:
! 1815: /*
! 1816: ** The following variable, if set to a non-zero value, becomes the result
! 1817: ** returned from sqliteOsCurrentTime(). This is used for testing.
! 1818: */
! 1819: #ifdef SQLITE_TEST
! 1820: int sqlite_current_time = 0;
! 1821: #endif
! 1822:
! 1823: /*
! 1824: ** Find the current time (in Universal Coordinated Time). Write the
! 1825: ** current time and date as a Julian Day number into *prNow and
! 1826: ** return 0. Return 1 if the time and date cannot be found.
! 1827: */
! 1828: int sqliteOsCurrentTime(double *prNow){
! 1829: #if OS_UNIX
! 1830: time_t t;
! 1831: time(&t);
! 1832: *prNow = t/86400.0 + 2440587.5;
! 1833: #endif
! 1834: #if OS_WIN
! 1835: FILETIME ft;
! 1836: /* FILETIME structure is a 64-bit value representing the number of
! 1837: 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
! 1838: */
! 1839: double now;
! 1840: GetSystemTimeAsFileTime( &ft );
! 1841: now = ((double)ft.dwHighDateTime) * 4294967296.0;
! 1842: *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
! 1843: #endif
! 1844: #ifdef SQLITE_TEST
! 1845: if( sqlite_current_time ){
! 1846: *prNow = sqlite_current_time/86400.0 + 2440587.5;
! 1847: }
! 1848: #endif
! 1849: return 0;
! 1850: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>