diff options
author | drh <drh@noemail.net> | 2008-12-03 19:34:47 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2008-12-03 19:34:47 +0000 |
commit | 6b9d6ddc2146071eb2e56500c57f4a2a7e9ed84e (patch) | |
tree | 9bb4ec9914cae1354bb9d64627c891b86880f557 /src/os_unix.c | |
parent | 08609ce7f0bc01e138e4d309862180b67d48c5f6 (diff) | |
download | sqlite-6b9d6ddc2146071eb2e56500c57f4a2a7e9ed84e.tar.gz sqlite-6b9d6ddc2146071eb2e56500c57f4a2a7e9ed84e.zip |
Continue with the cleanup of os_unix.c. (CVS 5969)
FossilOrigin-Name: 215d36ea89078036fb66b5154f054613b735dab3
Diffstat (limited to 'src/os_unix.c')
-rw-r--r-- | src/os_unix.c | 845 |
1 files changed, 553 insertions, 292 deletions
diff --git a/src/os_unix.c b/src/os_unix.c index b16369cef..cfdd5a0ae 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -24,7 +24,7 @@ ** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed ** in the correct division and should be clearly labeled. ** -** The current set of divisions is as follows: +** The layout of divisions is as follows: ** ** * General-purpose declarations and utility functions. ** * Unique file ID logic used by VxWorks. @@ -39,17 +39,18 @@ ** * sqlite3_file methods not associated with locking. ** * Definitions of sqlite3_io_methods objects for all locking ** methods plus "finder" functions for each locking method. -** * VFS method implementations. +** * sqlite3_vfs method implementations. ** * Definitions of sqlite3_vfs objects for all locking methods ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). ** -** $Id: os_unix.c,v 1.224 2008/11/29 02:20:27 drh Exp $ +** $Id: os_unix.c,v 1.225 2008/12/03 19:34:47 drh Exp $ */ #include "sqliteInt.h" #if SQLITE_OS_UNIX /* This file is used on unix only */ /* -** This module implements the following locking styles: +** There are various methods for file locking used for concurrency +** control: ** ** 1. POSIX locking (the default), ** 2. No locking, @@ -1791,13 +1792,24 @@ static int dotlockClose(sqlite3_file *id) { ** ** Use the flock() system call to do file locking. ** +** flock() locking is like dot-file locking in that the various +** fine-grain locking levels supported by SQLite are collapsed into +** a single exclusive lock. In other words, SHARED, RESERVED, and +** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite +** still works when you do this, but concurrency is reduced since +** only a single process can be reading the database at a time. +** ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if ** compiling for VXWORKS. */ #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS -/* flock-style reserved lock checking following the behavior of - ** unixCheckReservedLock, see the unixCheckReservedLock function comments */ +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; @@ -1851,6 +1863,35 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ return rc; } +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** flock() only really support EXCLUSIVE locks. We track intermediate +** lock states in the sqlite3_file structure, but all locks SHARED or +** above are really EXCLUSIVE locks and exclude all other processes from +** access the file. +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ static int flockLock(sqlite3_file *id, int locktype) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -1887,6 +1928,14 @@ static int flockLock(sqlite3_file *id, int locktype) { return rc; } + +/* +** Lower the locking level on file descriptor pFile to locktype. locktype +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ static int flockUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; @@ -1946,11 +1995,20 @@ static int flockClose(sqlite3_file *id) { ************************ Begin Named Semaphore Locking ************************ ** ** Named semaphore locking is only supported on VxWorks. +** +** Semaphore locking is like dot-lock and flock in that it really only +** supports EXCLUSIVE locking. Only a single process can read or write +** the database file at a time. This reduces potential concurrency, but +** makes the lock implementation much easier. */ #if OS_VXWORKS -/* Namedsem-style reserved lock checking following the behavior of -** unixCheckReservedLock, see the unixCheckReservedLock function comments */ +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { int rc = SQLITE_OK; int reserved = 0; @@ -1990,6 +2048,35 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { return rc; } +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** Semaphore locks only really support EXCLUSIVE locks. We track intermediate +** lock states in the sqlite3_file structure, but all locks SHARED or +** above are really EXCLUSIVE locks and exclude all other processes from +** access the file. +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ static int semLock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; int fd; @@ -2017,6 +2104,13 @@ static int semLock(sqlite3_file *id, int locktype) { return rc; } +/* +** Lower the locking level on file descriptor pFile to locktype. locktype +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ static int semUnlock(sqlite3_file *id, int locktype) { unixFile *pFile = (unixFile*)id; sem_t *pSem = pFile->pOpen->pSem; @@ -2093,7 +2187,7 @@ static int semClose(sqlite3_file *id) { typedef struct afpLockingContext afpLockingContext; struct afpLockingContext { unsigned long long sharedByte; - const char *dbPath; + const char *dbPath; /* Name of the open file */ }; struct ByteRangeLockPB2 @@ -2108,18 +2202,21 @@ struct ByteRangeLockPB2 #define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) -/* - ** Return SQLITE_OK on success, SQLITE_BUSY on failure. - */ -static int _AFPFSSetLock( - const char *path, - unixFile *pFile, - unsigned long long offset, - unsigned long long length, - int setLockFlag +/* +** This is a utility for setting or clearing a bit-range lock on an +** AFP filesystem. +** +** Return SQLITE_OK on success, SQLITE_BUSY on failure. +*/ +static int afpSetLock( + const char *path, /* Name of the file to be locked or unlocked */ + unixFile *pFile, /* Open file descriptor on path */ + unsigned long long offset, /* First byte to be locked */ + unsigned long long length, /* Number of bytes to lock */ + int setLockFlag /* True to set lock. False to clear lock */ ){ - struct ByteRangeLockPB2 pb; - int err; + struct ByteRangeLockPB2 pb; + int err; pb.unLockFlag = setLockFlag ? 0 : 1; pb.startEndFlag = 0; @@ -2154,8 +2251,12 @@ static int _AFPFSSetLock( } } -/* AFP-style reserved lock checking following the behavior of -** unixCheckReservedLock, see the unixCheckReservedLock function comments */ +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; @@ -2175,11 +2276,11 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ */ if( !reserved ){ /* lock the RESERVED byte */ - int lrc = _AFPFSSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); + int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); if( SQLITE_OK==lrc ){ /* if we succeeded in taking the reserved lock, unlock it to restore ** the original state */ - lrc = _AFPFSSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); + lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); } else { /* if we failed to get the lock then someone else must have it */ reserved = 1; @@ -2195,8 +2296,30 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ return rc; } -/* AFP-style locking following the behavior of unixLock, see the unixLock -** function comments for details of lock management. */ +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ static int afpLock(sqlite3_file *id, int locktype){ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -2242,7 +2365,7 @@ static int afpLock(sqlite3_file *id, int locktype){ || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK) ){ int failed; - failed = _AFPFSSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1); + failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1); if (failed) { rc = failed; goto afp_end_lock; @@ -2259,13 +2382,13 @@ static int afpLock(sqlite3_file *id, int locktype){ /* note that the quality of the randomness doesn't matter that much */ lk = random(); context->sharedByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); - lrc1 = _AFPFSSetLock(context->dbPath, pFile, + lrc1 = afpSetLock(context->dbPath, pFile, SHARED_FIRST+context->sharedByte, 1, 1); if( IS_LOCK_ERROR(lrc1) ){ lrc1Errno = pFile->lastErrno; } /* Drop the temporary PENDING lock */ - lrc2 = _AFPFSSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); + lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); if( IS_LOCK_ERROR(lrc1) ) { pFile->lastErrno = lrc1Errno; @@ -2289,7 +2412,7 @@ static int afpLock(sqlite3_file *id, int locktype){ assert( 0!=pFile->locktype ); if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) { /* Acquire a RESERVED lock */ - failed = _AFPFSSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); + failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); } if (!failed && locktype == EXCLUSIVE_LOCK) { /* Acquire an EXCLUSIVE lock */ @@ -2297,13 +2420,13 @@ static int afpLock(sqlite3_file *id, int locktype){ /* Remove the shared lock before trying the range. we'll need to ** reestablish the shared lock if we can't get the afpUnlock */ - if( !(failed = _AFPFSSetLock(context->dbPath, pFile, SHARED_FIRST + + if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST + context->sharedByte, 1, 0)) ){ int failed2 = SQLITE_OK; /* now attemmpt to get the exclusive lock range */ - failed = _AFPFSSetLock(context->dbPath, pFile, SHARED_FIRST, + failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 1); - if( failed && (failed2 = _AFPFSSetLock(context->dbPath, pFile, + if( failed && (failed2 = afpSetLock(context->dbPath, pFile, SHARED_FIRST + context->sharedByte, 1, 1)) ){ /* Can't reestablish the shared lock. Sqlite can't deal, this is ** a critical I/O error @@ -2361,23 +2484,23 @@ static int afpUnlock(sqlite3_file *id, int locktype) { if( pFile->locktype>SHARED_LOCK ){ if( pFile->locktype==EXCLUSIVE_LOCK ){ - rc = _AFPFSSetLock(pCtx->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0); + rc = afpSetLock(pCtx->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0); if( rc==SQLITE_OK && locktype==SHARED_LOCK ){ /* only re-establish the shared lock if necessary */ int sharedLockByte = SHARED_FIRST+pCtx->sharedByte; - rc = _AFPFSSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 1); + rc = afpSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 1); } } if( rc==SQLITE_OK && pFile->locktype>=PENDING_LOCK ){ - rc = _AFPFSSetLock(pCtx->dbPath, pFile, PENDING_BYTE, 1, 0); + rc = afpSetLock(pCtx->dbPath, pFile, PENDING_BYTE, 1, 0); } if( rc==SQLITE_OK && pFile->locktype>=RESERVED_LOCK ){ - rc = _AFPFSSetLock(pCtx->dbPath, pFile, RESERVED_BYTE, 1, 0); + rc = afpSetLock(pCtx->dbPath, pFile, RESERVED_BYTE, 1, 0); } }else if( locktype==NO_LOCK ){ /* clear the shared lock */ int sharedLockByte = SHARED_FIRST+pCtx->sharedByte; - rc = _AFPFSSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 0); + rc = afpSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 0); } if( rc==SQLITE_OK ){ @@ -2608,14 +2731,18 @@ static int afpClose(sqlite3_file *id) { */ #if defined(__DARWIN__) && SQLITE_ENABLE_LOCKING_STYLE - -static int getDbPathForUnixFile(unixFile *pFile, char *dbPath); -static int getLockPath(const char *dbPath, char *lPath, size_t maxLen); -static int createProxyUnixFile(const char *path, unixFile **ppFile); -static int fillInUnixFile(sqlite3_vfs *pVfs, int h, int dirfd, sqlite3_file *pId, const char *zFilename, int noLock, int isDelete); -static int takeConch(unixFile *pFile); -static int releaseConch(unixFile *pFile); -static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf); +/* +** Forward reference +*/ +static int fillInUnixFile( + sqlite3_vfs *pVfs, + int h, + int dirfd, + sqlite3_file *pId, + const char *zFilename, + int noLock, + int isDelete +); #ifdef SQLITE_TEST @@ -2629,91 +2756,16 @@ int sqlite3_hostid_num = 0; */ typedef struct proxyLockingContext proxyLockingContext; struct proxyLockingContext { - unixFile *conchFile; - char *conchFilePath; - unixFile *lockProxy; - char *lockProxyPath; - char *dbPath; - int conchHeld; - void *oldLockingContext; /* preserve the original locking context for close */ - sqlite3_io_methods const *pOldMethod; /* ditto pMethod */ + unixFile *conchFile; /* Open conch file */ + char *conchFilePath; /* Name of the conch file */ + unixFile *lockProxy; /* Open proxy lock file */ + char *lockProxyPath; /* Name of the proxy lock file */ + char *dbPath; /* Name of the open file */ + int conchHeld; /* True if the conch is currently held */ + void *oldLockingContext; /* Original lockingcontext to restore on close */ + sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ }; - -static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) { - unixFile *pFile = (unixFile*)id; - int rc = takeConch(pFile); - if( rc==SQLITE_OK ){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; - unixFile *proxy = pCtx->lockProxy; - return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut); - } - return rc; -} - -static int proxyLock(sqlite3_file *id, int locktype) { - unixFile *pFile = (unixFile*)id; - int rc = takeConch(pFile); - if( rc==SQLITE_OK ){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; - unixFile *proxy = pCtx->lockProxy; - rc = proxy->pMethod->xLock((sqlite3_file*)proxy, locktype); - pFile->locktype = proxy->locktype; - } - return rc; -} - -static int proxyUnlock(sqlite3_file *id, int locktype) { - unixFile *pFile = (unixFile*)id; - int rc = takeConch(pFile); - if( rc==SQLITE_OK ){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; - unixFile *proxy = pCtx->lockProxy; - rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, locktype); - pFile->locktype = proxy->locktype; - } - return rc; -} - -/* - ** Close a file. - */ -static int proxyClose(sqlite3_file *id) { - if( id ){ - unixFile *pFile = (unixFile*)id; - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; - unixFile *lockProxy = pCtx->lockProxy; - unixFile *conchFile = pCtx->conchFile; - int rc = SQLITE_OK; - - if( lockProxy ){ - rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); - if( rc ) return rc; - rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy); - if( rc ) return rc; - sqlite3_free(lockProxy); - } - if( conchFile ){ - if( pCtx->conchHeld ){ - rc = releaseConch(pFile); - if( rc ) return rc; - } - rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile); - if( rc ) return rc; - sqlite3_free(conchFile); - } - sqlite3_free(pCtx->lockProxyPath); - sqlite3_free(pCtx->conchFilePath); - sqlite3_free(pCtx->dbPath); - /* restore the original locking context and pMethod then close it */ - pFile->lockingContext = pCtx->oldLockingContext; - pFile->pMethod = pCtx->pOldMethod; - sqlite3_free(pCtx); - return pFile->pMethod->xClose(id); - } - return SQLITE_OK; -} - /* HOSTIDLEN and CONCHLEN both include space for the string ** terminating nul */ @@ -2725,7 +2777,7 @@ static int proxyClose(sqlite3_file *id) { /* basically a copy of unixRandomness with different ** test behavior built in */ -static int genHostID(char *pHostID){ +static int proxyGenerateHostID(char *pHostID){ int pid, fd, i, len; unsigned char *key = (unsigned char *)pHostID; @@ -2760,8 +2812,9 @@ static int genHostID(char *pHostID){ } /* writes the host id path to path, path should be an pre-allocated buffer -** with enough space for a path */ -static int getHostIDPath(char *path, size_t len){ +** with enough space for a path +*/ +static int proxyGetHostIDPath(char *path, size_t len){ strlcpy(path, HOSTIDPATH, len); #ifdef SQLITE_TEST if( sqlite3_hostid_num>0 ){ @@ -2776,13 +2829,13 @@ static int getHostIDPath(char *path, size_t len){ /* get the host ID from a sqlite hostid file stored in the ** user-specific tmp directory, create the ID if it's not there already */ -static int getHostID(char *pHostID, int *pError){ +static int proxyGetHostID(char *pHostID, int *pError){ int fd; char path[MAXPATHLEN]; size_t len; - int rc=SQLITE_OK; + int rc=SQLITE_OK; - getHostIDPath(path, MAXPATHLEN); + proxyGetHostIDPath(path, MAXPATHLEN); /* try to create the host ID file, if it already exists read the contents */ fd = open(path, O_CREAT|O_WRONLY|O_EXCL, 0644); if( fd<0 ){ @@ -2819,7 +2872,7 @@ static int getHostID(char *pHostID, int *pError){ }else{ int i; /* we're creating the host ID file (use a random string of bytes) */ - genHostID(pHostID); + proxyGenerateHostID(pHostID); len = pwrite(fd, pHostID, HOSTIDLEN, 0); if( len<0 ){ *pError = errno; @@ -2834,13 +2887,97 @@ static int getHostID(char *pHostID, int *pError){ } } +static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ + int len; + int dbLen; + int i; + +#ifdef LOCKPROXYDIR + len = strlcpy(lPath, LOCKPROXYDIR, maxLen); +#else +# ifdef _CS_DARWIN_USER_TEMP_DIR + { + char utdir[MAXPATHLEN]; + + confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen); + len = strlcat(lPath, "sqliteplocks", maxLen); + if( mkdir(lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ + /* if mkdir fails, handle as lock file creation failure */ + int err = errno; +# ifdef SQLITE_DEBUG + if( err!=EEXIST ){ + fprintf(stderr, "proxyGetLockPath: mkdir(%s,0%o) error %d %s\n", lPath, + SQLITE_DEFAULT_PROXYDIR_PERMISSIONS, err, strerror(err)); + } +# endif + }else{ + OSTRACE3("GETLOCKPATH mkdir %s pid=%d\n", lPath, getpid()); + } + + } +# else + len = strlcpy(lPath, "/tmp/", maxLen); +# endif +#endif + + if( lPath[len-1]!='/' ){ + len = strlcat(lPath, "/", maxLen); + } + + /* transform the db path to a unique cache name */ + dbLen = strlen(dbPath); + for( i=0; i<dbLen && (i+len+7)<maxLen; i++){ + char c = dbPath[i]; + lPath[i+len] = (c=='/')?'_':c; + } + lPath[i+len]='\0'; + strlcat(lPath, ":auto:", maxLen); + return SQLITE_OK; +} + +/* +** Create a new VFS file descriptor (stored in memory obtained from +** sqlite3_malloc) and open the file named "path" in the file descriptor. +** +** The caller is responsible not only for closing the file descriptor +** but also for freeing the memory associated with the file descriptor. +*/ +static int proxyCreateUnixFile(const char *path, unixFile **ppFile) { + int fd; + int dirfd = -1; + unixFile *pNew; + int rc = SQLITE_OK; + + fd = open(path, O_RDWR | O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS); + if( fd<0 ){ + return SQLITE_CANTOPEN; + } + + pNew = (unixFile *)sqlite3_malloc(sizeof(unixFile)); + if( pNew==NULL ){ + rc = SQLITE_NOMEM; + goto end_create_proxy; + } + memset(pNew, 0, sizeof(unixFile)); + + rc = fillInUnixFile(NULL, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0); + if( rc==SQLITE_OK ){ + *ppFile = pNew; + return SQLITE_OK; + } +end_create_proxy: + close(fd); /* silently leak fd if error, we're already in error */ + sqlite3_free(pNew); + return rc; +} + /* takes the conch by taking a shared lock and read the contents conch, if ** lockPath is non-NULL, the host ID and lock file path must match. A NULL ** lockPath means that the lockPath in the conch file will be used if the ** host IDs match, or a new lock path will be generated automatically ** and written to the conch file. */ -static int takeConch(unixFile *pFile){ +static int proxyTakeConch(unixFile *pFile){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; if( pCtx->conchHeld>0 ){ @@ -2860,12 +2997,12 @@ static int takeConch(unixFile *pFile){ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); if( rc==SQLITE_OK ){ - int pError = 0; + int pError = 0; memset(testValue, 0, CONCHLEN); // conch is fixed size - rc = getHostID(testValue, &pError); - if( rc&SQLITE_IOERR==SQLITE_IOERR ){ - pFile->lastErrno = pError; - } + rc = proxyGetHostID(testValue, &pError); + if( rc&SQLITE_IOERR==SQLITE_IOERR ){ + pFile->lastErrno = pError; + } if( pCtx->lockProxyPath ){ strlcpy(&testValue[HOSTIDLEN], pCtx->lockProxyPath, MAXPATHLEN); } @@ -2908,7 +3045,7 @@ static int takeConch(unixFile *pFile){ /* either conch was emtpy or didn't match */ if( !pCtx->lockProxyPath ){ - getLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); + proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); tLockPath = lockPath; strlcpy(&testValue[HOSTIDLEN], lockPath, MAXPATHLEN); } @@ -2964,13 +3101,13 @@ end_takeconch: if( fd>=0 ){ pFile->h = fd; }else{ - rc=SQLITE_CANTOPEN; // SQLITE_BUSY? takeConch called during locking + rc=SQLITE_CANTOPEN; // SQLITE_BUSY? proxyTakeConch called during locking } } if( rc==SQLITE_OK && !pCtx->lockProxy ){ char *path = tLockPath ? tLockPath : pCtx->lockProxyPath; // ACS: Need to make a copy of path sometimes - rc = createProxyUnixFile(path, &pCtx->lockProxy); + rc = proxyCreateUnixFile(path, &pCtx->lockProxy); } if( rc==SQLITE_OK ){ pCtx->conchHeld = 1; @@ -2989,12 +3126,17 @@ end_takeconch: return rc; } } - -static int releaseConch(unixFile *pFile){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; - int rc; - unixFile *conchFile = pCtx->conchFile; +/* +** If pFile holds a lock on a conch file, then release that lock. +*/ +static int proxyReleaseConch(unixFile *pFile){ + int rc; /* Subroutine return code */ + proxyLockingContext *pCtx; /* The locking context for the proxy lock */ + unixFile *conchFile; /* Name of the conch file */ + + pCtx = (proxyLockingContext *)pFile->lockingContext; + conchFile = pCtx->conchFile; OSTRACE4("RELEASECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()); @@ -3005,16 +3147,29 @@ static int releaseConch(unixFile *pFile){ return rc; } -static int getConchPathFromDBPath(char *dbPath, char **pConchPath){ - int i; - int len = strlen(dbPath); - char *conchPath; - - conchPath = (char *)sqlite3_malloc(len + 8); +/* +** Given the name of a database file, compute the name of its conch file. +** Store the conch filename in memory obtained from sqlite3_malloc(). +** Make *pConchPath point to the new name. Return SQLITE_OK on success +** or SQLITE_NOMEM if unable to obtain memory. +** +** The caller is responsible for ensuring that the allocated memory +** space is eventually freed. +** +** *pConchPath is set to NULL if a memory allocation error occurs. +*/ +static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ + int i; /* Loop counter */ + int len = strlen(dbPath); /* Length of database filename - dbPath */ + char *conchPath; /* buffer in which to construct conch name */ + + /* Allocate space for the conch filename and initialize the name to + ** the name of the original database file. */ + *pConchPath = conchPath = (char *)sqlite3_malloc(len + 8); if( conchPath==0 ){ return SQLITE_NOMEM; } - strlcpy(conchPath, dbPath, len+1); + memcpy(conchPath, dbPath, len+1); /* now insert a "." before the last / character */ for( i=(len-1); i>=0; i-- ){ @@ -3028,61 +3183,15 @@ static int getConchPathFromDBPath(char *dbPath, char **pConchPath){ conchPath[i+1]=dbPath[i]; i++; } - conchPath[i+1]='\0'; - strlcat(conchPath, "-conch", len + 8); - *pConchPath = conchPath; - return SQLITE_OK; -} - - -static int getLockPath(const char *dbPath, char *lPath, size_t maxLen){ - int len; - int dbLen; - int i; -#ifdef LOCKPROXYDIR - len = strlcpy(lPath, LOCKPROXYDIR, maxLen); -#else -# ifdef _CS_DARWIN_USER_TEMP_DIR - { - char utdir[MAXPATHLEN]; - - confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen); - len = strlcat(lPath, "sqliteplocks", maxLen); - if( mkdir(lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ - /* if mkdir fails, handle as lock file creation failure */ - int err = errno; -# ifdef SQLITE_DEBUG - if( err!=EEXIST ){ - fprintf(stderr, "getLockPath: mkdir(%s,0%o) error %d %s\n", lPath, - SQLITE_DEFAULT_PROXYDIR_PERMISSIONS, err, strerror(err)); - } -# endif - }else{ - OSTRACE3("GETLOCKPATH mkdir %s pid=%d\n", lPath, getpid()); - } - - } -# else - len = strlcpy(lPath, "/tmp/", maxLen); -# endif -#endif + /* append the "-conch" suffix to the file */ + memcpy(&conchPath[i+1], "-conch", 7); + assert( strlen(conchPath) == len+7 ); - if( lPath[len-1]!='/' ){ - len = strlcat(lPath, "/", maxLen); - } - - /* transform the db path to a unique cache name */ - dbLen = strlen(dbPath); - for( i=0; i<dbLen && (i+len+7)<maxLen; i++){ - char c = dbPath[i]; - lPath[i+len] = (c=='/')?'_':c; - } - lPath[i+len]='\0'; - strlcat(lPath, ":auto:", maxLen); return SQLITE_OK; } + /* Takes a fully configured proxy locking-style unix file and switches ** the local lock file path */ @@ -3117,6 +3226,35 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) { } /* +** pFile is a file that has been opened by a prior xOpen call. dbPath +** is a string buffer at least MAXPATHLEN+1 characters in size. +** +** This routine find the filename associated with pFile and writes it +** int dbPath. +*/ +static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ +#if defined(__DARWIN__) + if( pFile->pMethod == &afpIoMethods ){ + /* afp style keeps a reference to the db path in the filePath field + ** of the struct */ + assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); + strcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath) + }else +#endif + if( pFile->pMethod == &dotlockIoMethods ){ + /* dot lock style uses the locking context to store the dot lock + ** file path */ + int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX); + memcpy(dbPath, (char *)pFile->lockingContext, len + 1); + }else{ + /* all other styles use the locking context to store the db file path */ + assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); + strcpy(dbPath, (char *)pFile->lockingContext); + } + return SQLITE_OK; +} + +/* ** Takes an already filled in unix file and alters it so all file locking ** will be performed on the local proxy lock file. The following fields ** are preserved in the locking context so that they can be restored and @@ -3126,14 +3264,14 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) { */ static int transformUnixFileForLockProxy(unixFile *pFile, const char *path) { proxyLockingContext *pCtx; - char dbPath[MAXPATHLEN]; + char dbPath[MAXPATHLEN+1]; /* Name of the database file */ char *lockPath=NULL; int rc = SQLITE_OK; if( pFile->locktype!=NO_LOCK ){ return SQLITE_BUSY; } - getDbPathForUnixFile(pFile, dbPath); + proxyGetDbPathForUnixFile(pFile, dbPath); if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){ lockPath=NULL; }else{ @@ -3149,9 +3287,9 @@ static int transformUnixFileForLockProxy(unixFile *pFile, const char *path) { } memset(pCtx, 0, sizeof(*pCtx)); - rc = getConchPathFromDBPath(dbPath, &pCtx->conchFilePath); + rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath); if( rc==SQLITE_OK ){ - rc = createProxyUnixFile(pCtx->conchFilePath, &pCtx->conchFile); + rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile); } if( rc==SQLITE_OK && lockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath); @@ -3179,37 +3317,129 @@ end_transform_file: OSTRACE3("TRANSPROXY %d %s\n", pFile->h, (rc==SQLITE_OK ? "ok" : "failed")); return rc; -} +} -static int createProxyUnixFile(const char *path, unixFile **ppFile) { - int fd; - int dirfd = -1; - unixFile *pNew; - int rc = SQLITE_OK; +/* +** Within this division (the proxying locking implementation) the procedures +** above this point are all utilities. The lock-related methods of the +** proxy-locking sqlite3_io_method object follow. +*/ - fd = open(path, O_RDWR | O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS); - if( fd<0 ){ - return SQLITE_CANTOPEN; + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ +static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) { + unixFile *pFile = (unixFile*)id; + int rc = proxyTakeConch(pFile); + if( rc==SQLITE_OK ){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *proxy = pCtx->lockProxy; + return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut); } - - pNew = (unixFile *)sqlite3_malloc(sizeof(unixFile)); - if( pNew==NULL ){ - rc = SQLITE_NOMEM; - goto end_create_proxy; + return rc; +} + +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ +static int proxyLock(sqlite3_file *id, int locktype) { + unixFile *pFile = (unixFile*)id; + int rc = proxyTakeConch(pFile); + if( rc==SQLITE_OK ){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *proxy = pCtx->lockProxy; + rc = proxy->pMethod->xLock((sqlite3_file*)proxy, locktype); + pFile->locktype = proxy->locktype; } - memset(pNew, 0, sizeof(unixFile)); - - rc = fillInUnixFile(NULL, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0); + return rc; +} + + +/* +** Lower the locking level on file descriptor pFile to locktype. locktype +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ +static int proxyUnlock(sqlite3_file *id, int locktype) { + unixFile *pFile = (unixFile*)id; + int rc = proxyTakeConch(pFile); if( rc==SQLITE_OK ){ - *ppFile = pNew; - return SQLITE_OK; + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *proxy = pCtx->lockProxy; + rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, locktype); + pFile->locktype = proxy->locktype; } -end_create_proxy: - close(fd); /* silently leak fd if error, we're already in error */ - sqlite3_free(pNew); return rc; } +/* +** Close a file that uses proxy locks. +*/ +static int proxyClose(sqlite3_file *id) { + if( id ){ + unixFile *pFile = (unixFile*)id; + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *lockProxy = pCtx->lockProxy; + unixFile *conchFile = pCtx->conchFile; + int rc = SQLITE_OK; + + if( lockProxy ){ + rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); + if( rc ) return rc; + rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy); + if( rc ) return rc; + sqlite3_free(lockProxy); + pCtx->lockProxy = 0; + } + if( conchFile ){ + if( pCtx->conchHeld ){ + rc = proxyReleaseConch(pFile); + if( rc ) return rc; + } + rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile); + if( rc ) return rc; + sqlite3_free(conchFile); + } + sqlite3_free(pCtx->lockProxyPath); + sqlite3_free(pCtx->conchFilePath); + sqlite3_free(pCtx->dbPath); + /* restore the original locking context and pMethod then close it */ + pFile->lockingContext = pCtx->oldLockingContext; + pFile->pMethod = pCtx->pOldMethod; + sqlite3_free(pCtx); + return pFile->pMethod->xClose(id); + } + return SQLITE_OK; +} + + #endif /* defined(__DARWIN__) && SQLITE_ENABLE_LOCKING_STYLE */ /* @@ -3375,7 +3605,7 @@ static int unixWrite( #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test -** that syncs and fullsyncs are occuring at the right times. +** that syncs and fullsyncs are occurring at the right times. */ int sqlite3_sync_count = 0; int sqlite3_fullsync_count = 0; @@ -3450,13 +3680,13 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ rc = 1; } /* If the FULLFSYNC failed, fall back to attempting an fsync(). - * It shouldn't be possible for fullfsync to fail on the local - * file system (on OSX), so failure indicates that FULLFSYNC - * isn't supported for this file system. So, attempt an fsync - * and (for now) ignore the overhead of a superfluous fcntl call. - * It'd be better to detect fullfsync support once and avoid - * the fcntl call every time sync is called. - */ + ** It shouldn't be possible for fullfsync to fail on the local + ** file system (on OSX), so failure indicates that FULLFSYNC + ** isn't supported for this file system. So, attempt an fsync + ** and (for now) ignore the overhead of a superfluous fcntl call. + ** It'd be better to detect fullfsync support once and avoid + ** the fcntl call every time sync is called. + */ if( rc ) rc = fsync(fd); #else @@ -3609,7 +3839,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; if( pFile->pMethod == &proxyIoMethods ){ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; - takeConch(pFile); + proxyTakeConch(pFile); if( pCtx->lockProxyPath ){ *(const char **)pArg = pCtx->lockProxyPath; }else{ @@ -3652,7 +3882,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } return rc; } -#endif +#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__DARWIN__) */ } return SQLITE_ERROR; } @@ -3687,6 +3917,19 @@ static int unixDeviceCharacteristics(sqlite3_file *NotUsed){ ******************************************************************************/ /* +** This division contains definitions of sqlite3_io_methods objects that +** implement various file locking strategies. It also contains definitions +** of "finder" functions. A finder-function is used to locate the appropriate +** sqlite3_io_methods object for a particular database file. The pAppData +** field of the sqlite3_vfs VFS objects are initialized to be pointers to +** the correct finder-function for that VFS. +** +** Most finder functions return a pointer to a fixed sqlite3_io_methods +** object. The only interesting finder-function is autolockIoFinder, which +** looks at the filesystem type and tries to guess the best locking +** strategy from that. +** +** ** Each instance of this macro generates two objects: ** ** * A constant sqlite3_io_methods object call METHOD that has locking @@ -3790,8 +4033,8 @@ IOMETHODS( #if defined(__DARWIN__) && SQLITE_ENABLE_LOCKING_STYLE /* -** This procedure attempts to determine the best locking strategy for -** the given database file. It then returns the sqlite3_io_methods +** This "finder" function attempts to determine the best locking strategy +** for the database file "filePath". It then returns the sqlite3_io_methods ** object that implements that strategy. ** ** This is for MacOSX only. @@ -3801,8 +4044,8 @@ static const sqlite3_io_methods *autolockIoFinder( int fd /* file descriptor open on the database file */ ){ static const struct Mapping { - const char *zFilesystem; - const sqlite3_io_methods *pMethods; + const char *zFilesystem; /* Filesystem type name */ + const sqlite3_io_methods *pMethods; /* Appropriate locking method */ } aMap[] = { { "hfs", &posixIoMethods }, { "ufs", &posixIoMethods }, @@ -3820,6 +4063,8 @@ static const sqlite3_io_methods *autolockIoFinder( struct flock lockInfo; if( !filePath ){ + /* If filePath==NULL that means we are dealing with a transient file + ** that does not need to be locked. */ return &nolockIoMethods; } if( statfs(filePath, &fsInfo) != -1 ){ @@ -4008,30 +4253,6 @@ static int fillInUnixFile( return rc; } -#if SQLITE_ENABLE_LOCKING_STYLE -static int getDbPathForUnixFile(unixFile *pFile, char *dbPath){ -#if defined(__DARWIN__) - if( pFile->pMethod == &afpIoMethods ){ - /* afp style keeps a reference to the db path in the filePath field - ** of the struct */ - assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); - strcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath) - }else -#endif - if( pFile->pMethod == &dotlockIoMethods ){ - /* dot lock style uses the locking context to store the dot lock - ** file path */ - int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX); - memcpy(dbPath, (char *)pFile->lockingContext, len + 1); - }else{ - /* all other styles use the locking context to store the db file path */ - assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); - strcpy(dbPath, (char *)pFile->lockingContext); - } - return SQLITE_OK; -} -#endif - /* ** Open a file descriptor to the directory containing file zFilename. ** If successful, *pFd is set to the opened file descriptor and @@ -4148,15 +4369,15 @@ static int getTempname(int nBuf, char *zBuf){ ** OpenExclusive(). */ static int unixOpen( - sqlite3_vfs *pVfs, - const char *zPath, - sqlite3_file *pFile, - int flags, - int *pOutFlags + sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ + const char *zPath, /* Pathname of file to be opened */ + sqlite3_file *pFile, /* The file descriptor to be filled in */ + int flags, /* Input flags to control the opening */ + int *pOutFlags /* Output flags returned to SQLite core */ ){ int fd = 0; /* File descriptor returned by open() */ int dirfd = -1; /* Directory file descriptor */ - int openFlags = 0; /* Flags to pass to open() */ + int openFlags = 0; /* Flags to pass to open() */ int eType = flags&0xFFFFFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ int rc = SQLITE_OK; @@ -4304,7 +4525,11 @@ static int unixOpen( ** Delete the file at zPath. If the dirSync argument is true, fsync() ** the directory after deleting the file. */ -static int unixDelete(sqlite3_vfs *NotUsed, const char *zPath, int dirSync){ +static int unixDelete( + sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */ + const char *zPath, /* Name of file to be deleted */ + int dirSync /* If true, fsync() directory after deleting file */ +){ int rc = SQLITE_OK; UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); @@ -4342,10 +4567,10 @@ static int unixDelete(sqlite3_vfs *NotUsed, const char *zPath, int dirSync){ ** Otherwise return 0. */ static int unixAccess( - sqlite3_vfs *NotUsed, - const char *zPath, - int flags, - int *pResOut + sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */ + const char *zPath, /* Path of the file to examine */ + int flags, /* What do we want to learn about the zPath file? */ + int *pResOut /* Write result boolean here */ ){ int amode = 0; UNUSED_PARAMETER(NotUsed); @@ -4388,7 +4613,7 @@ static int unixFullPathname( /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the - ** current working directly has been unlinked. + ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); @@ -4523,11 +4748,12 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ } /* -** The following variable, if set to a non-zero value, becomes the result -** returned from sqlite3OsCurrentTime(). This is used for testing. +** The following variable, if set to a non-zero value, is interpreted as +** the number of seconds since 1970 and is used to set the result of +** sqlite3OsCurrentTime() during testing. */ #ifdef SQLITE_TEST -int sqlite3_current_time = 0; +int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ #endif /* @@ -4559,6 +4785,13 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ return 0; } +/* +** We added the xGetLastError() method with the intention of providing +** better low-level error messages when operating-system problems come up +** during SQLite operation. But so far, none of that has been implemented +** in the core. So this routine is never called. For now, it is merely +** a place-holder. +*/ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ UNUSED_PARAMETER(NotUsed); UNUSED_PARAMETER(NotUsed2); @@ -4577,12 +4810,27 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** systems. This routine, and the sqlite3_os_end() routine that follows, ** should be the only routines in this file that are visible from other ** files. +** +** This routine is called once during SQLite initialization and by a +** single thread. The memory allocation and mutex subsystems have not +** necessarily been initialized when this routine is called, and so they +** should not be used. */ int sqlite3_os_init(void){ - /* Macro to define the static contents of an sqlite3_vfs structure for - ** the unix backend. The two parameters are the values to use for - ** the sqlite3_vfs.zName and sqlite3_vfs.pAppData fields, respectively. - ** + /* + ** The following macro defines an initializer for an sqlite3_vfs object. + ** The name of the VFS is NAME. The pAppData is a pointer to a "finder" + ** function. The FINDER parameter to this macro is the name of the + ** finder-function. The finder-function returns a pointer to the + ** sqlite_io_methods object that implements the desired locking + ** behaviors. See the division above that contains the IOMETHODS + ** macro for addition information on finder-functions. + ** + ** Most finders simply return a pointer to a fixed sqlite3_io_methods + ** object. But the "autolockIoFinder" available on MacOSX does a little + ** more than that; it looks at the filesystem type that hosts the + ** database file and tries to choose an locking method appropriate for + ** that filesystem time. */ #define UNIXVFS(VFSNAME, FINDER) { \ 1, /* iVersion */ \ @@ -4605,7 +4853,13 @@ int sqlite3_os_init(void){ unixGetLastError /* xGetLastError */ \ } - unsigned int i; + /* + ** All default VFSes for unix are contained in the following array. + ** + ** Note that the sqlite3_vfs.pNext field of the VFS object is modified + ** by the SQLite core when the VFS is registered. So the following + ** array cannot be const. + */ static sqlite3_vfs aVfs[] = { #if SQLITE_ENABLE_LOCKING_STYLE && defined(__DARWIN__) UNIXVFS("unix", autolockIoFinder ), @@ -4626,6 +4880,9 @@ int sqlite3_os_init(void){ UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; + unsigned int i; /* Loop counter */ + + /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } @@ -4633,7 +4890,11 @@ int sqlite3_os_init(void){ } /* -** Shutdown the operating system interface. This is a no-op for unix. +** Shutdown the operating system interface. +** +** Some operating systems might need to do some cleanup in this routine, +** to release dynamically allocated objects. But not on unix. +** This routine is a no-op for unix. */ int sqlite3_os_end(void){ return SQLITE_OK; |