diff options
author | Scott MacVicar <scottmac@php.net> | 2008-03-07 10:55:14 +0000 |
---|---|---|
committer | Scott MacVicar <scottmac@php.net> | 2008-03-07 10:55:14 +0000 |
commit | 31dade5280849135b00fd1c5e53d057732a72776 (patch) | |
tree | 564b9f0f9d8cf89d7df9a9c12147ba8a5da6506f /ext/pdo_sqlite/sqlite/src/os_unix.c | |
parent | 7abf0787ad9fd613ddde880c9bc163161d7bf4ff (diff) | |
download | php-git-31dade5280849135b00fd1c5e53d057732a72776.tar.gz |
MFB: Update bundled SQLite to 3.5.6
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/os_unix.c')
-rw-r--r-- | ext/pdo_sqlite/sqlite/src/os_unix.c | 2284 |
1 files changed, 1525 insertions, 759 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/os_unix.c b/ext/pdo_sqlite/sqlite/src/os_unix.c index dd94bbb2db..6f9b3c02db 100644 --- a/ext/pdo_sqlite/sqlite/src/os_unix.c +++ b/ext/pdo_sqlite/sqlite/src/os_unix.c @@ -13,9 +13,10 @@ ** This file contains code that is specific to Unix systems. */ #include "sqliteInt.h" -#include "os.h" #if OS_UNIX /* This file is used on unix only */ +/* #define SQLITE_ENABLE_LOCKING_STYLE 0 */ + /* ** These #defines should enable >2GB file support on Posix if the ** underlying operating system supports it. If the OS lacks @@ -47,12 +48,17 @@ #include <time.h> #include <sys/time.h> #include <errno.h> +#ifdef SQLITE_ENABLE_LOCKING_STYLE +#include <sys/ioctl.h> +#include <sys/param.h> +#include <sys/mount.h> +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* ** If we are to be thread-safe, include the pthreads header and define ** the SQLITE_UNIX_THREADS macro. */ -#if defined(THREADSAFE) && THREADSAFE +#if SQLITE_THREADSAFE # include <pthread.h> # define SQLITE_UNIX_THREADS 1 #endif @@ -64,59 +70,44 @@ # define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 #endif +/* +** Maximum supported path-length. +*/ +#define MAX_PATHNAME 512 /* -** The unixFile structure is subclass of OsFile specific for the unix +** The unixFile structure is subclass of sqlite3_file specific for the unix ** protability layer. */ typedef struct unixFile unixFile; struct unixFile { - IoMethod const *pMethod; /* Always the first entry */ + sqlite3_io_methods const *pMethod; /* Always the first entry */ +#ifdef SQLITE_TEST + /* In test mode, increase the size of this structure a bit so that + ** it is larger than the struct CrashFile defined in test6.c. + */ + char aPadding[32]; +#endif struct openCnt *pOpen; /* Info about all open fd's on this inode */ struct lockInfo *pLock; /* Info about locks on this inode */ +#ifdef SQLITE_ENABLE_LOCKING_STYLE + void *lockingContext; /* Locking style specific state */ +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ int h; /* The file descriptor */ unsigned char locktype; /* The type of lock held on this fd */ - unsigned char isOpen; /* True if needs to be closed */ - unsigned char fullSync; /* Use F_FULLSYNC if available */ int dirfd; /* File descriptor for the directory */ - i64 offset; /* Seek offset */ -#ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* The thread that "owns" this OsFile */ +#if SQLITE_THREADSAFE + pthread_t tid; /* The thread that "owns" this unixFile */ #endif }; /* -** Provide the ability to override some OS-layer functions during -** testing. This is used to simulate OS crashes to verify that -** commits are atomic even in the event of an OS crash. -*/ -#ifdef SQLITE_CRASH_TEST - extern int sqlite3CrashTestEnable; - extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*); - extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int); - extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int); -# define CRASH_TEST_OVERRIDE(X,A,B,C) \ - if(sqlite3CrashTestEnable){ return X(A,B,C); } -#else -# define CRASH_TEST_OVERRIDE(X,A,B,C) /* no-op */ -#endif - - -/* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* -** Do not include any of the File I/O interface procedures if the -** SQLITE_OMIT_DISKIO macro is defined (indicating that the database -** will be in-memory only) -*/ -#ifndef SQLITE_OMIT_DISKIO - - -/* ** Define various macros that are missing from some systems. */ #ifndef O_LARGEFILE @@ -137,7 +128,7 @@ struct unixFile { ** The DJGPP compiler environment looks mostly like Unix, but it ** lacks the fcntl() system call. So redefine fcntl() to be something ** that always succeeds. This means that locking does not occur under -** DJGPP. But it's DOS - what did you expect? +** DJGPP. But it is DOS - what did you expect? */ #ifdef __DJGPP__ # define fcntl(A,B,C) 0 @@ -147,29 +138,29 @@ struct unixFile { ** The threadid macro resolves to the thread-id or to 0. Used for ** testing and debugging only. */ -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE #define threadid pthread_self() #else #define threadid 0 #endif /* -** Set or check the OsFile.tid field. This field is set when an OsFile -** is first opened. All subsequent uses of the OsFile verify that the -** same thread is operating on the OsFile. Some operating systems do +** Set or check the unixFile.tid field. This field is set when an unixFile +** is first opened. All subsequent uses of the unixFile verify that the +** same thread is operating on the unixFile. Some operating systems do ** not allow locks to be overridden by other threads and that restriction ** means that sqlite3* database handles cannot be moved from one thread ** to another. This logic makes sure a user does not try to do that ** by mistake. ** -** Version 3.3.1 (2007-01-15): OsFiles can be moved from one thread to +** Version 3.3.1 (2006-01-15): unixFile can be moved from one thread to ** another as long as we are running on a system that supports threads ** overriding each others locks (which now the most common behavior) -** or if no locks are held. But the OsFile.pLock field needs to be +** or if no locks are held. But the unixFile.pLock field needs to be ** recomputed because its key includes the thread-id. See the ** transferOwnership() function below for additional information */ -#if defined(SQLITE_UNIX_THREADS) +#if SQLITE_THREADSAFE # define SET_THREADID(X) (X)->tid = pthread_self() # define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \ !pthread_equal((X)->tid, pthread_self())) @@ -213,11 +204,11 @@ struct unixFile { ** locks to see if another thread has previously set a lock on that same ** inode. ** -** The OsFile structure for POSIX is no longer just an integer file +** The sqlite3_file structure for POSIX is no longer just an integer file ** descriptor. It is now a structure that holds the integer file ** descriptor and a pointer to a structure that describes the internal ** locks on the corresponding inode. There is one locking structure -** per inode, so if the same inode is opened twice, both OsFile structures +** per inode, so if the same inode is opened twice, both unixFile structures ** point to the same locking structure. The locking structure keeps ** a reference count (so we will know when to delete it) and a "cnt" ** field that tells us its internal lock status. cnt==0 means the @@ -236,11 +227,11 @@ struct unixFile { ** ** If you close a file descriptor that points to a file that has locks, ** all locks on that file that are owned by the current process are -** released. To work around this problem, each OsFile structure contains +** released. To work around this problem, each unixFile structure contains ** a pointer to an openCnt structure. There is one openCnt structure -** per open inode, which means that multiple OsFiles can point to a single -** openCnt. When an attempt is made to close an OsFile, if there are -** other OsFiles open on the same inode that are holding locks, the call +** per open inode, which means that multiple unixFile can point to a single +** openCnt. When an attempt is made to close an unixFile, if there are +** other unixFile open on the same inode that are holding locks, the call ** to close() the file descriptor is deferred until all of the locks clear. ** The openCnt structure keeps a list of file descriptors that need to ** be closed and that list is walked (and cleared) when the last lock @@ -290,7 +281,7 @@ struct unixFile { struct lockKey { dev_t dev; /* Device number */ ino_t ino; /* Inode number */ -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE pthread_t tid; /* Thread ID or zero if threads can override each other */ #endif }; @@ -300,9 +291,9 @@ struct lockKey { ** inode on each thread with a different process ID. (Threads have ** different process IDs on linux, but not on most other unixes.) ** -** A single inode can have multiple file descriptors, so each OsFile +** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this -** object keeps a count of the number of OsFiles pointing to it. +** object keeps a count of the number of unixFile pointing to it. */ struct lockInfo { struct lockKey key; /* The lookup key */ @@ -341,12 +332,46 @@ struct openCnt { ** openKey structures) into lockInfo and openCnt structures. Access to ** these hash tables must be protected by a mutex. */ -static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, - sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0}; -static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, - sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0}; +static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0}; +static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0}; + +#ifdef SQLITE_ENABLE_LOCKING_STYLE +/* +** The locking styles are associated with the different file locking +** capabilities supported by different file systems. +** +** POSIX locking style fully supports shared and exclusive byte-range locks +** ADP locking only supports exclusive byte-range locks +** FLOCK only supports a single file-global exclusive lock +** DOTLOCK isn't a true locking style, it refers to the use of a special +** file named the same as the database file with a '.lock' extension, this +** can be used on file systems that do not offer any reliable file locking +** NO locking means that no locking will be attempted, this is only used for +** read-only file systems currently +** UNSUPPORTED means that no locking will be attempted, this is only used for +** file systems that are known to be unsupported +*/ +typedef enum { + posixLockingStyle = 0, /* standard posix-advisory locks */ + afpLockingStyle, /* use afp locks */ + flockLockingStyle, /* use flock() */ + dotlockLockingStyle, /* use <file>.lock files */ + noLockingStyle, /* useful for read-only file system */ + unsupportedLockingStyle /* indicates unsupported file system */ +} sqlite3LockingStyle; +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + +/* +** Helper functions to obtain and relinquish the global mutex. +*/ +static void enterMutex(){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} +static void leaveMutex(){ + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); +} -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE /* ** This variable records whether or not threads can override each others ** locks. @@ -421,7 +446,7 @@ static int lockTrace(int fd, int op, struct flock *p){ sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, (int)p->l_pid, s); - if( s && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ + if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ struct flock l2; l2 = *p; fcntl(fd, F_GETLK, &l2); @@ -483,17 +508,18 @@ static void testThreadLockingBehavior(int fd_orig){ close(fd); threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0; } -#endif /* SQLITE_UNIX_THREADS */ +#endif /* SQLITE_THREADSAFE */ /* ** Release a lockInfo structure previously allocated by findLockInfo(). */ static void releaseLockInfo(struct lockInfo *pLock){ - assert( sqlite3OsInMutex(1) ); + if (pLock == NULL) + return; pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); - sqlite3ThreadSafeFree(pLock); + sqlite3_free(pLock); } } @@ -501,15 +527,91 @@ static void releaseLockInfo(struct lockInfo *pLock){ ** Release a openCnt structure previously allocated by findLockInfo(). */ static void releaseOpenCnt(struct openCnt *pOpen){ - assert( sqlite3OsInMutex(1) ); + if (pOpen == NULL) + return; pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); free(pOpen->aPending); - sqlite3ThreadSafeFree(pOpen); + sqlite3_free(pOpen); } } +#ifdef SQLITE_ENABLE_LOCKING_STYLE +/* +** Tests a byte-range locking query to see if byte range locks are +** supported, if not we fall back to dotlockLockingStyle. +*/ +static sqlite3LockingStyle sqlite3TestLockingStyle( + const char *filePath, + int fd +){ + /* test byte-range lock using fcntl */ + struct flock lockInfo; + + lockInfo.l_len = 1; + lockInfo.l_start = 0; + lockInfo.l_whence = SEEK_SET; + lockInfo.l_type = F_RDLCK; + + if( fcntl(fd, F_GETLK, &lockInfo)!=-1 ) { + return posixLockingStyle; + } + + /* testing for flock can give false positives. So if if the above test + ** fails, then we fall back to using dot-lock style locking. + */ + return dotlockLockingStyle; +} + +/* +** Examines the f_fstypename entry in the statfs structure as returned by +** stat() for the file system hosting the database file, assigns the +** appropriate locking style based on its value. These values and +** assignments are based on Darwin/OSX behavior and have not been tested on +** other systems. +*/ +static sqlite3LockingStyle sqlite3DetectLockingStyle( + const char *filePath, + int fd +){ + +#ifdef SQLITE_FIXED_LOCKING_STYLE + return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE; +#else + struct statfs fsInfo; + + if (statfs(filePath, &fsInfo) == -1) + return sqlite3TestLockingStyle(filePath, fd); + + if (fsInfo.f_flags & MNT_RDONLY) + return noLockingStyle; + + if( (!strcmp(fsInfo.f_fstypename, "hfs")) || + (!strcmp(fsInfo.f_fstypename, "ufs")) ) + return posixLockingStyle; + + if(!strcmp(fsInfo.f_fstypename, "afpfs")) + return afpLockingStyle; + + if(!strcmp(fsInfo.f_fstypename, "nfs")) + return sqlite3TestLockingStyle(filePath, fd); + + if(!strcmp(fsInfo.f_fstypename, "smbfs")) + return flockLockingStyle; + + if(!strcmp(fsInfo.f_fstypename, "msdos")) + return dotlockLockingStyle; + + if(!strcmp(fsInfo.f_fstypename, "webdav")) + return unsupportedLockingStyle; + + return sqlite3TestLockingStyle(filePath, fd); +#endif /* SQLITE_FIXED_LOCKING_STYLE */ +} + +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + /* ** Given a file descriptor, locate lockInfo and openCnt structures that ** describes that file descriptor. Create new ones if necessary. The @@ -531,11 +633,10 @@ static int findLockInfo( rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; - assert( sqlite3OsInMutex(1) ); memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE if( threadsOverrideEachOthersLocks<0 ){ testThreadLockingBehavior(fd); } @@ -547,7 +648,7 @@ static int findLockInfo( pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1)); if( pLock==0 ){ struct lockInfo *pOld; - pLock = sqlite3ThreadSafeMalloc( sizeof(*pLock) ); + pLock = sqlite3_malloc( sizeof(*pLock) ); if( pLock==0 ){ rc = 1; goto exit_findlockinfo; @@ -559,7 +660,7 @@ static int findLockInfo( pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ assert( pOld==pLock ); - sqlite3ThreadSafeFree(pLock); + sqlite3_free(pLock); rc = 1; goto exit_findlockinfo; } @@ -571,7 +672,7 @@ static int findLockInfo( pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); if( pOpen==0 ){ struct openCnt *pOld; - pOpen = sqlite3ThreadSafeMalloc( sizeof(*pOpen) ); + pOpen = sqlite3_malloc( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); rc = 1; @@ -585,7 +686,7 @@ static int findLockInfo( pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); if( pOld!=0 ){ assert( pOld==pOpen ); - sqlite3ThreadSafeFree(pOpen); + sqlite3_free(pOpen); releaseLockInfo(pLock); rc = 1; goto exit_findlockinfo; @@ -631,7 +732,7 @@ static const char *locktypeName(int locktype){ ** If the unixFile is locked and an ownership is wrong, then return ** SQLITE_MISUSE. SQLITE_OK is returned if everything works. */ -#ifdef SQLITE_UNIX_THREADS +#if SQLITE_THREADSAFE static int transferOwnership(unixFile *pFile){ int rc; pthread_t hSelf; @@ -642,21 +743,26 @@ static int transferOwnership(unixFile *pFile){ hSelf = pthread_self(); if( pthread_equal(pFile->tid, hSelf) ){ /* We are still in the same thread */ - TRACE1("No-transfer, same thread\n"); + OSTRACE1("No-transfer, same thread\n"); return SQLITE_OK; } if( pFile->locktype!=NO_LOCK ){ /* We cannot change ownership while we are holding a lock! */ return SQLITE_MISUSE; } - TRACE4("Transfer ownership of %d from %d to %d\n", pFile->h,pFile->tid,hSelf); + OSTRACE4("Transfer ownership of %d from %d to %d\n", + pFile->h, pFile->tid, hSelf); pFile->tid = hSelf; - releaseLockInfo(pFile->pLock); - rc = findLockInfo(pFile->h, &pFile->pLock, 0); - TRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h, - locktypeName(pFile->locktype), - locktypeName(pFile->pLock->locktype), pFile->pLock->cnt); - return rc; + if (pFile->pLock != NULL) { + releaseLockInfo(pFile->pLock); + rc = findLockInfo(pFile->h, &pFile->pLock, 0); + OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h, + locktypeName(pFile->locktype), + locktypeName(pFile->pLock->locktype), pFile->pLock->cnt); + return rc; + } else { + return SQLITE_OK; + } } #else /* On single-threaded builds, ownership transfer is a no-op */ @@ -664,259 +770,35 @@ static int transferOwnership(unixFile *pFile){ #endif /* -** Delete the named file -*/ -int sqlite3UnixDelete(const char *zFilename){ - unlink(zFilename); - return SQLITE_OK; -} - -/* -** Return TRUE if the named file exists. -*/ -int sqlite3UnixFileExists(const char *zFilename){ - return access(zFilename, 0)==0; -} - -/* Forward declaration */ -static int allocateUnixFile(unixFile *pInit, OsFile **pId); - -/* -** Attempt to open a file for both reading and writing. If that -** fails, try opening it read-only. If the file does not exist, -** try to create it. -** -** On success, a handle for the open file is written to *id -** and *pReadonly is set to 0 if the file was opened for reading and -** writing or 1 if the file was opened read-only. The function returns -** SQLITE_OK. +** Seek to the offset passed as the second argument, then read cnt +** bytes into pBuf. Return the number of bytes actually read. ** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id and *pReadonly unchanged. +** NB: If you define USE_PREAD or USE_PREAD64, then it might also +** be necessary to define _XOPEN_SOURCE to be 500. This varies from +** one system to another. Since SQLite does not define USE_PREAD +** any any form by default, we will not attempt to define _XOPEN_SOURCE. +** See tickets #2741 and #2681. */ -int sqlite3UnixOpenReadWrite( - const char *zFilename, - OsFile **pId, - int *pReadonly -){ - int rc; - unixFile f; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly); - assert( 0==*pId ); - f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, - SQLITE_DEFAULT_FILE_PERMISSIONS); - if( f.h<0 ){ -#ifdef EISDIR - if( errno==EISDIR ){ - return SQLITE_CANTOPEN; - } -#endif - f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( f.h<0 ){ - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - }else{ - *pReadonly = 0; - } - sqlite3OsEnterMutex(); - rc = findLockInfo(f.h, &f.pLock, &f.pOpen); - sqlite3OsLeaveMutex(); - if( rc ){ - close(f.h); - return SQLITE_NOMEM; - } - TRACE3("OPEN %-3d %s\n", f.h, zFilename); - return allocateUnixFile(&f, pId); -} - - -/* -** Attempt to open a new file for exclusive access by this process. -** The file will be opened for both reading and writing. To avoid -** a potential security problem, we do not allow the file to have -** previously existed. Nor do we allow the file to be a symbolic -** link. -** -** If delFlag is true, then make arrangements to automatically delete -** the file when it is closed. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ - int rc; - unixFile f; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag); - assert( 0==*pId ); - f.h = open(zFilename, - O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, - SQLITE_DEFAULT_FILE_PERMISSIONS); - if( f.h<0 ){ - return SQLITE_CANTOPEN; - } - sqlite3OsEnterMutex(); - rc = findLockInfo(f.h, &f.pLock, &f.pOpen); - sqlite3OsLeaveMutex(); - if( rc ){ - close(f.h); - unlink(zFilename); - return SQLITE_NOMEM; - } - if( delFlag ){ - unlink(zFilename); - } - TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename); - return allocateUnixFile(&f, pId); -} - -/* -** Attempt to open a new file for read-only access. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){ - int rc; - unixFile f; - - CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0); - assert( 0==*pId ); - f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( f.h<0 ){ - return SQLITE_CANTOPEN; - } - sqlite3OsEnterMutex(); - rc = findLockInfo(f.h, &f.pLock, &f.pOpen); - sqlite3OsLeaveMutex(); - if( rc ){ - close(f.h); - return SQLITE_NOMEM; - } - TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename); - return allocateUnixFile(&f, pId); -} - -/* -** Attempt to open a file descriptor for the directory that contains a -** file. This file descriptor can be used to fsync() the directory -** in order to make sure the creation of a new file is actually written -** to disk. -** -** This routine is only meaningful for Unix. It is a no-op under -** windows since windows does not support hard links. -** -** On success, a handle for a previously open file at *id is -** updated with the new directory file descriptor and SQLITE_OK is -** returned. -** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id unchanged. -*/ -static int unixOpenDirectory( - OsFile *id, - const char *zDirname -){ - unixFile *pFile = (unixFile*)id; - if( pFile==0 ){ - /* Do not open the directory if the corresponding file is not already - ** open. */ - return SQLITE_CANTOPEN; - } - SET_THREADID(pFile); - assert( pFile->dirfd<0 ); - pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); - if( pFile->dirfd<0 ){ - return SQLITE_CANTOPEN; - } - TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname); - return SQLITE_OK; -} - -/* -** If the following global variable points to a string which is the -** name of a directory, then that directory will be used to store -** temporary files. -** -** See also the "PRAGMA temp_store_directory" SQL command. -*/ -char *sqlite3_temp_directory = 0; - -/* -** Create a temporary file name in zBuf. zBuf must be big enough to -** hold at least SQLITE_TEMPNAME_SIZE characters. -*/ -int sqlite3UnixTempFileName(char *zBuf){ - static const char *azDirs[] = { - 0, - "/var/tmp", - "/usr/tmp", - "/tmp", - ".", - }; - static const unsigned char zChars[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789"; - int i, j; - struct stat buf; - const char *zDir = "."; - azDirs[0] = sqlite3_temp_directory; - for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ - if( azDirs[i]==0 ) continue; - if( stat(azDirs[i], &buf) ) continue; - if( !S_ISDIR(buf.st_mode) ) continue; - if( access(azDirs[i], 07) ) continue; - zDir = azDirs[i]; - break; - } - do{ - sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir); - j = strlen(zBuf); - sqlite3Randomness(15, &zBuf[j]); - for(i=0; i<15; i++, j++){ - zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; - } - zBuf[j] = 0; - }while( access(zBuf,0)==0 ); - return SQLITE_OK; -} - -/* -** Check that a given pathname is a directory and is writable -** -*/ -int sqlite3UnixIsDirWritable(char *zBuf){ -#ifndef SQLITE_OMIT_PAGER_PRAGMAS - struct stat buf; - if( zBuf==0 ) return 0; - if( zBuf[0]==0 ) return 0; - if( stat(zBuf, &buf) ) return 0; - if( !S_ISDIR(buf.st_mode) ) return 0; - if( access(zBuf, 07) ) return 0; -#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ - return 1; -} - -/* -** Seek to the offset in id->offset then read cnt bytes into pBuf. -** Return the number of bytes actually read. Update the offset. -*/ -static int seekAndRead(unixFile *id, void *pBuf, int cnt){ +static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; -#ifdef USE_PREAD - got = pread(id->h, pBuf, cnt, id->offset); + i64 newOffset; + TIMER_START; +#if defined(USE_PREAD) + got = pread(id->h, pBuf, cnt, offset); + SimulateIOError( got = -1 ); +#elif defined(USE_PREAD64) + got = pread64(id->h, pBuf, cnt, offset); + SimulateIOError( got = -1 ); #else - lseek(id->h, id->offset, SEEK_SET); + newOffset = lseek(id->h, offset, SEEK_SET); + SimulateIOError( newOffset-- ); + if( newOffset!=offset ){ + return -1; + } got = read(id->h, pBuf, cnt); #endif - if( got>0 ){ - id->offset += got; - } + TIMER_END; + OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); return got; } @@ -925,21 +807,22 @@ static int seekAndRead(unixFile *id, void *pBuf, int cnt){ ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -static int unixRead(OsFile *id, void *pBuf, int amt){ +static int unixRead( + sqlite3_file *id, + void *pBuf, + int amt, + sqlite3_int64 offset +){ int got; assert( id ); - SimulateIOError(SQLITE_IOERR); - TIMER_START; - got = seekAndRead((unixFile*)id, pBuf, amt); - TIMER_END; - TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got, - last_page, TIMER_ELAPSED); - SEEK(0); - /* if( got<0 ) got = 0; */ + got = seekAndRead((unixFile*)id, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; + }else if( got<0 ){ + return SQLITE_IOERR_READ; }else{ - return SQLITE_IOERR; + memset(&((char*)pBuf)[got], 0, amt-got); + return SQLITE_IOERR_SHORT_READ; } } @@ -947,17 +830,23 @@ static int unixRead(OsFile *id, void *pBuf, int amt){ ** Seek to the offset in id->offset then read cnt bytes into pBuf. ** Return the number of bytes actually read. Update the offset. */ -static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){ +static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; -#ifdef USE_PREAD - got = pwrite(id->h, pBuf, cnt, id->offset); + i64 newOffset; + TIMER_START; +#if defined(USE_PREAD) + got = pwrite(id->h, pBuf, cnt, offset); +#elif defined(USE_PREAD64) + got = pwrite64(id->h, pBuf, cnt, offset); #else - lseek(id->h, id->offset, SEEK_SET); + newOffset = lseek(id->h, offset, SEEK_SET); + if( newOffset!=offset ){ + return -1; + } got = write(id->h, pBuf, cnt); #endif - if( got>0 ){ - id->offset += got; - } + TIMER_END; + OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); return got; } @@ -966,40 +855,32 @@ static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){ ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -static int unixWrite(OsFile *id, const void *pBuf, int amt){ +static int unixWrite( + sqlite3_file *id, + const void *pBuf, + int amt, + sqlite3_int64 offset +){ int wrote = 0; assert( id ); assert( amt>0 ); - SimulateIOError(SQLITE_IOERR); - SimulateDiskfullError; - TIMER_START; - while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){ + while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){ amt -= wrote; + offset += wrote; pBuf = &((char*)pBuf)[wrote]; } - TIMER_END; - TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote, - last_page, TIMER_ELAPSED); - SEEK(0); + SimulateIOError(( wrote=(-1), amt=1 )); + SimulateDiskfullError(( wrote=0, amt=1 )); if( amt>0 ){ - return SQLITE_FULL; + if( wrote<0 ){ + return SQLITE_IOERR_WRITE; + }else{ + return SQLITE_FULL; + } } return SQLITE_OK; } -/* -** Move the read/write pointer in a file. -*/ -static int unixSeek(OsFile *id, i64 offset){ - assert( id ); - SEEK(offset/1024 + 1); -#ifdef SQLITE_TEST - if( offset ) SimulateDiskfullError -#endif - ((unixFile*)id)->offset = offset; - return SQLITE_OK; -} - #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test @@ -1065,16 +946,23 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ }else{ rc = 1; } - /* If the FULLSYNC failed, try to do a normal fsync() */ + /* 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. + */ if( rc ) rc = fsync(fd); -#else /* if !defined(F_FULLSYNC) */ +#else if( dataOnly ){ rc = fdatasync(fd); }else{ rc = fsync(fd); } -#endif /* defined(F_FULLFSYNC) */ +#endif /* HAVE_FULLFSYNC */ #endif /* defined(SQLITE_NO_SYNC) */ return rc; @@ -1095,23 +983,34 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ -static int unixSync(OsFile *id, int dataOnly){ +static int unixSync(sqlite3_file *id, int flags){ + int rc; unixFile *pFile = (unixFile*)id; + + int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); + int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; + + /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ + assert((flags&0x0F)==SQLITE_SYNC_NORMAL + || (flags&0x0F)==SQLITE_SYNC_FULL + ); + assert( pFile ); - SimulateIOError(SQLITE_IOERR); - TRACE2("SYNC %-3d\n", pFile->h); - if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){ - return SQLITE_IOERR; + OSTRACE2("SYNC %-3d\n", pFile->h); + rc = full_fsync(pFile->h, isFullsync, isDataOnly); + SimulateIOError( rc=1 ); + if( rc ){ + return SQLITE_IOERR_FSYNC; } if( pFile->dirfd>=0 ){ - TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, - HAVE_FULLFSYNC, pFile->fullSync); + OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, + HAVE_FULLFSYNC, isFullsync); #ifndef SQLITE_DISABLE_DIRSYNC /* The directory sync is only attempted if full_fsync is ** turned off or unavailable. If a full_fsync occurred above, ** then the directory sync is superfluous. */ - if( (!HAVE_FULLFSYNC || !pFile->fullSync) && full_fsync(pFile->dirfd,0,0) ){ + if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){ /* ** We have received multiple reports of fsync() returning ** errors when applied to directories on certain file systems. @@ -1128,49 +1027,31 @@ static int unixSync(OsFile *id, int dataOnly){ } /* -** Sync the directory zDirname. This is a no-op on operating systems other -** than UNIX. -** -** This is used to make sure the master journal file has truely been deleted -** before making changes to individual journals on a multi-database commit. -** The F_FULLFSYNC option is not needed here. -*/ -int sqlite3UnixSyncDirectory(const char *zDirname){ -#ifdef SQLITE_DISABLE_DIRSYNC - return SQLITE_OK; -#else - int fd; - int r; - SimulateIOError(SQLITE_IOERR); - fd = open(zDirname, O_RDONLY|O_BINARY, 0); - TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); - if( fd<0 ){ - return SQLITE_CANTOPEN; - } - r = fsync(fd); - close(fd); - return ((r==0)?SQLITE_OK:SQLITE_IOERR); -#endif -} - -/* ** Truncate an open file to a specified size */ -static int unixTruncate(OsFile *id, i64 nByte){ +static int unixTruncate(sqlite3_file *id, i64 nByte){ + int rc; assert( id ); - SimulateIOError(SQLITE_IOERR); - return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; + SimulateIOError( return SQLITE_IOERR_TRUNCATE ); + rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); + if( rc ){ + return SQLITE_IOERR_TRUNCATE; + }else{ + return SQLITE_OK; + } } /* ** Determine the current size of a file in bytes */ -static int unixFileSize(OsFile *id, i64 *pSize){ +static int unixFileSize(sqlite3_file *id, i64 *pSize){ + int rc; struct stat buf; assert( id ); - SimulateIOError(SQLITE_IOERR); - if( fstat(((unixFile*)id)->h, &buf)!=0 ){ - return SQLITE_IOERR; + rc = fstat(((unixFile*)id)->h, &buf); + SimulateIOError( rc=1 ); + if( rc!=0 ){ + return SQLITE_IOERR_FSTAT; } *pSize = buf.st_size; return SQLITE_OK; @@ -1182,12 +1063,12 @@ static int unixFileSize(OsFile *id, i64 *pSize){ ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ -static int unixCheckReservedLock(OsFile *id){ +static int unixCheckReservedLock(sqlite3_file *id){ int r = 0; unixFile *pFile = (unixFile*)id; assert( pFile ); - sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */ + enterMutex(); /* Because pFile->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( pFile->pLock->locktype>SHARED_LOCK ){ @@ -1208,8 +1089,8 @@ static int unixCheckReservedLock(OsFile *id){ } } - sqlite3OsLeaveMutex(); - TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); + leaveMutex(); + OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); return r; } @@ -1238,7 +1119,7 @@ static int unixCheckReservedLock(OsFile *id){ ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ -static int unixLock(OsFile *id, int locktype){ +static int unixLock(sqlite3_file *id, int locktype){ /* The following describes the implementation of the various locks and ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid @@ -1284,16 +1165,16 @@ static int unixLock(OsFile *id, int locktype){ int s; assert( pFile ); - TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, + OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, locktypeName(locktype), locktypeName(pFile->locktype), locktypeName(pLock->locktype), pLock->cnt , getpid()); /* If there is already a lock of this type or more restrictive on the - ** OsFile, do nothing. Don't use the end_lock: exit path, as - ** sqlite3OsEnterMutex() hasn't been called yet. + ** unixFile, do nothing. Don't use the end_lock: exit path, as + ** enterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ - TRACE3("LOCK %d %s ok (already held)\n", pFile->h, + OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, locktypeName(locktype)); return SQLITE_OK; } @@ -1306,18 +1187,18 @@ static int unixLock(OsFile *id, int locktype){ /* This mutex is needed because pFile->pLock is shared across threads */ - sqlite3OsEnterMutex(); + enterMutex(); /* Make sure the current thread owns the pFile. */ rc = transferOwnership(pFile); if( rc!=SQLITE_OK ){ - sqlite3OsLeaveMutex(); + leaveMutex(); return rc; } pLock = pFile->pLock; - /* If some thread using this PID has a lock via a different OsFile* + /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ if( (pFile->locktype!=pLock->locktype && @@ -1356,7 +1237,7 @@ static int unixLock(OsFile *id, int locktype){ lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; s = fcntl(pFile->h, F_SETLK, &lock); - if( s ){ + if( s==(-1) ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; goto end_lock; } @@ -1380,10 +1261,10 @@ static int unixLock(OsFile *id, int locktype){ lock.l_len = 1L; lock.l_type = F_UNLCK; if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ - rc = SQLITE_IOERR; /* This should never happen */ + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ goto end_lock; } - if( s ){ + if( s==(-1) ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ pFile->locktype = SHARED_LOCK; @@ -1413,7 +1294,7 @@ static int unixLock(OsFile *id, int locktype){ assert(0); } s = fcntl(pFile->h, F_SETLK, &lock); - if( s ){ + if( s==(-1) ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; } } @@ -1427,8 +1308,8 @@ static int unixLock(OsFile *id, int locktype){ } end_lock: - sqlite3OsLeaveMutex(); - TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), + leaveMutex(); + OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; } @@ -1440,14 +1321,14 @@ end_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 unixUnlock(OsFile *id, int locktype){ +static int unixUnlock(sqlite3_file *id, int locktype){ struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; assert( pFile ); - TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, + OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid()); assert( locktype<=SHARED_LOCK ); @@ -1457,7 +1338,7 @@ static int unixUnlock(OsFile *id, int locktype){ if( CHECK_THREADID(pFile) ){ return SQLITE_MISUSE; } - sqlite3OsEnterMutex(); + enterMutex(); pLock = pFile->pLock; assert( pLock->cnt!=0 ); if( pFile->locktype>SHARED_LOCK ){ @@ -1467,19 +1348,19 @@ static int unixUnlock(OsFile *id, int locktype){ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)==(-1) ){ /* This should never happen */ - rc = SQLITE_IOERR; + rc = SQLITE_IOERR_RDLOCK; } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); - if( fcntl(pFile->h, F_SETLK, &lock)==0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){ pLock->locktype = SHARED_LOCK; }else{ - rc = SQLITE_IOERR; /* This should never happen */ + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ } } if( locktype==NO_LOCK ){ @@ -1494,10 +1375,10 @@ static int unixUnlock(OsFile *id, int locktype){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; - if( fcntl(pFile->h, F_SETLK, &lock)==0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){ pLock->locktype = NO_LOCK; }else{ - rc = SQLITE_IOERR; /* This should never happen */ + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ } } @@ -1518,7 +1399,7 @@ static int unixUnlock(OsFile *id, int locktype){ pOpen->aPending = 0; } } - sqlite3OsLeaveMutex(); + leaveMutex(); pFile->locktype = locktype; return rc; } @@ -1526,184 +1407,1239 @@ static int unixUnlock(OsFile *id, int locktype){ /* ** Close a file. */ -static int unixClose(OsFile **pId){ - unixFile *id = (unixFile*)*pId; +static int unixClose(sqlite3_file *id){ + unixFile *pFile = (unixFile *)id; + if( !pFile ) return SQLITE_OK; + unixUnlock(id, NO_LOCK); + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); - if( !id ) return SQLITE_OK; - unixUnlock(*pId, NO_LOCK); - if( id->dirfd>=0 ) close(id->dirfd); - id->dirfd = -1; - sqlite3OsEnterMutex(); - - if( id->pOpen->nLock ){ + if( pFile->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->aPending. It will be automatically closed when ** the last lock is cleared. */ int *aNew; - struct openCnt *pOpen = id->pOpen; + struct openCnt *pOpen = pFile->pOpen; aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) ); if( aNew==0 ){ /* If a malloc fails, just leak the file descriptor */ }else{ pOpen->aPending = aNew; - pOpen->aPending[pOpen->nPending] = id->h; + pOpen->aPending[pOpen->nPending] = pFile->h; pOpen->nPending++; } }else{ /* There are no outstanding locks so we can close the file immediately */ - close(id->h); + close(pFile->h); } - releaseLockInfo(id->pLock); - releaseOpenCnt(id->pOpen); + releaseLockInfo(pFile->pLock); + releaseOpenCnt(pFile->pOpen); - sqlite3OsLeaveMutex(); - id->isOpen = 0; - TRACE2("CLOSE %-3d\n", id->h); + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); - sqlite3ThreadSafeFree(id); - *pId = 0; + memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } + +#ifdef SQLITE_ENABLE_LOCKING_STYLE +#pragma mark AFP Support + /* -** Turn a relative pathname into a full pathname. Return a pointer -** to the full pathname stored in space obtained from sqliteMalloc(). -** The calling function is responsible for freeing this space once it -** is no longer needed. -*/ -char *sqlite3UnixFullPathname(const char *zRelative){ - char *zFull = 0; - if( zRelative[0]=='/' ){ - sqlite3SetString(&zFull, zRelative, (char*)0); - }else{ - char *zBuf = sqliteMalloc(5000); - if( zBuf==0 ){ - return 0; + ** The afpLockingContext structure contains all afp lock specific state + */ +typedef struct afpLockingContext afpLockingContext; +struct afpLockingContext { + unsigned long long sharedLockByte; + char *filePath; +}; + +struct ByteRangeLockPB2 +{ + unsigned long long offset; /* offset to first byte to lock */ + unsigned long long length; /* nbr of bytes to lock */ + unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */ + unsigned char unLockFlag; /* 1 = unlock, 0 = lock */ + unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */ + int fd; /* file desc to assoc this lock with */ +}; + +#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) + +/* +** Return 0 on success, 1 on failure. To match the behavior of the +** normal posix file locking (used in unixLock for example), we should +** provide 'richer' return codes - specifically to differentiate between +** 'file busy' and 'file system error' results. +*/ +static int _AFPFSSetLock( + const char *path, + int fd, + unsigned long long offset, + unsigned long long length, + int setLockFlag +){ + struct ByteRangeLockPB2 pb; + int err; + + pb.unLockFlag = setLockFlag ? 0 : 1; + pb.startEndFlag = 0; + pb.offset = offset; + pb.length = length; + pb.fd = fd; + OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n", + (setLockFlag?"ON":"OFF"), fd, offset, length); + err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); + if ( err==-1 ) { + OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno, + strerror(errno)); + return 1; /* error */ + } else { + return 0; + } +} + +/* + ** 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, return + ** non-zero. If the file is unlocked or holds only SHARED locks, then + ** return zero. + */ +static int afpUnixCheckReservedLock(sqlite3_file *id){ + int r = 0; + unixFile *pFile = (unixFile*)id; + + assert( pFile ); + afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; + + /* Check if a thread in this process holds such a lock */ + if( pFile->locktype>SHARED_LOCK ){ + r = 1; + } + + /* Otherwise see if some other process holds it. + */ + if ( !r ) { + /* lock the byte */ + int failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1); + if (failed) { + /* if we failed to get the lock then someone else must have it */ + r = 1; + } else { + /* if we succeeded in taking the reserved lock, unlock it to restore + ** the original state */ + _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0); } - zBuf[0] = 0; - sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative, - (char*)0); - sqliteFree(zBuf); } + OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); + + return r; +} -#if 0 - /* - ** Remove "/./" path elements and convert "/A/./" path elements - ** to just "/". - */ - if( zFull ){ - int i, j; - for(i=j=0; zFull[i]; i++){ - if( zFull[i]=='/' ){ - if( zFull[i+1]=='/' ) continue; - if( zFull[i+1]=='.' && zFull[i+2]=='/' ){ - i += 1; - continue; - } - if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){ - while( j>0 && zFull[j-1]!='/' ){ j--; } - i += 3; - continue; +/* AFP-style locking following the behavior of unixLock, see the unixLock +** function comments for details of lock management. */ +static int afpUnixLock(sqlite3_file *id, int locktype) +{ + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; + int gotPendingLock = 0; + + assert( pFile ); + OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h, + locktypeName(locktype), locktypeName(pFile->locktype), getpid()); + /* If there is already a lock of this type or more restrictive on the + ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as + ** enterMutex() hasn't been called yet. + */ + if( pFile->locktype>=locktype ){ + OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, + locktypeName(locktype)); + return SQLITE_OK; + } + + /* Make sure the locking sequence is correct + */ + assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( locktype!=PENDING_LOCK ); + assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); + + /* This mutex is needed because pFile->pLock is shared across threads + */ + enterMutex(); + + /* Make sure the current thread owns the pFile. + */ + rc = transferOwnership(pFile); + if( rc!=SQLITE_OK ){ + leaveMutex(); + return rc; + } + + /* A PENDING lock is needed before acquiring a SHARED lock and before + ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will + ** be released. + */ + if( locktype==SHARED_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK) + ){ + int failed = _AFPFSSetLock(context->filePath, pFile->h, + PENDING_BYTE, 1, 1); + if (failed) { + rc = SQLITE_BUSY; + goto afp_end_lock; + } + } + + /* If control gets to this point, then actually go ahead and make + ** operating system calls for the specified lock. + */ + if( locktype==SHARED_LOCK ){ + int lk, failed; + int tries = 0; + + /* Now get the read-lock */ + /* note that the quality of the randomness doesn't matter that much */ + lk = random(); + context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); + failed = _AFPFSSetLock(context->filePath, pFile->h, + SHARED_FIRST+context->sharedLockByte, 1, 1); + + /* Drop the temporary PENDING lock */ + if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)) { + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ + goto afp_end_lock; + } + + if( failed ){ + rc = SQLITE_BUSY; + } else { + pFile->locktype = SHARED_LOCK; + } + }else{ + /* The request was for a RESERVED or EXCLUSIVE lock. It is + ** assumed that there is a SHARED or greater lock on the file + ** already. + */ + int failed = 0; + assert( 0!=pFile->locktype ); + if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) { + /* Acquire a RESERVED lock */ + failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1); + } + if (!failed && locktype == EXCLUSIVE_LOCK) { + /* Acquire an EXCLUSIVE lock */ + + /* Remove the shared lock before trying the range. we'll need to + ** reestablish the shared lock if we can't get the afpUnixUnlock + */ + if (!_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + + context->sharedLockByte, 1, 0)) { + /* now attemmpt to get the exclusive lock range */ + failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST, + SHARED_SIZE, 1); + if (failed && _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST + + context->sharedLockByte, 1, 1)) { + rc = SQLITE_IOERR_RDLOCK; /* this should never happen */ } + } else { + /* */ + rc = SQLITE_IOERR_UNLOCK; /* this should never happen */ } - zFull[j++] = zFull[i]; } - zFull[j] = 0; + if( failed && rc == SQLITE_OK){ + rc = SQLITE_BUSY; + } } -#endif + + if( rc==SQLITE_OK ){ + pFile->locktype = locktype; + }else if( locktype==EXCLUSIVE_LOCK ){ + pFile->locktype = PENDING_LOCK; + } + +afp_end_lock: + leaveMutex(); + OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), + rc==SQLITE_OK ? "ok" : "failed"); + 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 afpUnixUnlock(sqlite3_file *id, int locktype) { + struct flock lock; + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; - return zFull; + assert( pFile ); + OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype, + pFile->locktype, getpid()); + + assert( locktype<=SHARED_LOCK ); + if( pFile->locktype<=locktype ){ + return SQLITE_OK; + } + if( CHECK_THREADID(pFile) ){ + return SQLITE_MISUSE; + } + enterMutex(); + if( pFile->locktype>SHARED_LOCK ){ + if( locktype==SHARED_LOCK ){ + int failed = 0; + + /* unlock the exclusive range - then re-establish the shared lock */ + if (pFile->locktype==EXCLUSIVE_LOCK) { + failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST, + SHARED_SIZE, 0); + if (!failed) { + /* successfully removed the exclusive lock */ + if (_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+ + context->sharedLockByte, 1, 1)) { + /* failed to re-establish our shared lock */ + rc = SQLITE_IOERR_RDLOCK; /* This should never happen */ + } + } else { + /* This should never happen - failed to unlock the exclusive range */ + rc = SQLITE_IOERR_UNLOCK; + } + } + } + if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) { + if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)){ + /* failed to release the pending lock */ + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ + } + } + if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) { + if (_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0)) { + /* failed to release the reserved lock */ + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ + } + } + } + if( locktype==NO_LOCK ){ + int failed = _AFPFSSetLock(context->filePath, pFile->h, + SHARED_FIRST + context->sharedLockByte, 1, 0); + if (failed) { + rc = SQLITE_IOERR_UNLOCK; /* This should never happen */ + } + } + if (rc == SQLITE_OK) + pFile->locktype = locktype; + leaveMutex(); + return rc; +} + +/* + ** Close a file & cleanup AFP specific locking context + */ +static int afpUnixClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)pId; + + if( !pFile ) return SQLITE_OK; + afpUnixUnlock(*pId, NO_LOCK); + /* free the AFP locking structure */ + if (pFile->lockingContext != NULL) { + if (((afpLockingContext *)pFile->lockingContext)->filePath != NULL) + sqlite3_free(((afpLockingContext*)pFile->lockingContext)->filePath); + sqlite3_free(pFile->lockingContext); + } + + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + close(pFile->h); + OSTRACE2("CLOSE %-3d\n", pFile->h); + OpenCounter(-1); + return SQLITE_OK; } + +#pragma mark flock() style locking + /* -** Change the value of the fullsync flag in the given file descriptor. + ** The flockLockingContext is not used + */ +typedef void flockLockingContext; + +static int flockUnixCheckReservedLock(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; + + if (pFile->locktype == RESERVED_LOCK) { + return 1; /* already have a reserved lock */ + } else { + /* attempt to get the lock */ + int rc = flock(pFile->h, LOCK_EX | LOCK_NB); + if (!rc) { + /* got the lock, unlock it */ + flock(pFile->h, LOCK_UN); + return 0; /* no one has it reserved */ + } + return 1; /* someone else might have it reserved */ + } +} + +static int flockUnixLock(sqlite3_file *id, int locktype) { + unixFile *pFile = (unixFile*)id; + + /* if we already have a lock, it is exclusive. + ** Just adjust level and punt on outta here. */ + if (pFile->locktype > NO_LOCK) { + pFile->locktype = locktype; + return SQLITE_OK; + } + + /* grab an exclusive lock */ + int rc = flock(pFile->h, LOCK_EX | LOCK_NB); + if (rc) { + /* didn't get, must be busy */ + return SQLITE_BUSY; + } else { + /* got it, set the type and return ok */ + pFile->locktype = locktype; + return SQLITE_OK; + } +} + +static int flockUnixUnlock(sqlite3_file *id, int locktype) { + unixFile *pFile = (unixFile*)id; + + assert( locktype<=SHARED_LOCK ); + + /* no-op if possible */ + if( pFile->locktype==locktype ){ + return SQLITE_OK; + } + + /* shared can just be set because we always have an exclusive */ + if (locktype==SHARED_LOCK) { + pFile->locktype = locktype; + return SQLITE_OK; + } + + /* no, really, unlock. */ + int rc = flock(pFile->h, LOCK_UN); + if (rc) + return SQLITE_IOERR_UNLOCK; + else { + pFile->locktype = NO_LOCK; + return SQLITE_OK; + } +} + +/* + ** Close a file. + */ +static int flockUnixClose(sqlite3_file *pId) { + unixFile *pFile = (unixFile*)*pId; + + if( !pFile ) return SQLITE_OK; + flockUnixUnlock(*pId, NO_LOCK); + + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); + + close(pFile->h); + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); + OpenCounter(-1); + return SQLITE_OK; +} + +#pragma mark Old-School .lock file based locking + +/* + ** The dotlockLockingContext structure contains all dotlock (.lock) lock + ** specific state + */ +typedef struct dotlockLockingContext dotlockLockingContext; +struct dotlockLockingContext { + char *lockPath; +}; + + +static int dotlockUnixCheckReservedLock(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; + dotlockLockingContext *context = + (dotlockLockingContext *) pFile->lockingContext; + + if (pFile->locktype == RESERVED_LOCK) { + return 1; /* already have a reserved lock */ + } else { + struct stat statBuf; + if (lstat(context->lockPath,&statBuf) == 0) + /* file exists, someone else has the lock */ + return 1; + else + /* file does not exist, we could have it if we want it */ + return 0; + } +} + +static int dotlockUnixLock(sqlite3_file *id, int locktype) { + unixFile *pFile = (unixFile*)id; + dotlockLockingContext *context = + (dotlockLockingContext *) pFile->lockingContext; + + /* if we already have a lock, it is exclusive. + ** Just adjust level and punt on outta here. */ + if (pFile->locktype > NO_LOCK) { + pFile->locktype = locktype; + + /* Always update the timestamp on the old file */ + utimes(context->lockPath,NULL); + return SQLITE_OK; + } + + /* check to see if lock file already exists */ + struct stat statBuf; + if (lstat(context->lockPath,&statBuf) == 0){ + return SQLITE_BUSY; /* it does, busy */ + } + + /* grab an exclusive lock */ + int fd = open(context->lockPath,O_RDONLY|O_CREAT|O_EXCL,0600); + if (fd < 0) { + /* failed to open/create the file, someone else may have stolen the lock */ + return SQLITE_BUSY; + } + close(fd); + + /* got it, set the type and return ok */ + pFile->locktype = locktype; + return SQLITE_OK; +} + +static int dotlockUnixUnlock(sqlite3_file *id, int locktype) { + unixFile *pFile = (unixFile*)id; + dotlockLockingContext *context = + (dotlockLockingContext *) pFile->lockingContext; + + assert( locktype<=SHARED_LOCK ); + + /* no-op if possible */ + if( pFile->locktype==locktype ){ + return SQLITE_OK; + } + + /* shared can just be set because we always have an exclusive */ + if (locktype==SHARED_LOCK) { + pFile->locktype = locktype; + return SQLITE_OK; + } + + /* no, really, unlock. */ + unlink(context->lockPath); + pFile->locktype = NO_LOCK; + return SQLITE_OK; +} + +/* + ** Close a file. + */ +static int dotlockUnixClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; + + if( !pFile ) return SQLITE_OK; + dotlockUnixUnlock(*pId, NO_LOCK); + /* free the dotlock locking structure */ + if (pFile->lockingContext != NULL) { + if (((dotlockLockingContext *)pFile->lockingContext)->lockPath != NULL) + sqlite3_free( ( (dotlockLockingContext *) + pFile->lockingContext)->lockPath); + sqlite3_free(pFile->lockingContext); + } + + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); + + close(pFile->h); + + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); + OpenCounter(-1); + return SQLITE_OK; +} + + +#pragma mark No locking + +/* + ** The nolockLockingContext is void + */ +typedef void nolockLockingContext; + +static int nolockUnixCheckReservedLock(sqlite3_file *id) { + return 0; +} + +static int nolockUnixLock(sqlite3_file *id, int locktype) { + return SQLITE_OK; +} + +static int nolockUnixUnlock(sqlite3_file *id, int locktype) { + return SQLITE_OK; +} + +/* + ** Close a file. + */ +static int nolockUnixClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; + + if( !pFile ) return SQLITE_OK; + if( pFile->dirfd>=0 ) close(pFile->dirfd); + pFile->dirfd = -1; + enterMutex(); + + close(pFile->h); + + leaveMutex(); + OSTRACE2("CLOSE %-3d\n", pFile->h); + OpenCounter(-1); + return SQLITE_OK; +} + +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + + +/* +** Information and control of an open file handle. */ -static void unixSetFullSync(OsFile *id, int v){ - ((unixFile*)id)->fullSync = v; +static int unixFileControl(sqlite3_file *id, int op, void *pArg){ + switch( op ){ + case SQLITE_FCNTL_LOCKSTATE: { + *(int*)pArg = ((unixFile*)id)->locktype; + return SQLITE_OK; + } + } + return SQLITE_ERROR; } /* -** Return the underlying file handle for an OsFile +** Return the sector size in bytes of the underlying block device for +** the specified file. This is almost always 512 bytes, but may be +** larger for some devices. +** +** SQLite code assumes this function cannot fail. It also assumes that +** if two files are created in the same file-system directory (i.e. +** a database and its journal file) that the sector size will be the +** same for both. */ -static int unixFileHandle(OsFile *id){ - return ((unixFile*)id)->h; +static int unixSectorSize(sqlite3_file *id){ + return SQLITE_DEFAULT_SECTOR_SIZE; } /* -** Return an integer that indices the type of lock currently held -** by this handle. (Used for testing and analysis only.) +** Return the device characteristics for the file. This is always 0. */ -static int unixLockState(OsFile *id){ - return ((unixFile*)id)->locktype; +static int unixDeviceCharacteristics(sqlite3_file *id){ + return 0; } /* -** This vector defines all the methods that can operate on an OsFile +** This vector defines all the methods that can operate on an sqlite3_file ** for unix. */ -static const IoMethod sqlite3UnixIoMethod = { +static const sqlite3_io_methods sqlite3UnixIoMethod = { + 1, /* iVersion */ unixClose, - unixOpenDirectory, unixRead, unixWrite, - unixSeek, unixTruncate, unixSync, - unixSetFullSync, - unixFileHandle, unixFileSize, unixLock, unixUnlock, - unixLockState, unixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +#ifdef SQLITE_ENABLE_LOCKING_STYLE +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with AFP style file locking. +*/ +static const sqlite3_io_methods sqlite3AFPLockingUnixIoMethod = { + 1, /* iVersion */ + unixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + afpUnixLock, + afpUnixUnlock, + afpUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics }; /* -** Allocate memory for a unixFile. Initialize the new unixFile -** to the value given in pInit and return a pointer to the new -** OsFile. If we run out of memory, close the file and return NULL. +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with flock() style file locking. */ -static int allocateUnixFile(unixFile *pInit, OsFile **pId){ - unixFile *pNew; - pInit->dirfd = -1; - pInit->fullSync = 0; - pInit->locktype = 0; - pInit->offset = 0; - SET_THREADID(pInit); - pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) ); +static const sqlite3_io_methods sqlite3FlockLockingUnixIoMethod = { + 1, /* iVersion */ + flockUnixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + flockUnixLock, + flockUnixUnlock, + flockUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with dotlock style file locking. +*/ +static const sqlite3_io_methods sqlite3DotlockLockingUnixIoMethod = { + 1, /* iVersion */ + dotlockUnixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + dotlockUnixLock, + dotlockUnixUnlock, + dotlockUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +/* +** This vector defines all the methods that can operate on an sqlite3_file +** for unix with dotlock style file locking. +*/ +static const sqlite3_io_methods sqlite3NolockLockingUnixIoMethod = { + 1, /* iVersion */ + nolockUnixClose, + unixRead, + unixWrite, + unixTruncate, + unixSync, + unixFileSize, + nolockUnixLock, + nolockUnixUnlock, + nolockUnixCheckReservedLock, + unixFileControl, + unixSectorSize, + unixDeviceCharacteristics +}; + +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + +/* +** Allocate memory for a new unixFile and initialize that unixFile. +** Write a pointer to the new unixFile into *pId. +** If we run out of memory, close the file and return an error. +*/ +#ifdef SQLITE_ENABLE_LOCKING_STYLE +/* +** When locking extensions are enabled, the filepath and locking style +** are needed to determine the unixFile pMethod to use for locking operations. +** The locking-style specific lockingContext data structure is created +** and assigned here also. +*/ +static int fillInUnixFile( + int h, /* Open file descriptor of file being opened */ + int dirfd, /* Directory file descriptor */ + sqlite3_file *pId, /* Write completed initialization here */ + const char *zFilename, /* Name of the file being opened */ +){ + sqlite3LockingStyle lockingStyle; + unixFile *pNew = (unixFile *)pId; + int rc; + + memset(pNew, 0, sizeof(unixFile)); + lockingStyle = sqlite3DetectLockingStyle(zFilename, h); + if ( lockingStyle == posixLockingStyle ) { + enterMutex(); + rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen); + leaveMutex(); + if( rc ){ + close(h); + unlink(zFilename); + return SQLITE_NOMEM; + } + } else { + /* pLock and pOpen are only used for posix advisory locking */ + pNew->pLock = NULL; + pNew->pOpen = NULL; + } + pNew->dirfd = -1; + pNew->h = h; + SET_THREADID(pNew); + pNew = sqlite3_malloc( sizeof(unixFile) ); if( pNew==0 ){ - close(pInit->h); - sqlite3OsEnterMutex(); - releaseLockInfo(pInit->pLock); - releaseOpenCnt(pInit->pOpen); - sqlite3OsLeaveMutex(); - *pId = 0; + close(h); + enterMutex(); + releaseLockInfo(pNew->pLock); + releaseOpenCnt(pNew->pOpen); + leaveMutex(); return SQLITE_NOMEM; }else{ - *pNew = *pInit; - pNew->pMethod = &sqlite3UnixIoMethod; - *pId = (OsFile*)pNew; + switch(lockingStyle) { + case afpLockingStyle: { + /* afp locking uses the file path so it needs to be included in + ** the afpLockingContext */ + int nFilename; + pNew->pMethod = &sqlite3AFPLockingUnixIoMethod; + pNew->lockingContext = + sqlite3_malloc(sizeof(afpLockingContext)); + nFilename = strlen(zFilename)+1; + ((afpLockingContext *)pNew->lockingContext)->filePath = + sqlite3_malloc(nFilename); + memcpy(((afpLockingContext *)pNew->lockingContext)->filePath, + zFilename, nFilename); + srandomdev(); + break; + } + case flockLockingStyle: + /* flock locking doesn't need additional lockingContext information */ + pNew->pMethod = &sqlite3FlockLockingUnixIoMethod; + break; + case dotlockLockingStyle: { + /* dotlock locking uses the file path so it needs to be included in + ** the dotlockLockingContext */ + int nFilename; + pNew->pMethod = &sqlite3DotlockLockingUnixIoMethod; + pNew->lockingContext = sqlite3_malloc( + sizeof(dotlockLockingContext)); + nFilename = strlen(zFilename) + 6; + ((dotlockLockingContext *)pNew->lockingContext)->lockPath = + sqlite3_malloc( nFilename ); + sqlite3_snprintf(nFilename, + ((dotlockLockingContext *)pNew->lockingContext)->lockPath, + "%s.lock", zFilename); + break; + } + case posixLockingStyle: + /* posix locking doesn't need additional lockingContext information */ + pNew->pMethod = &sqlite3UnixIoMethod; + break; + case noLockingStyle: + case unsupportedLockingStyle: + default: + pNew->pMethod = &sqlite3NolockLockingUnixIoMethod; + } OpenCounter(+1); return SQLITE_OK; } } +#else /* SQLITE_ENABLE_LOCKING_STYLE */ +static int fillInUnixFile( + int h, /* Open file descriptor on file being opened */ + int dirfd, + sqlite3_file *pId, /* Write to the unixFile structure here */ + const char *zFilename /* Name of the file being opened */ +){ + unixFile *pNew = (unixFile *)pId; + int rc; + +#ifdef FD_CLOEXEC + fcntl(h, F_SETFD, fcntl(h, F_GETFD, 0) | FD_CLOEXEC); +#endif + + enterMutex(); + rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen); + leaveMutex(); + if( rc ){ + if( dirfd>=0 ) close(dirfd); + close(h); + return SQLITE_NOMEM; + } + + OSTRACE3("OPEN %-3d %s\n", h, zFilename); + pNew->dirfd = -1; + pNew->h = h; + pNew->dirfd = dirfd; + SET_THREADID(pNew); + + pNew->pMethod = &sqlite3UnixIoMethod; + OpenCounter(+1); + return SQLITE_OK; +} +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + +/* +** Open a file descriptor to the directory containing file zFilename. +** If successful, *pFd is set to the opened file descriptor and +** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM +** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined +** value. +** +** If SQLITE_OK is returned, the caller is responsible for closing +** the file descriptor *pFd using close(). +*/ +static int openDirectory(const char *zFilename, int *pFd){ + int ii; + int fd = -1; + char zDirname[MAX_PATHNAME+1]; + + sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); + for(ii=strlen(zDirname); ii>=0 && zDirname[ii]!='/'; ii--); + if( ii>0 ){ + zDirname[ii] = '\0'; + fd = open(zDirname, O_RDONLY|O_BINARY, 0); + if( fd>=0 ){ +#ifdef FD_CLOEXEC + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); +#endif + OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname); + } + } + *pFd = fd; + return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN); +} + +/* +** Open the file zPath. +** +** Previously, the SQLite OS layer used three functions in place of this +** one: +** +** sqlite3OsOpenReadWrite(); +** sqlite3OsOpenReadOnly(); +** sqlite3OsOpenExclusive(); +** +** These calls correspond to the following combinations of flags: +** +** ReadWrite() -> (READWRITE | CREATE) +** ReadOnly() -> (READONLY) +** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) +** +** The old OpenExclusive() accepted a boolean argument - "delFlag". If +** true, the file was configured to be automatically deleted when the +** file handle closed. To achieve the same effect using this new +** interface, add the DELETEONCLOSE flag to those specified above for +** OpenExclusive(). +*/ +static int unixOpen( + sqlite3_vfs *pVfs, + const char *zPath, + sqlite3_file *pFile, + int flags, + int *pOutFlags +){ + int fd = 0; /* File descriptor returned by open() */ + int dirfd = -1; /* Directory file descriptor */ + int oflags = 0; /* Flags to pass to open() */ + int eType = flags&0xFFFFFF00; /* Type of file to open */ + + int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); + int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); + int isCreate = (flags & SQLITE_OPEN_CREATE); + int isReadonly = (flags & SQLITE_OPEN_READONLY); + int isReadWrite = (flags & SQLITE_OPEN_READWRITE); + + /* If creating a master or main-file journal, this function will open + ** a file-descriptor on the directory too. The first time unixSync() + ** is called the directory file descriptor will be fsync()ed and close()d. + */ + int isOpenDirectory = (isCreate && + (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL) + ); + + /* Check the following statements are true: + ** + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (b) if CREATE is set, then READWRITE must also be set, and + ** (c) if EXCLUSIVE is set, then CREATE must also be set. + ** (d) if DELETEONCLOSE is set, then CREATE must also be set. + */ + assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); + assert(isCreate==0 || isReadWrite); + assert(isExclusive==0 || isCreate); + assert(isDelete==0 || isCreate); + + + /* The main DB, main journal, and master journal are never automatically + ** deleted + */ + assert( eType!=SQLITE_OPEN_MAIN_DB || !isDelete ); + assert( eType!=SQLITE_OPEN_MAIN_JOURNAL || !isDelete ); + assert( eType!=SQLITE_OPEN_MASTER_JOURNAL || !isDelete ); + + /* Assert that the upper layer has set one of the "file-type" flags. */ + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_TRANSIENT_DB + ); + + if( isReadonly ) oflags |= O_RDONLY; + if( isReadWrite ) oflags |= O_RDWR; + if( isCreate ) oflags |= O_CREAT; + if( isExclusive ) oflags |= (O_EXCL|O_NOFOLLOW); + oflags |= (O_LARGEFILE|O_BINARY); + + memset(pFile, 0, sizeof(unixFile)); + fd = open(zPath, oflags, isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS); + if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){ + /* Failed to open the file for read/write access. Try read-only. */ + flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + flags |= SQLITE_OPEN_READONLY; + return unixOpen(pVfs, zPath, pFile, flags, pOutFlags); + } + if( fd<0 ){ + return SQLITE_CANTOPEN; + } + if( isDelete ){ + unlink(zPath); + } + if( pOutFlags ){ + *pOutFlags = flags; + } + + assert(fd!=0); + if( isOpenDirectory ){ + int rc = openDirectory(zPath, &dirfd); + if( rc!=SQLITE_OK ){ + close(fd); + return rc; + } + } + return fillInUnixFile(fd, dirfd, pFile, zPath); +} + +/* +** Delete the file at zPath. If the dirSync argument is true, fsync() +** the directory after deleting the file. +*/ +static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + int rc = SQLITE_OK; + SimulateIOError(return SQLITE_IOERR_DELETE); + unlink(zPath); + if( dirSync ){ + int fd; + rc = openDirectory(zPath, &fd); + if( rc==SQLITE_OK ){ + if( fsync(fd) ){ + rc = SQLITE_IOERR_DIR_FSYNC; + } + close(fd); + } + } + return rc; +} + +/* +** Test the existance of or access permissions of file zPath. The +** test performed depends on the value of flags: +** +** SQLITE_ACCESS_EXISTS: Return 1 if the file exists +** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. +** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. +** +** Otherwise return 0. +*/ +static int unixAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ + int amode = 0; + switch( flags ){ + case SQLITE_ACCESS_EXISTS: + amode = F_OK; + break; + case SQLITE_ACCESS_READWRITE: + amode = W_OK|R_OK; + break; + case SQLITE_ACCESS_READ: + amode = R_OK; + break; + + default: + assert(!"Invalid flags argument"); + } + return (access(zPath, amode)==0); +} + +/* +** Create a temporary file name in zBuf. zBuf must be allocated +** by the calling process and must be big enough to hold at least +** pVfs->mxPathname bytes. +*/ +static int unixGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + static const char *azDirs[] = { + 0, + "/var/tmp", + "/usr/tmp", + "/tmp", + ".", + }; + static const unsigned char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + struct stat buf; + const char *zDir = "."; + + /* 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. + */ + SimulateIOError( return SQLITE_ERROR ); + + azDirs[0] = sqlite3_temp_directory; + for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ + if( azDirs[i]==0 ) continue; + if( stat(azDirs[i], &buf) ) continue; + if( !S_ISDIR(buf.st_mode) ) continue; + if( access(azDirs[i], 07) ) continue; + zDir = azDirs[i]; + break; + } + if( strlen(zDir) - sizeof(SQLITE_TEMP_FILE_PREFIX) - 17 <=0 ){ + return SQLITE_ERROR; + } + do{ + assert( pVfs->mxPathname==MAX_PATHNAME ); + sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); + j = strlen(zBuf); + sqlite3Randomness(15, &zBuf[j]); + for(i=0; i<15; i++, j++){ + zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + } + zBuf[j] = 0; + }while( access(zBuf,0)==0 ); + return SQLITE_OK; +} + + +/* +** Turn a relative pathname into a full pathname. The relative path +** is stored as a nul-terminated string in the buffer pointed to by +** zPath. +** +** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes +** (in this case, MAX_PATHNAME bytes). The full-path is written to +** this buffer before returning. +*/ +static int unixFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zPath, /* Possibly relative input path */ + int nOut, /* Size of output buffer in bytes */ + char *zOut /* Output buffer */ +){ + + /* 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. + */ + SimulateIOError( return SQLITE_ERROR ); + + assert( pVfs->mxPathname==MAX_PATHNAME ); + zOut[nOut-1] = '\0'; + if( zPath[0]=='/' ){ + sqlite3_snprintf(nOut, zOut, "%s", zPath); + }else{ + int nCwd; + if( getcwd(zOut, nOut-1)==0 ){ + return SQLITE_CANTOPEN; + } + nCwd = strlen(zOut); + sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath); + } + return SQLITE_OK; + +#if 0 + /* + ** Remove "/./" path elements and convert "/A/./" path elements + ** to just "/". + */ + if( zFull ){ + int i, j; + for(i=j=0; zFull[i]; i++){ + if( zFull[i]=='/' ){ + if( zFull[i+1]=='/' ) continue; + if( zFull[i+1]=='.' && zFull[i+2]=='/' ){ + i += 1; + continue; + } + if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){ + while( j>0 && zFull[j-1]!='/' ){ j--; } + i += 3; + continue; + } + } + zFull[j++] = zFull[i]; + } + zFull[j] = 0; + } +#endif +} -#endif /* SQLITE_OMIT_DISKIO */ -/*************************************************************************** -** Everything above deals with file I/O. Everything that follows deals -** with other miscellanous aspects of the operating system interface -****************************************************************************/ +#ifndef SQLITE_OMIT_LOAD_EXTENSION +/* +** Interfaces for opening a shared library, finding entry points +** within the shared library, and closing the shared library. +*/ +#include <dlfcn.h> +static void *unixDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ + return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL); +} +/* +** SQLite calls this function immediately after a call to unixDlSym() or +** unixDlOpen() fails (returns a null pointer). If a more detailed error +** message is available, it is written to zBufOut. If no error message +** is available, zBufOut is left unmodified and SQLite uses a default +** error message. +*/ +static void unixDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ + char *zErr; + enterMutex(); + zErr = dlerror(); + if( zErr ){ + sqlite3_snprintf(nBuf, zBufOut, "%s", zErr); + } + leaveMutex(); +} +static void *unixDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ + return dlsym(pHandle, zSymbol); +} +static void unixDlClose(sqlite3_vfs *pVfs, void *pHandle){ + dlclose(pHandle); +} +#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ + #define unixDlOpen 0 + #define unixDlError 0 + #define unixDlSym 0 + #define unixDlClose 0 +#endif /* -** Get information to seed the random number generator. The seed -** is written into the buffer zBuf[256]. The calling function must -** supply a sufficiently large buffer. +** Write nBuf bytes of random data to the supplied buffer zBuf. */ -int sqlite3UnixRandomSeed(char *zBuf){ +static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + + assert(nBuf>=(sizeof(time_t)+sizeof(int))); + /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the @@ -1716,7 +2652,7 @@ int sqlite3UnixRandomSeed(char *zBuf){ ** that we always use the same random number sequence. This makes the ** tests repeatable. */ - memset(zBuf, 0, 256); + memset(zBuf, 0, nBuf); #if !defined(SQLITE_TEST) { int pid, fd; @@ -1726,9 +2662,9 @@ int sqlite3UnixRandomSeed(char *zBuf){ time(&t); memcpy(zBuf, &t, sizeof(t)); pid = getpid(); - memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); + memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); }else{ - read(fd, zBuf, 256); + read(fd, zBuf, nBuf); close(fd); } } @@ -1736,224 +2672,23 @@ int sqlite3UnixRandomSeed(char *zBuf){ return SQLITE_OK; } + /* ** Sleep for a little while. Return the amount of time slept. -** The argument is the number of milliseconds we want to sleep. +** The argument is the number of microseconds we want to sleep. +** The return value is the number of microseconds of sleep actually +** requested from the underlying operating system, a number which +** might be greater than or equal to the argument, but not less +** than the argument. */ -int sqlite3UnixSleep(int ms){ +static int unixSleep(sqlite3_vfs *pVfs, int microseconds){ #if defined(HAVE_USLEEP) && HAVE_USLEEP - usleep(ms*1000); - return ms; + usleep(microseconds); + return microseconds; #else - sleep((ms+999)/1000); - return 1000*((ms+999)/1000); -#endif -} - -/* -** Static variables used for thread synchronization. -** -** inMutex the nesting depth of the recursive mutex. The thread -** holding mutexMain can read this variable at any time. -** But is must hold mutexAux to change this variable. Other -** threads must hold mutexAux to read the variable and can -** never write. -** -** mutexOwner The thread id of the thread holding mutexMain. Same -** access rules as for inMutex. -** -** mutexOwnerValid True if the value in mutexOwner is valid. The same -** access rules apply as for inMutex. -** -** mutexMain The main mutex. Hold this mutex in order to get exclusive -** access to SQLite data structures. -** -** mutexAux An auxiliary mutex needed to access variables defined above. -** -** Mutexes are always acquired in this order: mutexMain mutexAux. It -** is not necessary to acquire mutexMain in order to get mutexAux - just -** do not attempt to acquire them in the reverse order: mutexAux mutexMain. -** Either get the mutexes with mutexMain first or get mutexAux only. -** -** When running on a platform where the three variables inMutex, mutexOwner, -** and mutexOwnerValid can be set atomically, the mutexAux is not required. -** On many systems, all three are 32-bit integers and writing to a 32-bit -** integer is atomic. I think. But there are no guarantees. So it seems -** safer to protect them using mutexAux. -*/ -static int inMutex = 0; -#ifdef SQLITE_UNIX_THREADS -static pthread_t mutexOwner; /* Thread holding mutexMain */ -static int mutexOwnerValid = 0; /* True if mutexOwner is valid */ -static pthread_mutex_t mutexMain = PTHREAD_MUTEX_INITIALIZER; /* The mutex */ -static pthread_mutex_t mutexAux = PTHREAD_MUTEX_INITIALIZER; /* Aux mutex */ -#endif - -/* -** The following pair of routine implement mutual exclusion for -** multi-threaded processes. Only a single thread is allowed to -** executed code that is surrounded by EnterMutex() and LeaveMutex(). -** -** SQLite uses only a single Mutex. There is not much critical -** code and what little there is executes quickly and without blocking. -** -** As of version 3.3.2, this mutex must be recursive. -*/ -void sqlite3UnixEnterMutex(){ -#ifdef SQLITE_UNIX_THREADS - pthread_mutex_lock(&mutexAux); - if( !mutexOwnerValid || !pthread_equal(mutexOwner, pthread_self()) ){ - pthread_mutex_unlock(&mutexAux); - pthread_mutex_lock(&mutexMain); - assert( inMutex==0 ); - assert( !mutexOwnerValid ); - pthread_mutex_lock(&mutexAux); - mutexOwner = pthread_self(); - mutexOwnerValid = 1; - } - inMutex++; - pthread_mutex_unlock(&mutexAux); -#else - inMutex++; -#endif -} -void sqlite3UnixLeaveMutex(){ - assert( inMutex>0 ); -#ifdef SQLITE_UNIX_THREADS - pthread_mutex_lock(&mutexAux); - inMutex--; - assert( pthread_equal(mutexOwner, pthread_self()) ); - if( inMutex==0 ){ - assert( mutexOwnerValid ); - mutexOwnerValid = 0; - pthread_mutex_unlock(&mutexMain); - } - pthread_mutex_unlock(&mutexAux); -#else - inMutex--; -#endif -} - -/* -** Return TRUE if the mutex is currently held. -** -** If the thisThrd parameter is true, return true only if the -** calling thread holds the mutex. If the parameter is false, return -** true if any thread holds the mutex. -*/ -int sqlite3UnixInMutex(int thisThrd){ -#ifdef SQLITE_UNIX_THREADS - int rc; - pthread_mutex_lock(&mutexAux); - rc = inMutex>0 && (thisThrd==0 || pthread_equal(mutexOwner,pthread_self())); - pthread_mutex_unlock(&mutexAux); - return rc; -#else - return inMutex>0; -#endif -} - -/* -** Remember the number of thread-specific-data blocks allocated. -** Use this to verify that we are not leaking thread-specific-data. -** Ticket #1601 -*/ -#ifdef SQLITE_TEST -int sqlite3_tsd_count = 0; -# ifdef SQLITE_UNIX_THREADS - static pthread_mutex_t tsd_counter_mutex = PTHREAD_MUTEX_INITIALIZER; -# define TSD_COUNTER(N) \ - pthread_mutex_lock(&tsd_counter_mutex); \ - sqlite3_tsd_count += N; \ - pthread_mutex_unlock(&tsd_counter_mutex); -# else -# define TSD_COUNTER(N) sqlite3_tsd_count += N -# endif -#else -# define TSD_COUNTER(N) /* no-op */ -#endif - -/* -** If called with allocateFlag>0, then return a pointer to thread -** specific data for the current thread. Allocate and zero the -** thread-specific data if it does not already exist. -** -** If called with allocateFlag==0, then check the current thread -** specific data. Return it if it exists. If it does not exist, -** then return NULL. -** -** If called with allocateFlag<0, check to see if the thread specific -** data is allocated and is all zero. If it is then deallocate it. -** Return a pointer to the thread specific data or NULL if it is -** unallocated or gets deallocated. -*/ -ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){ - static const ThreadData zeroData = {0}; /* Initializer to silence warnings - ** from broken compilers */ -#ifdef SQLITE_UNIX_THREADS - static pthread_key_t key; - static int keyInit = 0; - ThreadData *pTsd; - - if( !keyInit ){ - sqlite3OsEnterMutex(); - if( !keyInit ){ - int rc; - rc = pthread_key_create(&key, 0); - if( rc ){ - sqlite3OsLeaveMutex(); - return 0; - } - keyInit = 1; - } - sqlite3OsLeaveMutex(); - } - - pTsd = pthread_getspecific(key); - if( allocateFlag>0 ){ - if( pTsd==0 ){ - if( !sqlite3TestMallocFail() ){ - pTsd = sqlite3OsMalloc(sizeof(zeroData)); - } -#ifdef SQLITE_MEMDEBUG - sqlite3_isFail = 0; -#endif - if( pTsd ){ - *pTsd = zeroData; - pthread_setspecific(key, pTsd); - TSD_COUNTER(+1); - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ - sqlite3OsFree(pTsd); - pthread_setspecific(key, 0); - TSD_COUNTER(-1); - pTsd = 0; - } - return pTsd; -#else - static ThreadData *pTsd = 0; - if( allocateFlag>0 ){ - if( pTsd==0 ){ - if( !sqlite3TestMallocFail() ){ - pTsd = sqlite3OsMalloc( sizeof(zeroData) ); - } -#ifdef SQLITE_MEMDEBUG - sqlite3_isFail = 0; -#endif - if( pTsd ){ - *pTsd = zeroData; - TSD_COUNTER(+1); - } - } - }else if( pTsd!=0 && allocateFlag<0 - && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ - sqlite3OsFree(pTsd); - TSD_COUNTER(-1); - pTsd = 0; - } - return pTsd; + int seconds = (microseconds+999999)/1000000; + sleep(seconds); + return seconds*1000000; #endif } @@ -1970,15 +2705,14 @@ int sqlite3_current_time = 0; ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3UnixCurrentTime(double *prNow){ +static int unixCurrentTime(sqlite3_vfs *pVfs, double *prNow){ #ifdef NO_GETTOD time_t t; time(&t); *prNow = t/86400.0 + 2440587.5; #else struct timeval sNow; - struct timezone sTz; /* Not used */ - gettimeofday(&sNow, &sTz); + gettimeofday(&sNow, 0); *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0; #endif #ifdef SQLITE_TEST @@ -1989,4 +2723,36 @@ int sqlite3UnixCurrentTime(double *prNow){ return 0; } +/* +** Return a pointer to the sqlite3DefaultVfs structure. We use +** a function rather than give the structure global scope because +** some compilers (MSVC) do not allow forward declarations of +** initialized structures. +*/ +sqlite3_vfs *sqlite3OsDefaultVfs(void){ + static sqlite3_vfs unixVfs = { + 1, /* iVersion */ + sizeof(unixFile), /* szOsFile */ + MAX_PATHNAME, /* mxPathname */ + 0, /* pNext */ + "unix", /* zName */ + 0, /* pAppData */ + + unixOpen, /* xOpen */ + unixDelete, /* xDelete */ + unixAccess, /* xAccess */ + unixGetTempname, /* xGetTempName */ + unixFullPathname, /* xFullPathname */ + unixDlOpen, /* xDlOpen */ + unixDlError, /* xDlError */ + unixDlSym, /* xDlSym */ + unixDlClose, /* xDlClose */ + unixRandomness, /* xRandomness */ + unixSleep, /* xSleep */ + unixCurrentTime /* xCurrentTime */ + }; + + return &unixVfs; +} + #endif /* OS_UNIX */ |