* [tarantool-patches] [PATCH v1 1/1] sql: drop useless code from os_unix.c
@ 2018-06-28 15:21 Kirill Shcherbatov
2018-07-02 11:22 ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-14 7:45 ` Kirill Yukhin
0 siblings, 2 replies; 9+ messages in thread
From: Kirill Shcherbatov @ 2018-06-28 15:21 UTC (permalink / raw)
To: tarantool-patches; +Cc: v.shpilevoy, Kirill Shcherbatov
Resolves #3284.
---
https://github.com/tarantool/tarantool/tree/kshch/gh-3284-no-os-unix
https://github.com/tarantool/tarantool/issues/3284
src/box/sql/os.c | 168 --
src/box/sql/os_unix.c | 6195 ++++++++++-------------------------------------
src/box/sql/sqliteInt.h | 1 -
3 files changed, 1342 insertions(+), 5022 deletions(-)
diff --git a/src/box/sql/os.c b/src/box/sql/os.c
index 38d3585..5a04edb 100644
--- a/src/box/sql/os.c
+++ b/src/box/sql/os.c
@@ -123,123 +123,12 @@ sqlite3OsWrite(sqlite3_file * id, const void *pBuf, int amt, i64 offset)
return id->pMethods->xWrite(id, pBuf, amt, offset);
}
-int
-sqlite3OsTruncate(sqlite3_file * id, i64 size)
-{
- return id->pMethods->xTruncate(id, size);
-}
-
-int
-sqlite3OsSync(sqlite3_file * id, int flags)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xSync(id, flags);
-}
-
-int
-sqlite3OsFileSize(sqlite3_file * id, i64 * pSize)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xFileSize(id, pSize);
-}
-
-int
-sqlite3OsLock(sqlite3_file * id, int lockType)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xLock(id, lockType);
-}
-
-int
-sqlite3OsUnlock(sqlite3_file * id, int lockType)
-{
- return id->pMethods->xUnlock(id, lockType);
-}
-
-int
-sqlite3OsCheckReservedLock(sqlite3_file * id, int *pResOut)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xCheckReservedLock(id, pResOut);
-}
-
-/*
- * Use sqlite3OsFileControl() when we are doing something that might fail
- * and we need to know about the failures. Use sqlite3OsFileControlHint()
- * when simply tossing information over the wall to the VFS and we do not
- * really care if the VFS receives and understands the information since it
- * is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
- * routine has no return value since the return value would be meaningless.
- */
-int
-sqlite3OsFileControl(sqlite3_file * id, int op, void *pArg)
-{
-#ifdef SQLITE_TEST
- if (op != SQLITE_FCNTL_COMMIT_PHASETWO) {
- /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
- * is using a regular VFS, it is called after the corresponding
- * transaction has been committed. Injecting a fault at this point
- * confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
- * but the transaction is committed anyway.
- *
- * The core must call OsFileControl() though, not OsFileControlHint(),
- * as if a custom VFS (e.g. zipvfs) returns an error here, it probably
- * means the commit really has failed and an error should be returned
- * to the user.
- */
- DO_OS_MALLOC_TEST(id);
- }
-#endif
- return id->pMethods->xFileControl(id, op, pArg);
-}
-
void
sqlite3OsFileControlHint(sqlite3_file * id, int op, void *pArg)
{
(void)id->pMethods->xFileControl(id, op, pArg);
}
-int
-sqlite3OsSectorSize(sqlite3_file * id)
-{
- int (*xSectorSize) (sqlite3_file *) = id->pMethods->xSectorSize;
- return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
-}
-
-int
-sqlite3OsDeviceCharacteristics(sqlite3_file * id)
-{
- return id->pMethods->xDeviceCharacteristics(id);
-}
-
-int
-sqlite3OsShmLock(sqlite3_file * id, int offset, int n, int flags)
-{
- return id->pMethods->xShmLock(id, offset, n, flags);
-}
-
-void
-sqlite3OsShmBarrier(sqlite3_file * id)
-{
- id->pMethods->xShmBarrier(id);
-}
-
-int
-sqlite3OsShmUnmap(sqlite3_file * id, int deleteFlag)
-{
- return id->pMethods->xShmUnmap(id, deleteFlag);
-}
-
-int
-sqlite3OsShmMap(sqlite3_file * id, /* Database file handle */
- int iPage, int pgsz, int bExtend, /* True to extend file if necessary */
- void volatile **pp /* OUT: Pointer to mapping */
- )
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
-}
-
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
int
@@ -296,53 +185,6 @@ sqlite3OsOpen(sqlite3_vfs * pVfs,
}
int
-sqlite3OsDelete(sqlite3_vfs * pVfs, const char *zPath, int dirSync)
-{
- DO_OS_MALLOC_TEST(0);
- assert(dirSync == 0 || dirSync == 1);
- return pVfs->xDelete(pVfs, zPath, dirSync);
-}
-
-int
-sqlite3OsAccess(sqlite3_vfs * pVfs, const char *zPath, int flags, int *pResOut)
-{
- DO_OS_MALLOC_TEST(0);
- return pVfs->xAccess(pVfs, zPath, flags, pResOut);
-}
-
-int
-sqlite3OsFullPathname(sqlite3_vfs * pVfs,
- const char *zPath, int nPathOut, char *zPathOut)
-{
- DO_OS_MALLOC_TEST(0);
- zPathOut[0] = 0;
- return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
-}
-
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-void *
-sqlite3OsDlOpen(sqlite3_vfs * pVfs, const char *zPath)
-{
- return pVfs->xDlOpen(pVfs, zPath);
-}
-
-void
-sqlite3OsDlError(sqlite3_vfs * pVfs, int nByte, char *zBufOut)
-{
- pVfs->xDlError(pVfs, nByte, zBufOut);
-}
-
-void (*sqlite3OsDlSym(sqlite3_vfs * pVfs, void *pHdle, const char *zSym)) (void) {
- return pVfs->xDlSym(pVfs, pHdle, zSym);
-}
-
-void
-sqlite3OsDlClose(sqlite3_vfs * pVfs, void *pHandle)
-{
- pVfs->xDlClose(pVfs, pHandle);
-}
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-int
sqlite3OsRandomness(sqlite3_vfs * pVfs, int nByte, char *zBufOut)
{
return pVfs->xRandomness(pVfs, nByte, zBufOut);
@@ -503,13 +345,3 @@ sqlite3_vfs_register(sqlite3_vfs * pVfs, int makeDflt)
assert(vfsList);
return SQLITE_OK;
}
-
-/*
- * Unregister a VFS so that it is no longer accessible.
- */
-int
-sqlite3_vfs_unregister(sqlite3_vfs * pVfs)
-{
- vfsUnlink(pVfs);
- return SQLITE_OK;
-}
diff --git a/src/box/sql/os_unix.c b/src/box/sql/os_unix.c
index 9cb8a54..fb990f6 100644
--- a/src/box/sql/os_unix.c
+++ b/src/box/sql/os_unix.c
@@ -29,80 +29,7 @@
* SUCH DAMAGE.
*/
-/*
- *
- * This file contains the VFS implementation for unix-like operating systems.
- *
- * There are actually several different VFS implementations in this file.
- * The differences are in the way that file locking is done. The default
- * implementation uses Posix Advisory Locks. Alternative implementations
- * use flock(), dot-files, various proprietary locking schemas, or simply
- * skip locking all together.
- *
- * This source file is organized into divisions where the logic for various
- * subfunctions is contained within the appropriate division. PLEASE
- * KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
- * in the correct division and should be clearly labeled.
- *
- * The layout of divisions is as follows:
- *
- * * General-purpose declarations and utility functions.
- * * Various locking primitive implementations (all except proxy locking):
- * + for Posix Advisory Locks
- * + for no-op locks
- * + for dot-file locks
- * + for flock() locking
- * + for AFP filesystem locks (MacOSX only)
- * * sqlite3_file methods not associated with locking.
- * * Definitions of sqlite3_io_methods objects for all locking
- * methods plus "finder" functions for each locking method.
- * * sqlite3_vfs method implementations.
- * * Locking primitives for the proxy uber-locking-method. (MacOSX only)
- * * Definitions of sqlite3_vfs objects for all locking methods
- * plus implementations of sqlite3_os_init() and sqlite3_os_end().
- */
#include "sqliteInt.h"
-
-/*
- * There are various methods for file locking used for concurrency
- * control:
- *
- * 1. POSIX locking (the default),
- * 2. No locking,
- * 3. Dot-file locking,
- * 4. flock() locking,
- * 5. AFP locking (OSX only),
- * 6. proxy locking. (OSX only)
- *
- * Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE
- * is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic
- * selection of the appropriate locking style based on the filesystem
- * where the database is located.
- */
-#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
-#if defined(__APPLE__)
-#define SQLITE_ENABLE_LOCKING_STYLE 1
-#else
-#define SQLITE_ENABLE_LOCKING_STYLE 0
-#endif
-#endif
-
-/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
-#define HAVE_PREAD 1
-#define HAVE_PWRITE 1
-#endif
-#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
-#undef USE_PREAD
-#define USE_PREAD64 1
-#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
-#undef USE_PREAD64
-#define USE_PREAD 1
-#endif
-
-/*
- * standard include files.
- */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -110,28 +37,8 @@
#include <time.h>
#include <sys/time.h>
#include <errno.h>
-#if SQLITE_MAX_MMAP_SIZE>0
#include <sys/mman.h>
-#endif
-
-#if SQLITE_ENABLE_LOCKING_STYLE
-#include <sys/ioctl.h>
-#include <sys/file.h>
-#include <sys/param.h>
-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
-#include <sys/mount.h>
-#endif
-
-#ifdef HAVE_UTIME
-#include <utime.h>
-#endif
-/*
- * Allowed values of unixFile.fsFlags
- */
-#define SQLITE_FSFLAGS_IS_MSDOS 0x1
/*
* Default permissions when creating a new file
@@ -152,16 +59,6 @@
*/
#define MAX_PATHNAME 512
-/*
- * Maximum supported symbolic links
- */
-#define SQLITE_MAX_SYMLINKS 100
-
-/*
- * Only set the lastErrno if the error code is a real error and not
- * a normal expected return code of SQLITE_BUSY or SQLITE_OK
- */
-#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
/* Forward references */
typedef struct unixShm unixShm; /* Connection shared memory */
@@ -194,44 +91,14 @@ struct unixFile {
unsigned char eFileLock; /* The type of lock held on this fd */
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
- void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
- unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
-#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch refs */
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
- int openFlags; /* The flags specified at open() */
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
- unsigned fsFlags; /* cached details from statfs() */
-#endif
-#ifdef SQLITE_DEBUG
- /* The next group of variables are used to track whether or not the
- * transaction counter in bytes 24-27 of database files are updated
- * whenever any part of the database changes. An assertion fault will
- * occur if a file is updated without also updating the transaction
- * counter. This test is made to avoid new problems similar to the
- * one described by ticket #3584.
- */
- unsigned char transCntrChng; /* True if the transaction counter changed */
- unsigned char dbUpdate; /* True if any part of database file changed */
- unsigned char inNormalWrite; /* True if in a normal write operation */
-
-#endif
-
-#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
};
/* This variable holds the process id (pid) from when the xRandomness()
@@ -245,11 +112,7 @@ static pid_t randomnessPid = 0;
*/
#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
-#ifndef SQLITE_DISABLE_DIRSYNC
#define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
-#else
-#define UNIXFILE_DIRSYNC 0x00
-#endif
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
@@ -262,305 +125,11 @@ static pid_t randomnessPid = 0;
/*
* Define various macros that are missing from some systems.
*/
-#ifndef O_LARGEFILE
-#define O_LARGEFILE 0
-#endif
-#ifdef SQLITE_DISABLE_LFS
-#undef O_LARGEFILE
-#define O_LARGEFILE 0
-#endif
-#ifndef O_NOFOLLOW
-#define O_NOFOLLOW 0
-#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
/*
- * HAVE_MREMAP defaults to true on Linux and false everywhere else.
- */
-#if !defined(HAVE_MREMAP)
-#if defined(__linux__) && defined(_GNU_SOURCE)
-#define HAVE_MREMAP 1
-#else
-#define HAVE_MREMAP 0
-#endif
-#endif
-
-
-
-/*
- * Different Unix systems declare open() in different ways. Same use
- * open(const char*,int,mode_t). Others use open(const char*,int,...).
- * The difference is important when using a pointer to the function.
- *
- * The safest way to deal with the problem is to always use this wrapper
- * which always has the same well-defined interface.
- */
-static int
-posixOpen(const char *zFile, int flags, int mode)
-{
- return open(zFile, flags, mode);
-}
-
-/* Forward reference */
-static int openDirectory(const char *, int *);
-#if SQLITE_MAX_MMAP_SIZE > 0
-static int unixGetpagesize(void);
-#endif
-
-/*
- * Many system calls are accessed through pointer-to-functions so that
- * they may be overridden at runtime to facilitate fault injection during
- * testing and sandboxing. The following array holds the names and pointers
- * to all overrideable system calls.
- */
-static struct unix_syscall {
- const char *zName; /* Name of the system call */
- sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
- sqlite3_syscall_ptr pDefault; /* Default value */
-} aSyscall[] = {
- {
- "open", (sqlite3_syscall_ptr) posixOpen, 0},
-#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
- {
- "close", (sqlite3_syscall_ptr) close, 0},
-#define osClose ((int(*)(int))aSyscall[1].pCurrent)
- {
- "access", (sqlite3_syscall_ptr) access, 0},
-#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent)
- {
- "getcwd", (sqlite3_syscall_ptr) getcwd, 0},
-#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
- {
- "stat", (sqlite3_syscall_ptr) stat, 0},
-#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
- {
- "fstat", (sqlite3_syscall_ptr) fstat, 0},
-#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
- {
- "ftruncate", (sqlite3_syscall_ptr) ftruncate, 0},
-#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent)
- {
- "fcntl", (sqlite3_syscall_ptr) fcntl, 0},
-#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
- {
- "read", (sqlite3_syscall_ptr) read, 0},
-#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
-#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
- {
- "pread", (sqlite3_syscall_ptr) pread, 0},
-#else
- {
- "pread", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
-#if defined(USE_PREAD64)
- {
- "pread64", (sqlite3_syscall_ptr) pread64, 0},
-#else
- {
- "pread64", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
- {
- "write", (sqlite3_syscall_ptr) write, 0},
-#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
-#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
- {
- "pwrite", (sqlite3_syscall_ptr) pwrite, 0},
-#else
- {
- "pwrite", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
- aSyscall[12].pCurrent)
-#if defined(USE_PREAD64)
- {
- "pwrite64", (sqlite3_syscall_ptr) pwrite64, 0},
-#else
- {
- "pwrite64", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
- aSyscall[13].pCurrent)
- {
- "fchmod", (sqlite3_syscall_ptr) fchmod, 0},
-#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
- {
- "fallocate", (sqlite3_syscall_ptr) posix_fallocate, 0},
-#else
- {
- "fallocate", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent)
- {
- "unlink", (sqlite3_syscall_ptr) unlink, 0},
-#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent)
- {
- "openDirectory", (sqlite3_syscall_ptr) openDirectory, 0},
-#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent)
- {
- "mkdir", (sqlite3_syscall_ptr) mkdir, 0},
-#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
- {
- "rmdir", (sqlite3_syscall_ptr) rmdir, 0},
-#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
-#if defined(HAVE_FCHOWN)
- {
- "fchown", (sqlite3_syscall_ptr) fchown, 0},
-#else
- {
- "fchown", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
- {
- "geteuid", (sqlite3_syscall_ptr) geteuid, 0},
-#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
-
-#if SQLITE_MAX_MMAP_SIZE>0
- {
- "mmap", (sqlite3_syscall_ptr) mmap, 0},
-#else
- {
- "mmap", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
-#if SQLITE_MAX_MMAP_SIZE>0
- {
- "munmap", (sqlite3_syscall_ptr) munmap, 0},
-#else
- {
- "munmap", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
-#if HAVE_MREMAP && (SQLITE_MAX_MMAP_SIZE>0)
- {
- "mremap", (sqlite3_syscall_ptr) mremap, 0},
-#else
- {
- "mremap", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
-#if SQLITE_MAX_MMAP_SIZE>0
- {
- "getpagesize", (sqlite3_syscall_ptr) unixGetpagesize, 0},
-#else
- {
- "getpagesize", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
-#if defined(HAVE_READLINK)
- {
- "readlink", (sqlite3_syscall_ptr) readlink, 0},
-#else
- {
- "readlink", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
-#if defined(HAVE_LSTAT)
- {
- "lstat", (sqlite3_syscall_ptr) lstat, 0},
-#else
- {
- "lstat", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
-}; /* End of the overrideable system calls */
-
-
-/*
- * This is the xSetSystemCall() method of sqlite3_vfs for all of the
- * "unix" VFSes. Return SQLITE_OK opon successfully updating the
- * system call pointer, or SQLITE_NOTFOUND if there is no configurable
- * system call named zName.
- */
-static int
-unixSetSystemCall(sqlite3_vfs * pNotUsed, /* The VFS pointer. Not used */
- const char *zName, /* Name of system call to override */
- sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
- )
-{
- unsigned int i;
- int rc = SQLITE_NOTFOUND;
-
- UNUSED_PARAMETER(pNotUsed);
- if (zName == 0) {
- /* If no zName is given, restore all system calls to their default
- * settings and return NULL
- */
- rc = SQLITE_OK;
- for (i = 0; i < sizeof(aSyscall) / sizeof(aSyscall[0]); i++) {
- if (aSyscall[i].pDefault) {
- aSyscall[i].pCurrent = aSyscall[i].pDefault;
- }
- }
- } else {
- /* If zName is specified, operate on only the one system call
- * specified.
- */
- for (i = 0; i < sizeof(aSyscall) / sizeof(aSyscall[0]); i++) {
- if (strcmp(zName, aSyscall[i].zName) == 0) {
- if (aSyscall[i].pDefault == 0) {
- aSyscall[i].pDefault =
- aSyscall[i].pCurrent;
- }
- rc = SQLITE_OK;
- if (pNewFunc == 0)
- pNewFunc = aSyscall[i].pDefault;
- aSyscall[i].pCurrent = pNewFunc;
- break;
- }
- }
- }
- return rc;
-}
-
-/*
- * Return the value of a system call. Return NULL if zName is not a
- * recognized system call name. NULL is also returned if the system call
- * is currently undefined.
- */
-static sqlite3_syscall_ptr
-unixGetSystemCall(sqlite3_vfs * pNotUsed, const char *zName)
-{
- unsigned int i;
-
- UNUSED_PARAMETER(pNotUsed);
- for (i = 0; i < sizeof(aSyscall) / sizeof(aSyscall[0]); i++) {
- if (strcmp(zName, aSyscall[i].zName) == 0)
- return aSyscall[i].pCurrent;
- }
- return 0;
-}
-
-/*
- * Return the name of the first system call after zName. If zName==NULL
- * then return the name of the first system call. Return NULL if zName
- * is the last system call or if zName is not the name of a valid
- * system call.
- */
-static const char *
-unixNextSystemCall(sqlite3_vfs * p, const char *zName)
-{
- int i = -1;
-
- UNUSED_PARAMETER(p);
- if (zName) {
- for (i = 0; i < ArraySize(aSyscall) - 1; i++) {
- if (strcmp(zName, aSyscall[i].zName) == 0)
- break;
- }
- }
- for (i++; i < ArraySize(aSyscall); i++) {
- if (aSyscall[i].pCurrent != 0)
- return aSyscall[i].zName;
- }
- return 0;
-}
-
-/*
* Do not accept any file descriptor less than this value, in order to avoid
* opening database file using file descriptors that are commonly used for
* standard input, output, and error.
@@ -592,11 +161,7 @@ robust_open(const char *z, int f, mode_t m)
int fd;
mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
while (1) {
-#if defined(O_CLOEXEC)
- fd = osOpen(z, f | O_CLOEXEC, m2);
-#else
- fd = osOpen(z, f, m2);
-#endif
+ fd = open(z, f | O_CLOEXEC, m2);
if (fd < 0) {
if (errno == EINTR)
continue;
@@ -604,95 +169,26 @@ robust_open(const char *z, int f, mode_t m)
}
if (fd >= SQLITE_MINIMUM_FILE_DESCRIPTOR)
break;
- osClose(fd);
+ close(fd);
sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z,
fd);
fd = -1;
- if (osOpen("/dev/null", f, m) < 0)
+ if (open("/dev/null", f, m) < 0)
break;
}
if (fd >= 0) {
if (m != 0) {
struct stat statbuf;
- if (osFstat(fd, &statbuf) == 0
- && statbuf.st_size == 0
- && (statbuf.st_mode & 0777) != m) {
- osFchmod(fd, m);
- }
+ if (fstat(fd, &statbuf) == 0 &&
+ statbuf.st_size == 0 &&
+ (statbuf.st_mode & 0777) != m)
+ fchmod(fd, m);
}
-#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
}
return fd;
}
-#ifdef SQLITE_LOCK_TRACE
-/*
- * Print out information about all locking operations.
- *
- * This routine is used for troubleshooting locks on multithreaded
- * platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE
- * command-line option on the compiler. This code is normally
- * turned off.
- */
-static int
-lockTrace(int fd, int op, struct flock *p)
-{
- char *zOpName, *zType;
- int s;
- int savedErrno;
- if (op == F_GETLK) {
- zOpName = "GETLK";
- } else if (op == F_SETLK) {
- zOpName = "SETLK";
- } else {
- s = osFcntl(fd, op, p);
- sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
- return s;
- }
- if (p->l_type == F_RDLCK) {
- zType = "RDLCK";
- } else if (p->l_type == F_WRLCK) {
- zType = "WRLCK";
- } else if (p->l_type == F_UNLCK) {
- zType = "UNLCK";
- } else {
- assert(0);
- }
- assert(p->l_whence == SEEK_SET);
- s = osFcntl(fd, op, p);
- savedErrno = errno;
- sqlite3DebugPrintf("fcntl %d %s %s %d %d %d %d\n",
- fd, zOpName, zType, (int)p->l_start,
- (int)p->l_len, (int)p->l_pid, s);
- if (s == (-1) && op == F_SETLK
- && (p->l_type == F_RDLCK || p->l_type == F_WRLCK)) {
- struct flock l2;
- l2 = *p;
- osFcntl(fd, F_GETLK, &l2);
- if (l2.l_type == F_RDLCK) {
- zType = "RDLCK";
- } else if (l2.l_type == F_WRLCK) {
- zType = "WRLCK";
- } else if (l2.l_type == F_UNLCK) {
- zType = "UNLCK";
- } else {
- assert(0);
- }
- sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n",
- zType, (int)l2.l_start, (int)l2.l_len,
- (int)l2.l_pid);
- }
- errno = savedErrno;
- return s;
-}
-
-#undef osFcntl
-#define osFcntl lockTrace
-#endif /* SQLITE_LOCK_TRACE */
-
/*
* Retry ftruncate() calls that fail due to EINTR
*
@@ -704,7 +200,7 @@ robust_ftruncate(int h, sqlite3_int64 sz)
{
int rc;
do {
- rc = osFtruncate(h, sz);
+ rc = ftruncate(h, sz);
} while (rc < 0 && errno == EINTR);
return rc;
}
@@ -861,9 +357,6 @@ struct unixInodeInfo {
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
unixInodeInfo *pPrev; /* .... doubly linked */
-#if SQLITE_ENABLE_LOCKING_STYLE
- unsigned long long sharedByte; /* for AFP simulated shared lock */
-#endif
};
/*
@@ -925,7 +418,7 @@ unixLogErrorAtLine(int errcode, /* SQLite error code */
static void
robust_close(unixFile * pFile, int h, int lineno)
{
- if (osClose(h)) {
+ if (close(h) != 0) {
unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
pFile ? pFile->zPath : 0, lineno);
}
@@ -1008,38 +501,11 @@ findInodeInfo(unixFile * pFile, /* Unix file with file desc used in the key */
* create a unique name for the file.
*/
fd = pFile->h;
- rc = osFstat(fd, &statbuf);
+ rc = fstat(fd, &statbuf);
if (rc != 0) {
storeLastErrno(pFile, errno);
return SQLITE_IOERR;
}
-#ifdef __APPLE__
- /* On OS X on an msdos filesystem, the inode number is reported
- * incorrectly for zero-size files. See ticket #3260. To work
- * around this problem (we consider it a bug in OS X, not SQLite)
- * we always increase the file size to 1 by writing a single byte
- * prior to accessing the inode number. The one byte written is
- * an ASCII 'S' character which also happens to be the first byte
- * in the header of every SQLite database. In this way, if there
- * is a race condition such that another thread has already populated
- * the first page of the database, no damage is done.
- */
- if (statbuf.st_size == 0
- && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) {
- do {
- rc = osWrite(fd, "S", 1);
- } while (rc < 0 && errno == EINTR);
- if (rc != 1) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR;
- }
- rc = osFstat(fd, &statbuf);
- if (rc != 0) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR;
- }
- }
-#endif
memset(&fileId, 0, sizeof(fileId));
fileId.dev = statbuf.st_dev;
@@ -1075,9 +541,9 @@ static int
fileHasMoved(unixFile * pFile)
{
struct stat buf;
- return pFile->pInode != 0 &&
- (osStat(pFile->zPath, &buf) != 0
- || (u64) buf.st_ino != pFile->pInode->fileId.ino);
+ return pFile->pInode != NULL && (stat(pFile->zPath, &buf) != 0 ||
+ (u64) buf.st_ino !=
+ pFile->pInode->fileId.ino);
}
/*
@@ -1099,7 +565,7 @@ verifyDbFile(unixFile * pFile)
if (pFile->ctrlFlags & UNIXFILE_NOLOCK)
return;
- rc = osFstat(pFile->h, &buf);
+ rc = fstat(pFile->h, &buf);
if (rc != 0) {
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s",
pFile->zPath);
@@ -1123,34 +589,6 @@ verifyDbFile(unixFile * pFile)
}
/*
- * 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
-unixCheckReservedLock(sqlite3_file * id, int *pResOut)
-{
- int rc = SQLITE_OK;
- int reserved = 0;
- unixFile *pFile = (unixFile *) id;
-
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
-
- assert(pFile);
- assert(pFile->eFileLock <= SHARED_LOCK);
-
- /* Check if a thread in this process holds such a lock */
- if (pFile->pInode->eFileLock > SHARED_LOCK) {
- reserved = 1;
- }
-
- *pResOut = reserved;
- return rc;
-}
-
-/*
* Attempt to set a system-lock on the file pFile. The lock is
* described by pLock.
*
@@ -1184,7 +622,7 @@ unixFileLock(unixFile * pFile, struct flock *pLock)
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
lock.l_type = F_WRLCK;
- rc = osFcntl(pFile->h, F_SETLK, &lock);
+ rc = fcntl(pFile->h, F_SETLK, &lock);
if (rc < 0)
return rc;
pInode->bProcessLock = 1;
@@ -1193,7 +631,7 @@ unixFileLock(unixFile * pFile, struct flock *pLock)
rc = 0;
}
} else {
- rc = osFcntl(pFile->h, F_SETLK, pLock);
+ rc = fcntl(pFile->h, F_SETLK, pLock);
}
return rc;
}
@@ -1295,9 +733,8 @@ unixLock(sqlite3_file * id, int eFileLock)
* has a SHARED or RESERVED lock, then increment reference counts and
* return SQLITE_OK.
*/
- if (eFileLock == SHARED_LOCK &&
- (pInode->eFileLock == SHARED_LOCK
- || pInode->eFileLock == RESERVED_LOCK)) {
+ if (eFileLock == SHARED_LOCK && (pInode->eFileLock == SHARED_LOCK ||
+ pInode->eFileLock == RESERVED_LOCK)) {
assert(eFileLock == SHARED_LOCK);
assert(pFile->eFileLock == 0);
assert(pInode->nShared > 0);
@@ -1399,20 +836,6 @@ unixLock(sqlite3_file * id, int eFileLock)
}
}
-#ifdef SQLITE_DEBUG
- /* Set up the transaction-counter change checking flags when
- * transitioning from a SHARED to a RESERVED lock. The change
- * from SHARED to RESERVED marks the beginning of a normal
- * write operation.
- */
- if (rc == SQLITE_OK
- && pFile->eFileLock <= SHARED_LOCK && eFileLock == RESERVED_LOCK) {
- pFile->transCntrChng = 0;
- pFile->dbUpdate = 0;
- pFile->inNormalWrite = 1;
- }
-#endif
-
if (rc == SQLITE_OK) {
pFile->eFileLock = eFileLock;
pInode->eFileLock = eFileLock;
@@ -1472,18 +895,6 @@ posixUnlock(sqlite3_file * id, int eFileLock, int handleNFSUnlock)
if (pFile->eFileLock > SHARED_LOCK) {
assert(pInode->eFileLock == pFile->eFileLock);
-#ifdef SQLITE_DEBUG
- /* When reducing a lock such that other processes can start
- * reading the database file again, make sure that the
- * transaction counter was updated if any part of the database
- * file changed. If the transaction counter is not updated,
- * other connections to the same file might not realize that
- * the file has changed and hence might not know to flush their
- * cache. The use of a stale cache can lead to database corruption.
- */
- pFile->inNormalWrite = 0;
-#endif
-
/* downgrading to a shared lock on NFS involves clearing the write lock
* before establishing the readlock - to avoid a race condition we downgrade
* the lock in 2 blocks, so that part of the range will be covered by a
@@ -1494,50 +905,8 @@ posixUnlock(sqlite3_file * id, int eFileLock, int handleNFSUnlock)
* 4: [RRRR.]
*/
if (eFileLock == SHARED_LOCK) {
-#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
(void)handleNFSUnlock;
assert(handleNFSUnlock == 0);
-#endif
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- if (handleNFSUnlock) {
- int tErrno; /* Error code from system call errors */
- off_t divSize = SHARED_SIZE - 1;
-
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST;
- lock.l_len = divSize;
- if (unixFileLock(pFile, &lock) == (-1)) {
- tErrno = errno;
- rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- goto end_unlock;
- }
- lock.l_type = F_RDLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST;
- lock.l_len = divSize;
- if (unixFileLock(pFile, &lock) == (-1)) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_RDLOCK);
- if (IS_LOCK_ERROR(rc)) {
- storeLastErrno(pFile, tErrno);
- }
- goto end_unlock;
- }
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST + divSize;
- lock.l_len = SHARED_SIZE - divSize;
- if (unixFileLock(pFile, &lock) == (-1)) {
- tErrno = errno;
- rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- goto end_unlock;
- }
- } else
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
{
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
@@ -1617,16 +986,12 @@ posixUnlock(sqlite3_file * id, int eFileLock, int handleNFSUnlock)
static int
unixUnlock(sqlite3_file * id, int eFileLock)
{
-#if SQLITE_MAX_MMAP_SIZE>0
assert(eFileLock == SHARED_LOCK || ((unixFile *) id)->nFetchOut == 0);
-#endif
return posixUnlock(id, eFileLock, 0);
}
-#if SQLITE_MAX_MMAP_SIZE>0
static int unixMapfile(unixFile * pFd, i64 nByte);
static void unixUnmapfile(unixFile * pFd);
-#endif
/*
* This function performs the parts of the "close file" operation
@@ -1645,13 +1010,6 @@ closeUnixFile(sqlite3_file * id)
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
}
-#ifdef SQLITE_UNLINK_AFTER_CLOSE
- if (pFile->ctrlFlags & UNIXFILE_DELETE) {
- osUnlink(pFile->zPath);
- sqlite3_free(*(char **)&pFile->zPath);
- pFile->zPath = 0;
- }
-#endif
OpenCounter(-1);
sqlite3_free(pFile->pUnused);
memset(pFile, 0, sizeof(unixFile));
@@ -1707,14 +1065,6 @@ unixClose(sqlite3_file * id)
*/
static int
-nolockCheckReservedLock(sqlite3_file * NotUsed, int *pResOut)
-{
- UNUSED_PARAMETER(NotUsed);
- *pResOut = 0;
- return SQLITE_OK;
-}
-
-static int
nolockLock(sqlite3_file * NotUsed, int NotUsed2)
{
UNUSED_PARAMETER2(NotUsed, NotUsed2);
@@ -1737,4465 +1087,1647 @@ nolockClose(sqlite3_file * id)
return closeUnixFile(id);
}
-/******************* End of the no-op lock implementation *********************
+
+/******************* End of the non-op lock implementation *******************
*****************************************************************************/
/******************************************************************************
- ************************ Begin dot-file Locking ******************************
- *
- * The dotfile locking implementation uses the existence of separate lock
- * files (really a directory) to control access to the database. This works
- * on just about every filesystem imaginable. But there are serious downsides:
- *
- * (1) There is zero concurrency. A single reader blocks all other
- * connections from reading or writing the database.
- *
- * (2) An application crash or power loss can leave stale lock files
- * sitting around that need to be cleared manually.
- *
- * Nevertheless, a dotlock is an appropriate locking mode for use if no
- * other locking strategy is available.
+ *************** Non-locking sqlite3_file methods *****************************
*
- * Dotfile locking works by creating a subdirectory in the same directory as
- * the database and with the same name but with a ".lock" extension added.
- * The existence of a lock directory implies an EXCLUSIVE lock. All other
- * lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
- */
-
-/*
- * The file suffix added to the data base filename in order to create the
- * lock directory.
+ * The next division contains implementations for all methods of the
+ * sqlite3_file object other than the locking methods. The locking
+ * methods were defined in divisions above (one locking method per
+ * division). Those methods that are common to all locking modes
+ * are gather together into this division.
*/
-#define DOTLOCK_SUFFIX ".lock"
/*
- * 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.
+ * Seek to the offset passed as the second argument, then read cnt
+ * bytes into pBuf. Return the number of bytes actually read.
*
- * In dotfile locking, either a lock exists or it does not. So in this
- * variation of CheckReservedLock(), *pResOut is set to true if any lock
- * is held on the file and false if the file is unlocked.
+ * 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
+ * in any form by default, we will not attempt to define _XOPEN_SOURCE.
+ * See tickets #2741 and #2681.
+ *
+ * To avoid stomping the errno value on a failed read the lastErrno value
+ * is set before returning.
*/
static int
-dotlockCheckReservedLock(sqlite3_file * id, int *pResOut)
+seekAndRead(unixFile * id, sqlite3_int64 offset, void *pBuf, int cnt)
{
- int rc = SQLITE_OK;
- int reserved = 0;
- unixFile *pFile = (unixFile *) id;
-
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
-
- assert(pFile);
- reserved = osAccess((const char *)pFile->lockingContext, 0) == 0;
- *pResOut = reserved;
- return rc;
-}
+ int got;
+ int prior = 0;
+ i64 newOffset;
-/*
- * Lock the file with the lock specified by parameter eFileLock - 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.
- *
- * With dotfile locking, we really only support state (4): EXCLUSIVE.
- * But we track the other locking levels internally.
- */
-static int
-dotlockLock(sqlite3_file * id, int eFileLock)
-{
- unixFile *pFile = (unixFile *) id;
- char *zLockFile = (char *)pFile->lockingContext;
- int rc;
-
- /* If we have any lock, then the lock file already exists. All we have
- * to do is adjust our internal record of the lock level.
- */
- if (pFile->eFileLock > NO_LOCK) {
- pFile->eFileLock = eFileLock;
- /* Always update the timestamp on the old file */
-#ifdef HAVE_UTIME
- utime(zLockFile, NULL);
-#else
- utimes(zLockFile, NULL);
-#endif
- return SQLITE_OK;
- }
-
- /* grab an exclusive lock */
- rc = osMkdir(zLockFile, 0777);
- if (rc < 0) {
- /* failed to open/create the lock directory */
- int tErrno = errno;
- if (EEXIST == tErrno) {
- rc = SQLITE_BUSY;
- } else {
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- if (rc != SQLITE_BUSY) {
- storeLastErrno(pFile, tErrno);
+ assert(cnt == (cnt & 0x1ffff));
+ assert(id->h > 2);
+ do {
+ newOffset = lseek(id->h, offset, SEEK_SET);
+ SimulateIOError(newOffset = -1);
+ if (newOffset < 0) {
+ storeLastErrno((unixFile *) id, errno);
+ return -1;
+ }
+ got = read(id->h, pBuf, cnt);
+ if (got == cnt)
+ break;
+ if (got < 0) {
+ if (errno == EINTR) {
+ got = 1;
+ continue;
}
+ prior = 0;
+ storeLastErrno((unixFile *) id, errno);
+ break;
+ } else if (got > 0) {
+ cnt -= got;
+ offset += got;
+ prior += got;
+ pBuf = (void *)(got + (char *)pBuf);
}
- return rc;
- }
-
- /* got it, set the type and return ok */
- pFile->eFileLock = eFileLock;
- return rc;
+ } while (got > 0);
+ return got + prior;
}
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * 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.
- *
- * When the locking level reaches NO_LOCK, delete the lock file.
+ * Read data from a file into a buffer. Return SQLITE_OK if all
+ * bytes were read successfully and SQLITE_IOERR if anything goes
+ * wrong.
*/
static int
-dotlockUnlock(sqlite3_file * id, int eFileLock)
+unixRead(sqlite3_file * id, void *pBuf, int amt, sqlite3_int64 offset)
{
unixFile *pFile = (unixFile *) id;
- char *zLockFile = (char *)pFile->lockingContext;
- int rc;
-
- assert(pFile);
- assert(eFileLock <= SHARED_LOCK);
-
- /* no-op if possible */
- if (pFile->eFileLock == eFileLock) {
- return SQLITE_OK;
- }
+ int got;
+ assert(id);
+ assert(offset >= 0);
+ assert(amt > 0);
- /* To downgrade to shared, simply update our internal notion of the
- * lock state. No need to mess with the file on disk.
+#if SQLITE_MAX_MMAP_SIZE>0
+ /* Deal with as much of this read request as possible by transfering
+ * data from the memory mapping using memcpy().
*/
- if (eFileLock == SHARED_LOCK) {
- pFile->eFileLock = SHARED_LOCK;
- return SQLITE_OK;
- }
-
- /* To fully unlock the database, delete the lock file */
- assert(eFileLock == NO_LOCK);
- rc = osRmdir(zLockFile);
- if (rc < 0) {
- int tErrno = errno;
- if (tErrno == ENOENT) {
- rc = SQLITE_OK;
+ if (offset < pFile->mmapSize) {
+ if (offset + amt <= pFile->mmapSize) {
+ memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
+ amt);
+ return SQLITE_OK;
} else {
- rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
+ int nCopy = pFile->mmapSize - offset;
+ memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
+ nCopy);
+ pBuf = &((u8 *) pBuf)[nCopy];
+ amt -= nCopy;
+ offset += nCopy;
}
- return rc;
}
- pFile->eFileLock = NO_LOCK;
- return SQLITE_OK;
+#endif
+
+ got = seekAndRead(pFile, offset, pBuf, amt);
+ if (got == amt) {
+ return SQLITE_OK;
+ } else if (got < 0) {
+ /* lastErrno set by seekAndRead */
+ return SQLITE_IOERR_READ;
+ } else {
+ storeLastErrno(pFile, 0); /* not a system error */
+ /* Unread parts of the buffer must be zero-filled */
+ memset(&((char *)pBuf)[got], 0, amt - got);
+ return SQLITE_IOERR_SHORT_READ;
+ }
}
/*
- * Close a file. Make sure the lock has been released before closing.
+ * Attempt to seek the file-descriptor passed as the first argument to
+ * absolute offset iOff, then attempt to write nBuf bytes of data from
+ * pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
+ * return the actual number of bytes written (which may be less than
+ * nBuf).
*/
static int
-dotlockClose(sqlite3_file * id)
+seekAndWriteFd(int fd, /* File descriptor to write to */
+ i64 iOff, /* File offset to begin writing at */
+ const void *pBuf, /* Copy data from this buffer to the file */
+ int nBuf, /* Size of buffer pBuf in bytes */
+ int *piErrno /* OUT: Error number if error occurs */
+ )
{
- unixFile *pFile = (unixFile *) id;
- assert(id != 0);
- dotlockUnlock(id, NO_LOCK);
- sqlite3_free(pFile->lockingContext);
- return closeUnixFile(id);
-}
+ int rc = 0; /* Value returned by system call */
-/****************** End of the dot-file lock implementation *******************
- *****************************************************************************/
+ assert(nBuf == (nBuf & 0x1ffff));
+ assert(fd > 2);
+ assert(piErrno != 0);
+ nBuf &= 0x1ffff;
+ do {
+ i64 iSeek = lseek(fd, iOff, SEEK_SET);
+ SimulateIOError(iSeek = -1);
+ if (iSeek < 0) {
+ rc = -1;
+ break;
+ }
+ rc = write(fd, pBuf, nBuf);
+ } while (rc < 0 && errno == EINTR);
-/******************************************************************************
- ************************* Begin flock Locking ********************************
- *
- * 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
- */
-#if SQLITE_ENABLE_LOCKING_STYLE
+ if (rc < 0)
+ *piErrno = errno;
+ return rc;
+}
/*
- * Retry flock() calls that fail with EINTR
+ * Seek to the offset in id->offset then read cnt bytes into pBuf.
+ * Return the number of bytes actually read. Update the offset.
+ *
+ * To avoid stomping the errno value on a failed write the lastErrno value
+ * is set before returning.
*/
-#ifdef EINTR
static int
-robust_flock(int fd, int op)
+seekAndWrite(unixFile * id, i64 offset, const void *pBuf, int cnt)
{
- int rc;
- do {
- rc = flock(fd, op);
- } while (rc < 0 && errno == EINTR);
- return rc;
+ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
}
-#else
-#define robust_flock(a,b) flock(a,b)
-#endif
/*
- * 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.
+ * Write data from a buffer into a file. Return SQLITE_OK on success
+ * or some other error code on failure.
*/
static int
-flockCheckReservedLock(sqlite3_file * id, int *pResOut)
+unixWrite(sqlite3_file * id, const void *pBuf, int amt, sqlite3_int64 offset)
{
- int rc = SQLITE_OK;
- int reserved = 0;
unixFile *pFile = (unixFile *) id;
+ int wrote = 0;
+ assert(id);
+ assert(amt > 0);
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
-
- assert(pFile);
-
- /* Check if a thread in this process holds such a lock */
- if (pFile->eFileLock > SHARED_LOCK) {
- reserved = 1;
+ while ((wrote = seekAndWrite(pFile, offset, pBuf, amt)) < amt
+ && wrote > 0) {
+ amt -= wrote;
+ offset += wrote;
+ pBuf = &((char *)pBuf)[wrote];
}
+ SimulateIOError((wrote = (-1), amt = 1));
+ SimulateDiskfullError((wrote = 0, amt = 1));
- /* Otherwise see if some other process holds it. */
- if (!reserved) {
- /* attempt to get the lock */
- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
- if (!lrc) {
- /* got the lock, unlock it */
- lrc = robust_flock(pFile->h, LOCK_UN);
- if (lrc) {
- int tErrno = errno;
- /* unlock failed with an error */
- lrc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
+ if (amt > wrote) {
+ if (wrote < 0 && pFile->lastErrno != ENOSPC) {
+ /* lastErrno set by seekAndWrite */
+ return SQLITE_IOERR_WRITE;
} else {
- int tErrno = errno;
- reserved = 1;
- /* someone else might have it reserved */
- lrc =
- sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- if (IS_LOCK_ERROR(lrc)) {
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
+ storeLastErrno(pFile, 0); /* not a system error */
+ return SQLITE_FULL;
}
}
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if ((rc & SQLITE_IOERR) == SQLITE_IOERR) {
- rc = SQLITE_OK;
- reserved = 1;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- *pResOut = reserved;
- return rc;
+ return SQLITE_OK;
}
+#ifdef SQLITE_TEST
/*
- * Lock the file with the lock specified by parameter eFileLock - 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
+ * Count the number of fullsyncs and normal syncs. This is used to test
+ * that syncs and fullsyncs are occurring at the right times.
+ */
+int sqlite3_sync_count = 0;
+int sqlite3_fullsync_count = 0;
+#endif
+
+
+/*
+ * The fsync() system call does not work as advertised on many
+ * unix systems. The following procedure is an attempt to make
+ * it work better.
*
- * 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.
+ * The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
+ * for testing when we want to run through the test suite quickly.
+ * You are strongly advised *not* to deploy with SQLITE_NO_SYNC
+ * enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
+ * or power failure will likely corrupt the database file.
*
- * This routine will only increase a lock. Use the sqlite3OsUnlock()
- * routine to lower a locking level.
+ * SQLite sets the dataOnly flag if the size of the file is unchanged.
+ * The idea behind dataOnly is that it should only write the file content
+ * to disk, not the inode. We only set dataOnly if the file size is
+ * unchanged since the file size is part of the inode. However,
+ * Ted Ts'o tells us that fdatasync() will also write the inode if the
+ * file size has changed. The only real difference between fdatasync()
+ * and fsync(), Ted tells us, is that fdatasync() will not flush the
+ * inode if the mtime or owner or other inode attributes have changed.
+ * We only care about the file size, not the other file attributes, so
+ * as far as SQLite is concerned, an fdatasync() is always adequate.
+ * So, we always use fdatasync() if it is available, regardless of
+ * the value of the dataOnly flag.
*/
static int
-flockLock(sqlite3_file * id, int eFileLock)
+full_fsync(int fd, int fullSync, int dataOnly)
{
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
-
- assert(pFile);
+ UNUSED_PARAMETER(fd);
+ UNUSED_PARAMETER(fullSync);
+ UNUSED_PARAMETER(dataOnly);
- /* if we already have a lock, it is exclusive.
- * Just adjust level and punt on outta here.
+ /* Record the number of times that we do a normal fsync() and
+ * FULLSYNC. This is used during testing to verify that this procedure
+ * gets called with the correct arguments.
*/
- if (pFile->eFileLock > NO_LOCK) {
- pFile->eFileLock = eFileLock;
- return SQLITE_OK;
- }
-
- /* grab an exclusive lock */
-
- if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
- int tErrno = errno;
- /* didn't get, must be busy */
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if (IS_LOCK_ERROR(rc)) {
- storeLastErrno(pFile, tErrno);
- }
- } else {
- /* got it, set the type and return ok */
- pFile->eFileLock = eFileLock;
- }
+#ifdef SQLITE_TEST
+ if (fullSync)
+ sqlite3_fullsync_count++;
+ sqlite3_sync_count++;
+#endif
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if ((rc & SQLITE_IOERR) == SQLITE_IOERR) {
- rc = SQLITE_BUSY;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- return rc;
+ struct stat buf;
+ return fstat(fd, &buf);
}
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * must be either NO_LOCK or SHARED_LOCK.
+ * 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 the locking level of the file descriptor is already at or below
- * the requested locking level, this routine is a no-op.
+ * The directory file descriptor is used for only one thing - to
+ * fsync() a directory to make sure file creation and deletion events
+ * are flushed to disk. Such fsyncs are not needed on newer
+ * journaling filesystems, but are required on older filesystems.
+ *
+ * This routine can be overridden using the xSetSysCall interface.
+ * The ability to override this routine was added in support of the
+ * chromium sandbox. Opening a directory is a security risk (we are
+ * told) so making it overrideable allows the chromium sandbox to
+ * replace this routine with a harmless no-op. To make this routine
+ * a no-op, replace it with a stub that returns SQLITE_OK but leaves
+ * *pFd set to a negative number.
+ *
+ * If SQLITE_OK is returned, the caller is responsible for closing
+ * the file descriptor *pFd using close().
*/
static int
-flockUnlock(sqlite3_file * id, int eFileLock)
+openDirectory(const char *zFilename, int *pFd)
{
- unixFile *pFile = (unixFile *) id;
-
- assert(pFile);
- assert(eFileLock <= SHARED_LOCK);
-
- /* no-op if possible */
- if (pFile->eFileLock == eFileLock) {
- return SQLITE_OK;
- }
+ int ii;
+ int fd;
+ char zDirname[MAX_PATHNAME + 1];
- /* shared can just be set because we always have an exclusive */
- if (eFileLock == SHARED_LOCK) {
- pFile->eFileLock = eFileLock;
- return SQLITE_OK;
+ sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
+ for (ii = (int)strlen(zDirname); ii > 0 && zDirname[ii] != '/'; ii--) ;
+ if (ii > 0) {
+ zDirname[ii] = '\0';
+ } else {
+ if (zDirname[0] != '/')
+ zDirname[0] = '.';
+ zDirname[1] = 0;
}
+ fd = robust_open(zDirname, O_RDONLY | O_BINARY, 0);
- /* no, really, unlock. */
- if (robust_flock(pFile->h, LOCK_UN)) {
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- return SQLITE_OK;
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- return SQLITE_IOERR_UNLOCK;
- } else {
- pFile->eFileLock = NO_LOCK;
+ *pFd = fd;
+ if (fd >= 0)
return SQLITE_OK;
- }
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
}
/*
- * Close a file.
+ * Make sure all writes to a particular file are committed to disk.
+ *
+ * If dataOnly==0 then both the file itself and its metadata (file
+ * size, access time, etc) are synced. If dataOnly!=0 then only the
+ * file data is synced.
+ *
+ * Under Unix, also make sure that the directory entry for the file
+ * has been created by fsync-ing the directory that contains the file.
+ * If we do not do this and we encounter a power failure, the directory
+ * entry for the journal might not exist after we reboot. The next
+ * SQLite to access the file will not know that the journal exists (because
+ * the directory entry for the journal was never created) and the transaction
+ * will not roll back - possibly leading to database corruption.
*/
static int
-flockClose(sqlite3_file * id)
+unixSync(sqlite3_file * id, int flags)
{
- assert(id != 0);
- flockUnlock(id, NO_LOCK);
- return closeUnixFile(id);
-}
-
-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-
-/******************* End of the flock lock implementation *********************
- *****************************************************************************/
+ int rc;
+ unixFile *pFile = (unixFile *) id;
+ int isDataOnly = (flags & SQLITE_SYNC_DATAONLY);
+ int isFullsync = (flags & 0x0F) == SQLITE_SYNC_FULL;
-/******************************************************************************
- ************************** Begin AFP Locking *********************************
- *
- * AFP is the Apple Filing Protocol. AFP is a network filesystem found
- * on Apple Macintosh computers - both OS9 and OSX.
- *
- * Third-party implementations of AFP are available. But this code here
- * only works on OSX.
- */
+ /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
+ assert((flags & 0x0F) == SQLITE_SYNC_NORMAL
+ || (flags & 0x0F) == SQLITE_SYNC_FULL);
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
- * The afpLockingContext structure contains all afp lock specific state
- */
-typedef struct afpLockingContext afpLockingContext;
-struct afpLockingContext {
- int reserved;
- const char *dbPath; /* Name of the open file */
-};
+ /* Unix cannot, but some systems may return SQLITE_FULL from here. This
+ * line is to test that doing so does not cause any problems.
+ */
+ SimulateDiskfullError(return SQLITE_FULL);
-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 */
-};
+ assert(pFile);
+ rc = full_fsync(pFile->h, isFullsync, isDataOnly);
+ SimulateIOError(rc = 1);
+ if (rc) {
+ storeLastErrno(pFile, errno);
+ return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync",
+ pFile->zPath);
+ }
-#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+ return rc;
+}
/*
- * 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.
+ * Truncate an open file to a specified size
*/
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 */
- )
+unixTruncate(sqlite3_file * id, i64 nByte)
{
- struct ByteRangeLockPB2 pb;
- int err;
-
- pb.unLockFlag = setLockFlag ? 0 : 1;
- pb.startEndFlag = 0;
- pb.offset = offset;
- pb.length = length;
- pb.fd = pFile->h;
+ unixFile *pFile = (unixFile *) id;
+ int rc;
+ assert(pFile);
+ SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
- if (err == -1) {
- int rc;
- int tErrno = errno;
+ /* If the user has configured a chunk-size for this file, truncate the
+ * file so that it consists of an integer number of chunks (i.e. the
+ * actual file size after the operation may be larger than the requested
+ * size).
+ */
+ if (pFile->szChunk > 0) {
+ nByte =
+ ((nByte + pFile->szChunk -
+ 1) / pFile->szChunk) * pFile->szChunk;
+ }
-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
- rc = SQLITE_BUSY;
-#else
- rc = sqliteErrorFromPosixError(tErrno,
- setLockFlag ? SQLITE_IOERR_LOCK :
- SQLITE_IOERR_UNLOCK);
-#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
- if (IS_LOCK_ERROR(rc)) {
- storeLastErrno(pFile, tErrno);
- }
- return rc;
+ rc = robust_ftruncate(pFile->h, nByte);
+ if (rc) {
+ storeLastErrno(pFile, errno);
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate",
+ pFile->zPath);
} else {
+ /* If the file was just truncated to a size smaller than the currently
+ * mapped region, reduce the effective mapping size as well. SQLite will
+ * use read() and write() to access data beyond this point from now on.
+ */
+ if (nByte < pFile->mmapSize)
+ pFile->mmapSize = nByte;
+
return SQLITE_OK;
}
}
/*
- * 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.
+ * Determine the current size of a file in bytes
*/
static int
-afpCheckReservedLock(sqlite3_file * id, int *pResOut)
-{
- int rc = SQLITE_OK;
- int reserved = 0;
- unixFile *pFile = (unixFile *) id;
- afpLockingContext *context;
+unixFileSize(sqlite3_file * id, i64 * pSize) {
+ int rc;
+ struct stat buf;
+ assert(id);
+ rc = fstat(((unixFile *) id)->h, &buf);
+ SimulateIOError(rc = 1);
+ if (rc != 0) {
+ storeLastErrno((unixFile *) id, errno);
+ return SQLITE_IOERR_FSTAT;
+ }
+ *pSize = buf.st_size;
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
+ /* When opening a zero-size database, the findInodeInfo() procedure
+ * writes a single byte into that file in order to work around a bug
+ * in the OS-X msdos filesystem. In order to avoid problems with upper
+ * layers, we need to report this file size as zero even though it is
+ * really 1. Ticket #3260.
+ */
+ if (*pSize == 1)
+ *pSize = 0;
- assert(pFile);
- context = (afpLockingContext *) pFile->lockingContext;
- if (context->reserved) {
- *pResOut = 1;
- return SQLITE_OK;
- }
+ return SQLITE_OK;
+}
- /* Check if a thread in this process holds such a lock */
- if (pFile->pInode->eFileLock > SHARED_LOCK) {
- reserved = 1;
- }
+/*
+ * This function is called to handle the SQLITE_FCNTL_SIZE_HINT
+ * file-control operation. Enlarge the database to nBytes in size
+ * (rounded up to the next chunk-size). If the database is already
+ * nBytes or larger, this routine is a no-op.
+ */
+static int
+fcntlSizeHint(unixFile * pFile, i64 nByte)
+{
+ if (pFile->szChunk > 0) {
+ i64 nSize; /* Required file size */
+ struct stat buf; /* Used to hold return values of fstat() */
- /* Otherwise see if some other process holds it.
- */
- if (!reserved) {
- /* lock the RESERVED byte */
- 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 =
- afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,
- 0);
- } else {
- /* if we failed to get the lock then someone else must have it */
- reserved = 1;
+ if (fstat(pFile->h, &buf))
+ return SQLITE_IOERR_FSTAT;
+
+ nSize =
+ ((nByte + pFile->szChunk -
+ 1) / pFile->szChunk) * pFile->szChunk;
+ if (nSize > (i64) buf.st_size) {
+ int nBlk = buf.st_blksize; /* File-system block size */
+ int nWrite = 0; /* Number of bytes written by seekAndWrite */
+ i64 iWrite; /* Next offset to write to */
+
+ iWrite = (buf.st_size / nBlk) * nBlk + nBlk - 1;
+ assert(iWrite >= buf.st_size);
+ assert(((iWrite + 1) % nBlk) == 0);
+ for ( /*no-op */ ; iWrite < nSize + nBlk - 1;
+ iWrite += nBlk) {
+ if (iWrite >= nSize)
+ iWrite = nSize - 1;
+ nWrite = seekAndWrite(pFile, iWrite, "", 1);
+ if (nWrite != 1)
+ return SQLITE_IOERR_WRITE;
+ }
}
- if (IS_LOCK_ERROR(lrc)) {
- rc = lrc;
+ }
+ if (pFile->mmapSizeMax > 0 && nByte > pFile->mmapSize) {
+ int rc;
+ if (pFile->szChunk <= 0) {
+ if (robust_ftruncate(pFile->h, nByte)) {
+ storeLastErrno(pFile, errno);
+ return unixLogError(SQLITE_IOERR_TRUNCATE,
+ "ftruncate", pFile->zPath);
+ }
}
+
+ rc = unixMapfile(pFile, nByte);
+ return rc;
}
- *pResOut = reserved;
- return rc;
+ return SQLITE_OK;
}
+/* Forward declaration */
+static int unixGetTempname(int nBuf, char *zBuf);
+
/*
- * Lock the file with the lock specified by parameter eFileLock - 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.
+ * Information and control of an open file handle.
*/
static int
-afpLock(sqlite3_file * id, int eFileLock)
+unixFileControl(sqlite3_file * id, int op, void *pArg)
{
- int rc = SQLITE_OK;
unixFile *pFile = (unixFile *) id;
- unixInodeInfo *pInode = pFile->pInode;
- afpLockingContext *context =
- (afpLockingContext *) pFile->lockingContext;
-
- assert(pFile);
-
- /* If there is already a lock of this type or more restrictive on the
- * unixFile, do nothing.
- */
- if (pFile->eFileLock >= eFileLock) {
- return SQLITE_OK;
- }
-
- /* Make sure the locking sequence is correct
- * (1) We never move from unlocked to anything higher than shared lock.
- * (2) SQLite never explicitly requests a pendig lock.
- * (3) A shared lock is always held when a reserve lock is requested.
- */
- assert(pFile->eFileLock != NO_LOCK || eFileLock == SHARED_LOCK);
- assert(eFileLock != PENDING_LOCK);
- assert(eFileLock != RESERVED_LOCK || pFile->eFileLock == SHARED_LOCK);
-
- pInode = pFile->pInode;
-
- /* If some thread using this PID has a lock via a different unixFile*
- * handle that precludes the requested lock, return BUSY.
- */
- if ((pFile->eFileLock != pInode->eFileLock &&
- (pInode->eFileLock >= PENDING_LOCK || eFileLock > SHARED_LOCK))
- ) {
- rc = SQLITE_BUSY;
- goto afp_end_lock;
- }
-
- /* If a SHARED lock is requested, and some thread using this PID already
- * has a SHARED or RESERVED lock, then increment reference counts and
- * return SQLITE_OK.
- */
- if (eFileLock == SHARED_LOCK &&
- (pInode->eFileLock == SHARED_LOCK
- || pInode->eFileLock == RESERVED_LOCK)) {
- assert(eFileLock == SHARED_LOCK);
- assert(pFile->eFileLock == 0);
- assert(pInode->nShared > 0);
- pFile->eFileLock = SHARED_LOCK;
- pInode->nShared++;
- pInode->nLock++;
- goto afp_end_lock;
- }
-
- /* 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 (eFileLock == SHARED_LOCK
- || (eFileLock == EXCLUSIVE_LOCK && pFile->eFileLock < PENDING_LOCK)
- ) {
- int failed;
- failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1);
- if (failed) {
- rc = failed;
- goto afp_end_lock;
+ switch (op) {
+ case SQLITE_FCNTL_LOCKSTATE:{
+ *(int *)pArg = pFile->eFileLock;
+ return SQLITE_OK;
}
- }
-
- /* If control gets to this point, then actually go ahead and make
- * operating system calls for the specified lock.
- */
- if (eFileLock == SHARED_LOCK) {
- int lrc1, lrc2, lrc1Errno = 0;
- long lk, mask;
-
- assert(pInode->nShared == 0);
- assert(pInode->eFileLock == 0);
-
- mask = (sizeof(long) == 8) ? LARGEST_INT64 : 0x7fffffff;
- /* Now get the read-lock SHARED_LOCK */
- /* note that the quality of the randomness doesn't matter that much */
- lk = random();
- pInode->sharedByte = (lk & mask) % (SHARED_SIZE - 1);
- lrc1 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + pInode->sharedByte, 1, 1);
- if (IS_LOCK_ERROR(lrc1)) {
- lrc1Errno = pFile->lastErrno;
+ case SQLITE_FCNTL_LAST_ERRNO:{
+ *(int *)pArg = pFile->lastErrno;
+ return SQLITE_OK;
}
- /* Drop the temporary PENDING lock */
- lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
-
- if (IS_LOCK_ERROR(lrc1)) {
- storeLastErrno(pFile, lrc1Errno);
- rc = lrc1;
- goto afp_end_lock;
- } else if (IS_LOCK_ERROR(lrc2)) {
- rc = lrc2;
- goto afp_end_lock;
- } else if (lrc1 != SQLITE_OK) {
- rc = lrc1;
- } else {
- pFile->eFileLock = SHARED_LOCK;
- pInode->nLock++;
- pInode->nShared = 1;
+ case SQLITE_FCNTL_CHUNK_SIZE:{
+ pFile->szChunk = *(int *)pArg;
+ return SQLITE_OK;
}
- } else if (eFileLock == EXCLUSIVE_LOCK && pInode->nShared > 1) {
- /* We are trying for an exclusive lock but another thread in this
- * same process is still holding a shared lock.
- */
- rc = SQLITE_BUSY;
- } 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->eFileLock);
- if (eFileLock >= RESERVED_LOCK
- && pFile->eFileLock < RESERVED_LOCK) {
- /* Acquire a RESERVED lock */
- failed =
- afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,
- 1);
- if (!failed) {
- context->reserved = 1;
+ case SQLITE_FCNTL_SIZE_HINT:{
+ int rc;
+ SimulateIOErrorBenign(1);
+ rc = fcntlSizeHint(pFile, *(i64 *) pArg);
+ SimulateIOErrorBenign(0);
+ return rc;
+ }
+ case SQLITE_FCNTL_VFSNAME:{
+ *(char **)pArg =
+ sqlite3_mprintf("%s", pFile->pVfs->zName);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_TEMPFILENAME:{
+ char *zTFile =
+ sqlite3_malloc64(pFile->pVfs->mxPathname);
+ if (zTFile) {
+ unixGetTempname(pFile->pVfs->mxPathname,
+ zTFile);
+ *(char **)pArg = zTFile;
}
+ return SQLITE_OK;
}
- if (!failed && eFileLock == 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 afpUnlock
- */
- if (!
- (failed =
- afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + pInode->sharedByte, 1,
- 0))) {
- int failed2 = SQLITE_OK;
- /* now attemmpt to get the exclusive lock range */
- failed =
- afpSetLock(context->dbPath, pFile,
- SHARED_FIRST, SHARED_SIZE, 1);
- if (failed
- && (failed2 =
- afpSetLock(context->dbPath, pFile,
- SHARED_FIRST +
- pInode->sharedByte, 1, 1))) {
- /* Can't reestablish the shared lock. Sqlite can't deal, this is
- * a critical I/O error
- */
- rc = ((failed & SQLITE_IOERR) ==
- SQLITE_IOERR) ? failed2 :
- SQLITE_IOERR_LOCK;
- goto afp_end_lock;
+ case SQLITE_FCNTL_HAS_MOVED:{
+ *(int *)pArg = fileHasMoved(pFile);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_MMAP_SIZE:{
+ i64 newLimit = *(i64 *) pArg;
+ int rc = SQLITE_OK;
+ if (newLimit > sqlite3GlobalConfig.mxMmap) {
+ newLimit = sqlite3GlobalConfig.mxMmap;
+ }
+ *(i64 *) pArg = pFile->mmapSizeMax;
+ if (newLimit >= 0 && newLimit != pFile->mmapSizeMax
+ && pFile->nFetchOut == 0) {
+ pFile->mmapSizeMax = newLimit;
+ if (pFile->mmapSize > 0) {
+ unixUnmapfile(pFile);
+ rc = unixMapfile(pFile, -1);
}
- } else {
- rc = failed;
}
+ return rc;
}
- if (failed) {
- rc = failed;
- }
- }
-
- if (rc == SQLITE_OK) {
- pFile->eFileLock = eFileLock;
- pInode->eFileLock = eFileLock;
- } else if (eFileLock == EXCLUSIVE_LOCK) {
- pFile->eFileLock = PENDING_LOCK;
- pInode->eFileLock = PENDING_LOCK;
}
-
- afp_end_lock:
- return rc;
+ return SQLITE_NOTFOUND;
}
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * must be either NO_LOCK or SHARED_LOCK.
+ * 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.
*
- * If the locking level of the file descriptor is already at or below
- * the requested locking level, this routine is a no-op.
+ * 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
-afpUnlock(sqlite3_file * id, int eFileLock)
+unixSectorSize(sqlite3_file * NotUsed)
{
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
- unixInodeInfo *pInode;
- afpLockingContext *context =
- (afpLockingContext *) pFile->lockingContext;
- int skipShared = 0;
-#ifdef SQLITE_TEST
- int h = pFile->h;
-#endif
-
- assert(pFile);
-
- assert(eFileLock <= SHARED_LOCK);
- if (pFile->eFileLock <= eFileLock) {
- return SQLITE_OK;
- }
- pInode = pFile->pInode;
- assert(pInode->nShared != 0);
- if (pFile->eFileLock > SHARED_LOCK) {
- assert(pInode->eFileLock == pFile->eFileLock);
- SimulateIOErrorBenign(1);
- SimulateIOError(h = (-1))
- SimulateIOErrorBenign(0);
-
-#ifdef SQLITE_DEBUG
- /* When reducing a lock such that other processes can start
- * reading the database file again, make sure that the
- * transaction counter was updated if any part of the database
- * file changed. If the transaction counter is not updated,
- * other connections to the same file might not realize that
- * the file has changed and hence might not know to flush their
- * cache. The use of a stale cache can lead to database corruption.
- */
- assert(pFile->inNormalWrite == 0
- || pFile->dbUpdate == 0 || pFile->transCntrChng == 1);
- pFile->inNormalWrite = 0;
-#endif
-
- if (pFile->eFileLock == EXCLUSIVE_LOCK) {
- rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
- SHARED_SIZE, 0);
- if (rc == SQLITE_OK
- && (eFileLock == SHARED_LOCK
- || pInode->nShared > 1)) {
- /* only re-establish the shared lock if necessary */
- int sharedLockByte =
- SHARED_FIRST + pInode->sharedByte;
- rc = afpSetLock(context->dbPath, pFile,
- sharedLockByte, 1, 1);
- } else {
- skipShared = 1;
- }
- }
- if (rc == SQLITE_OK && pFile->eFileLock >= PENDING_LOCK) {
- rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1,
- 0);
- }
- if (rc == SQLITE_OK && pFile->eFileLock >= RESERVED_LOCK
- && context->reserved) {
- rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE,
- 1, 0);
- if (!rc) {
- context->reserved = 0;
- }
- }
- if (rc == SQLITE_OK
- && (eFileLock == SHARED_LOCK || pInode->nShared > 1)) {
- pInode->eFileLock = SHARED_LOCK;
- }
- }
- if (rc == SQLITE_OK && eFileLock == NO_LOCK) {
-
- /* Decrement the shared lock counter. Release the lock using an
- * OS call only when all threads in this same process have released
- * the lock.
- */
- unsigned long long sharedLockByte =
- SHARED_FIRST + pInode->sharedByte;
- pInode->nShared--;
- if (pInode->nShared == 0) {
- SimulateIOErrorBenign(1);
- SimulateIOError(h = (-1))
- SimulateIOErrorBenign(0);
- if (!skipShared) {
- rc = afpSetLock(context->dbPath, pFile,
- sharedLockByte, 1, 0);
- }
- if (!rc) {
- pInode->eFileLock = NO_LOCK;
- pFile->eFileLock = NO_LOCK;
- }
- }
- if (rc == SQLITE_OK) {
- pInode->nLock--;
- assert(pInode->nLock >= 0);
- if (pInode->nLock == 0) {
- closePendingFds(pFile);
- }
- }
- }
-
- if (rc == SQLITE_OK)
- pFile->eFileLock = eFileLock;
- return rc;
+ UNUSED_PARAMETER(NotUsed);
+ return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
- * Close a file & cleanup AFP specific locking context
+ * Return the device characteristics for the file.
+ *
+ * This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
+ * However, that choice is controversial since technically the underlying
+ * file system does not always provide powersafe overwrites. (In other
+ * words, after a power-loss event, parts of the file that were never
+ * written might end up being altered.) However, non-PSOW behavior is very,
+ * very rare. And asserting PSOW makes a large reduction in the amount
+ * of required I/O for journaling, since a lot of padding is eliminated.
+ * Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
+ * available to turn it off and URI query parameter available to turn it off.
*/
static int
-afpClose(sqlite3_file * id)
+unixDeviceCharacteristics(sqlite3_file * pNotUsed)
{
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
- assert(id != 0);
- afpUnlock(id, NO_LOCK);
- if (pFile->pInode && pFile->pInode->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 pInode->aPending. It will be automatically closed when
- * the last lock is cleared.
- */
- setPendingFd(pFile);
- }
- releaseInodeInfo(pFile);
- sqlite3_free(pFile->lockingContext);
- rc = closeUnixFile(id);
- return rc;
+ UNUSED_PARAMETER(pNotUsed);
+ return SQLITE_OK;
}
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
-/*
- * The code above is the AFP lock implementation. The code is specific
- * to MacOSX and does not work on other unix platforms. No alternative
- * is available. If you don't compile for a mac, then the "unix-afp"
- * VFS is not available.
- *
- ******************** End of the AFP lock implementation **********************
- *****************************************************************************/
-
-/******************************************************************************
- ************************** Begin NFS Locking *******************************
- */
+#define unixShmMap 0
+#define unixShmLock 0
+#define unixShmBarrier 0
+#define unixShmUnmap 0
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
- ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- ** 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.
+ * If it is currently memory mapped, unmap file pFd.
*/
-static int
-nfsUnlock(sqlite3_file * id, int eFileLock)
+static void
+unixUnmapfile(unixFile * pFd)
{
- return posixUnlock(id, eFileLock, 1);
+ assert(pFd->nFetchOut == 0);
+ if (pFd->pMapRegion) {
+ munmap(pFd->pMapRegion, pFd->mmapSizeActual);
+ pFd->pMapRegion = 0;
+ pFd->mmapSize = 0;
+ pFd->mmapSizeActual = 0;
+ }
}
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
/*
- * The code above is the NFS lock implementation. The code is specific
- * to MacOSX and does not work on other unix platforms. No alternative
- * is available.
+ * Attempt to set the size of the memory mapping maintained by file
+ * descriptor pFd to nNew bytes. Any existing mapping is discarded.
*
- ******************** End of the NFS lock implementation **********************
- *****************************************************************************/
-
-/******************************************************************************
- *************** Non-locking sqlite3_file methods *****************************
+ * If successful, this function sets the following variables:
*
- * The next division contains implementations for all methods of the
- * sqlite3_file object other than the locking methods. The locking
- * methods were defined in divisions above (one locking method per
- * division). Those methods that are common to all locking modes
- * are gather together into this division.
- */
-
-/*
- * Seek to the offset passed as the second argument, then read cnt
- * bytes into pBuf. Return the number of bytes actually read.
- *
- * 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
- * in any form by default, we will not attempt to define _XOPEN_SOURCE.
- * See tickets #2741 and #2681.
+ * unixFile.pMapRegion
+ * unixFile.mmapSize
+ * unixFile.mmapSizeActual
*
- * To avoid stomping the errno value on a failed read the lastErrno value
- * is set before returning.
+ * If unsuccessful, an error message is logged via sqlite3_log() and
+ * the three variables above are zeroed. In this case SQLite should
+ * continue accessing the database using the xRead() and xWrite()
+ * methods.
*/
-static int
-seekAndRead(unixFile * id, sqlite3_int64 offset, void *pBuf, int cnt)
+static void
+unixRemapfile(unixFile * pFd, /* File descriptor object */
+ i64 nNew /* Required mapping size */
+ )
{
- int got;
- int prior = 0;
-#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
- i64 newOffset;
-#endif
- TIMER_START;
- assert(cnt == (cnt & 0x1ffff));
- assert(id->h > 2);
- do {
-#if defined(USE_PREAD)
- got = osPread(id->h, pBuf, cnt, offset);
- SimulateIOError(got = -1);
-#elif defined(USE_PREAD64)
- got = osPread64(id->h, pBuf, cnt, offset);
- SimulateIOError(got = -1);
-#else
- newOffset = lseek(id->h, offset, SEEK_SET);
- SimulateIOError(newOffset = -1);
- if (newOffset < 0) {
- storeLastErrno((unixFile *) id, errno);
- return -1;
- }
- got = osRead(id->h, pBuf, cnt);
-#endif
- if (got == cnt)
- break;
- if (got < 0) {
- if (errno == EINTR) {
- got = 1;
- continue;
+ const char *zErr = "mmap";
+ int h = pFd->h; /* File descriptor open on db file */
+ u8 *pOrig = (u8 *) pFd->pMapRegion; /* Pointer to current file mapping */
+ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
+ u8 *pNew = 0; /* Location of new mapping */
+ int flags = PROT_READ; /* Flags to pass to mmap() */
+
+ assert(pFd->nFetchOut == 0);
+ assert(nNew > pFd->mmapSize);
+ assert(nNew <= pFd->mmapSizeMax);
+ assert(nNew > 0);
+ assert(pFd->mmapSizeActual >= pFd->mmapSize);
+ assert(MAP_FAILED != 0);
+
+ if (pOrig) {
+ i64 nReuse = pFd->mmapSize;
+ u8 *pReq = &pOrig[nReuse];
+
+ /* Unmap any pages of the existing mapping that cannot be reused. */
+ if (nReuse != nOrig)
+ munmap(pReq, nOrig - nReuse);
+ #ifndef __APPLE__
+ pNew = mremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
+ zErr = "mremap";
+ #else
+ pNew = mmap(pReq, nNew - nReuse, flags, MAP_SHARED, h, nReuse);
+ if (pNew != MAP_FAILED) {
+ if (pNew != pReq) {
+ munmap(pNew, nNew - nReuse);
+ pNew = NULL;
+ } else {
+ pNew = pOrig;
}
- prior = 0;
- storeLastErrno((unixFile *) id, errno);
- break;
- } else if (got > 0) {
- cnt -= got;
- offset += got;
- prior += got;
- pBuf = (void *)(got + (char *)pBuf);
}
- } while (got > 0);
- TIMER_END;
- return got + prior;
+ #endif
+
+ /* The attempt to extend the existing mapping failed. Free it. */
+ if (pNew == MAP_FAILED || pNew == NULL)
+ munmap(pOrig, nReuse);
+ }
+
+ /* If pNew is still NULL, try to create an entirely new mapping. */
+ if (pNew == NULL)
+ pNew = mmap(0, nNew, flags, MAP_SHARED, h, 0);
+
+ if (pNew == MAP_FAILED) {
+ pNew = 0;
+ nNew = 0;
+ unixLogError(SQLITE_OK, zErr, pFd->zPath);
+
+ /* If the mmap() above failed, assume that all subsequent mmap() calls
+ * will probably fail too. Fall back to using xRead/xWrite exclusively
+ * in this case.
+ */
+ pFd->mmapSizeMax = 0;
+ }
+ pFd->pMapRegion = (void *)pNew;
+ pFd->mmapSize = pFd->mmapSizeActual = nNew;
}
/*
- * Read data from a file into a buffer. Return SQLITE_OK if all
- * bytes were read successfully and SQLITE_IOERR if anything goes
- * wrong.
+ * Memory map or remap the file opened by file-descriptor pFd (if the file
+ * is already mapped, the existing mapping is replaced by the new). Or, if
+ * there already exists a mapping for this file, and there are still
+ * outstanding xFetch() references to it, this function is a no-op.
+ *
+ * If parameter nByte is non-negative, then it is the requested size of
+ * the mapping to create. Otherwise, if nByte is less than zero, then the
+ * requested size is the size of the file on disk. The actual size of the
+ * created mapping is either the requested size or the value configured
+ * using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
+ *
+ * SQLITE_OK is returned if no error occurs (even if the mapping is not
+ * recreated as a result of outstanding references) or an SQLite error
+ * code otherwise.
*/
static int
-unixRead(sqlite3_file * id, void *pBuf, int amt, sqlite3_int64 offset)
+unixMapfile(unixFile * pFd, i64 nMap)
{
- unixFile *pFile = (unixFile *) id;
- int got;
- assert(id);
- assert(offset >= 0);
- assert(amt > 0);
+ assert(nMap >= 0 || pFd->nFetchOut == 0);
+ assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
+ if (pFd->nFetchOut > 0)
+ return SQLITE_OK;
-#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
- * data from the memory mapping using memcpy().
- */
- if (offset < pFile->mmapSize) {
- if (offset + amt <= pFile->mmapSize) {
- memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
- amt);
- return SQLITE_OK;
- } else {
- int nCopy = pFile->mmapSize - offset;
- memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
- nCopy);
- pBuf = &((u8 *) pBuf)[nCopy];
- amt -= nCopy;
- offset += nCopy;
- }
+ if (nMap < 0) {
+ struct stat statbuf; /* Low-level file information */
+ if (fstat(pFd->h, &statbuf))
+ return SQLITE_IOERR_FSTAT;
+ nMap = statbuf.st_size;
+ }
+ if (nMap > pFd->mmapSizeMax) {
+ nMap = pFd->mmapSizeMax;
}
-#endif
- got = seekAndRead(pFile, offset, pBuf, amt);
- if (got == amt) {
- return SQLITE_OK;
- } else if (got < 0) {
- /* lastErrno set by seekAndRead */
- return SQLITE_IOERR_READ;
- } else {
- storeLastErrno(pFile, 0); /* not a system error */
- /* Unread parts of the buffer must be zero-filled */
- memset(&((char *)pBuf)[got], 0, amt - got);
- return SQLITE_IOERR_SHORT_READ;
+ assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
+ if (nMap != pFd->mmapSize) {
+ unixRemapfile(pFd, nMap);
}
+
+ return SQLITE_OK;
}
/*
- * Attempt to seek the file-descriptor passed as the first argument to
- * absolute offset iOff, then attempt to write nBuf bytes of data from
- * pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
- * return the actual number of bytes written (which may be less than
- * nBuf).
+ * If possible, return a pointer to a mapping of file fd starting at offset
+ * iOff. The mapping must be valid for at least nAmt bytes.
+ *
+ * If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
+ * Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
+ * Finally, if an error does occur, return an SQLite error code. The final
+ * value of *pp is undefined in this case.
+ *
+ * If this function does return a pointer, the caller must eventually
+ * release the reference by calling unixUnfetch().
*/
static int
-seekAndWriteFd(int fd, /* File descriptor to write to */
- i64 iOff, /* File offset to begin writing at */
- const void *pBuf, /* Copy data from this buffer to the file */
- int nBuf, /* Size of buffer pBuf in bytes */
- int *piErrno /* OUT: Error number if error occurs */
- )
+unixFetch(sqlite3_file * fd MAYBE_UNUSED,
+ i64 iOff MAYBE_UNUSED,
+ int nAmt MAYBE_UNUSED, void **pp)
{
- int rc = 0; /* Value returned by system call */
-
- assert(nBuf == (nBuf & 0x1ffff));
- assert(fd > 2);
- assert(piErrno != 0);
- nBuf &= 0x1ffff;
- TIMER_START;
+#if SQLITE_MAX_MMAP_SIZE>0
+ unixFile *pFd = (unixFile *) fd; /* The underlying database file */
+#endif
+ *pp = 0;
-#if defined(USE_PREAD)
- do {
- rc = (int)osPwrite(fd, pBuf, nBuf, iOff);
- } while (rc < 0 && errno == EINTR);
-#elif defined(USE_PREAD64)
- do {
- rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);
- } while (rc < 0 && errno == EINTR);
-#else
- do {
- i64 iSeek = lseek(fd, iOff, SEEK_SET);
- SimulateIOError(iSeek = -1);
- if (iSeek < 0) {
- rc = -1;
- break;
+#if SQLITE_MAX_MMAP_SIZE>0
+ if (pFd->mmapSizeMax > 0) {
+ if (pFd->pMapRegion == 0) {
+ int rc = unixMapfile(pFd, -1);
+ if (rc != SQLITE_OK)
+ return rc;
}
- rc = osWrite(fd, pBuf, nBuf);
- } while (rc < 0 && errno == EINTR);
+ if (pFd->mmapSize >= iOff + nAmt) {
+ *pp = &((u8 *) pFd->pMapRegion)[iOff];
+ pFd->nFetchOut++;
+ }
+ }
#endif
-
- TIMER_END;
-
- if (rc < 0)
- *piErrno = errno;
- return rc;
+ return SQLITE_OK;
}
/*
- * Seek to the offset in id->offset then read cnt bytes into pBuf.
- * Return the number of bytes actually read. Update the offset.
+ * If the third argument is non-NULL, then this function releases a
+ * reference obtained by an earlier call to unixFetch(). The second
+ * argument passed to this function must be the same as the corresponding
+ * argument that was passed to the unixFetch() invocation.
*
- * To avoid stomping the errno value on a failed write the lastErrno value
- * is set before returning.
+ * Or, if the third argument is NULL, then this function is being called
+ * to inform the VFS layer that, according to POSIX, any existing mapping
+ * may now be invalid and should be unmapped.
*/
static int
-seekAndWrite(unixFile * id, i64 offset, const void *pBuf, int cnt)
+unixUnfetch(sqlite3_file * fd, i64 iOff, void *p)
{
- return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
-}
+ unixFile *pFd = (unixFile *) fd; /* The underlying database file */
+ UNUSED_PARAMETER(iOff);
-/*
- * Write data from a buffer into a file. Return SQLITE_OK on success
- * or some other error code on failure.
- */
-static int
-unixWrite(sqlite3_file * id, const void *pBuf, int amt, sqlite3_int64 offset)
-{
- unixFile *pFile = (unixFile *) id;
- int wrote = 0;
- assert(id);
- assert(amt > 0);
-
-#ifdef SQLITE_DEBUG
- /* If we are doing a normal write to a database file,
- * then record the fact that the database
- * has changed. If the transaction counter is modified, record that
- * fact too.
- */
- if (pFile->inNormalWrite) {
- pFile->dbUpdate = 1; /* The database has been modified */
- if (offset <= 24 && offset + amt >= 27) {
- int rc;
- char oldCntr[4];
- SimulateIOErrorBenign(1);
- rc = seekAndRead(pFile, 24, oldCntr, 4);
- SimulateIOErrorBenign(0);
- if (rc != 4
- || memcmp(oldCntr, &((char *)pBuf)[24 - offset],
- 4) != 0) {
- pFile->transCntrChng = 1; /* The transaction counter has changed */
- }
- }
- }
-#endif
-
-#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
- * data from the memory mapping using memcpy().
- */
- if (offset < pFile->mmapSize) {
- if (offset + amt <= pFile->mmapSize) {
- memcpy(&((u8 *) (pFile->pMapRegion))[offset], pBuf,
- amt);
- return SQLITE_OK;
- } else {
- int nCopy = pFile->mmapSize - offset;
- memcpy(&((u8 *) (pFile->pMapRegion))[offset], pBuf,
- nCopy);
- pBuf = &((u8 *) pBuf)[nCopy];
- amt -= nCopy;
- offset += nCopy;
- }
- }
-#endif
-
- while ((wrote = seekAndWrite(pFile, offset, pBuf, amt)) < amt
- && wrote > 0) {
- amt -= wrote;
- offset += wrote;
- pBuf = &((char *)pBuf)[wrote];
- }
- SimulateIOError((wrote = (-1), amt = 1));
- SimulateDiskfullError((wrote = 0, amt = 1));
-
- if (amt > wrote) {
- if (wrote < 0 && pFile->lastErrno != ENOSPC) {
- /* lastErrno set by seekAndWrite */
- return SQLITE_IOERR_WRITE;
- } else {
- storeLastErrno(pFile, 0); /* not a system error */
- return SQLITE_FULL;
- }
- }
-
- return SQLITE_OK;
-}
-
-#ifdef SQLITE_TEST
-/*
- * Count the number of fullsyncs and normal syncs. This is used to test
- * that syncs and fullsyncs are occurring at the right times.
- */
-int sqlite3_sync_count = 0;
-int sqlite3_fullsync_count = 0;
-#endif
-
-/*
- * We do not trust systems to provide a working fdatasync(). Some do.
- * Others do no. To be safe, we will stick with the (slightly slower)
- * fsync(). If you know that your system does support fdatasync() correctly,
- * then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
- */
-#if !defined(fdatasync) && !HAVE_FDATASYNC
-#define fdatasync fsync
-#endif
-
-/*
- * The fsync() system call does not work as advertised on many
- * unix systems. The following procedure is an attempt to make
- * it work better.
- *
- * The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
- * for testing when we want to run through the test suite quickly.
- * You are strongly advised *not* to deploy with SQLITE_NO_SYNC
- * enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
- * or power failure will likely corrupt the database file.
- *
- * SQLite sets the dataOnly flag if the size of the file is unchanged.
- * The idea behind dataOnly is that it should only write the file content
- * to disk, not the inode. We only set dataOnly if the file size is
- * unchanged since the file size is part of the inode. However,
- * Ted Ts'o tells us that fdatasync() will also write the inode if the
- * file size has changed. The only real difference between fdatasync()
- * and fsync(), Ted tells us, is that fdatasync() will not flush the
- * inode if the mtime or owner or other inode attributes have changed.
- * We only care about the file size, not the other file attributes, so
- * as far as SQLite is concerned, an fdatasync() is always adequate.
- * So, we always use fdatasync() if it is available, regardless of
- * the value of the dataOnly flag.
- */
-static int
-full_fsync(int fd, int fullSync, int dataOnly)
-{
- int rc;
-
- /* The following "ifdef/elif/else/" block has the same structure as
- * the one below. It is replicated here solely to avoid cluttering
- * up the real code with the UNUSED_PARAMETER() macros.
- */
-#ifdef SQLITE_NO_SYNC
- UNUSED_PARAMETER(fd);
- UNUSED_PARAMETER(fullSync);
- UNUSED_PARAMETER(dataOnly);
-#else
- UNUSED_PARAMETER(fullSync);
- UNUSED_PARAMETER(dataOnly);
-#endif
-
- /* Record the number of times that we do a normal fsync() and
- * FULLSYNC. This is used during testing to verify that this procedure
- * gets called with the correct arguments.
- */
-#ifdef SQLITE_TEST
- if (fullSync)
- sqlite3_fullsync_count++;
- sqlite3_sync_count++;
-#endif
-
- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
- * no-op. But go ahead and call fstat() to validate the file
- * descriptor as we need a method to provoke a failure during
- * coverate testing.
- */
-#ifdef SQLITE_NO_SYNC
- {
- struct stat buf;
- rc = osFstat(fd, &buf);
- }
-#elif defined(__APPLE__)
- /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
- * so currently we default to the macro that redefines fdatasync to fsync
- */
- rc = fsync(fd);
-#else
- rc = fdatasync(fd);
-#endif /* ifdef SQLITE_NO_SYNC */
-
- return rc;
-}
-
-/*
- * 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.
- *
- * The directory file descriptor is used for only one thing - to
- * fsync() a directory to make sure file creation and deletion events
- * are flushed to disk. Such fsyncs are not needed on newer
- * journaling filesystems, but are required on older filesystems.
- *
- * This routine can be overridden using the xSetSysCall interface.
- * The ability to override this routine was added in support of the
- * chromium sandbox. Opening a directory is a security risk (we are
- * told) so making it overrideable allows the chromium sandbox to
- * replace this routine with a harmless no-op. To make this routine
- * a no-op, replace it with a stub that returns SQLITE_OK but leaves
- * *pFd set to a negative number.
- *
- * 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;
- char zDirname[MAX_PATHNAME + 1];
-
- sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
- for (ii = (int)strlen(zDirname); ii > 0 && zDirname[ii] != '/'; ii--) ;
- if (ii > 0) {
- zDirname[ii] = '\0';
- } else {
- if (zDirname[0] != '/')
- zDirname[0] = '.';
- zDirname[1] = 0;
- }
- fd = robust_open(zDirname, O_RDONLY | O_BINARY, 0);
-
- *pFd = fd;
- if (fd >= 0)
- return SQLITE_OK;
- return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
-}
-
-/*
- * Make sure all writes to a particular file are committed to disk.
- *
- * If dataOnly==0 then both the file itself and its metadata (file
- * size, access time, etc) are synced. If dataOnly!=0 then only the
- * file data is synced.
- *
- * Under Unix, also make sure that the directory entry for the file
- * has been created by fsync-ing the directory that contains the file.
- * If we do not do this and we encounter a power failure, the directory
- * entry for the journal might not exist after we reboot. The next
- * SQLite to access the file will not know that the journal exists (because
- * the directory entry for the journal was never created) and the transaction
- * will not roll back - possibly leading to database corruption.
- */
-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);
-
- /* Unix cannot, but some systems may return SQLITE_FULL from here. This
- * line is to test that doing so does not cause any problems.
- */
- SimulateDiskfullError(return SQLITE_FULL);
-
- assert(pFile);
- rc = full_fsync(pFile->h, isFullsync, isDataOnly);
- SimulateIOError(rc = 1);
- if (rc) {
- storeLastErrno(pFile, errno);
- return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync",
- pFile->zPath);
- }
-
- return rc;
-}
-
-/*
- * Truncate an open file to a specified size
- */
-static int
-unixTruncate(sqlite3_file * id, i64 nByte)
-{
- unixFile *pFile = (unixFile *) id;
- int rc;
- assert(pFile);
- SimulateIOError(return SQLITE_IOERR_TRUNCATE);
-
- /* If the user has configured a chunk-size for this file, truncate the
- * file so that it consists of an integer number of chunks (i.e. the
- * actual file size after the operation may be larger than the requested
- * size).
- */
- if (pFile->szChunk > 0) {
- nByte =
- ((nByte + pFile->szChunk -
- 1) / pFile->szChunk) * pFile->szChunk;
- }
-
- rc = robust_ftruncate(pFile->h, nByte);
- if (rc) {
- storeLastErrno(pFile, errno);
- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate",
- pFile->zPath);
- } else {
-#ifdef SQLITE_DEBUG
- /* If we are doing a normal write to a database file (as opposed to
- * doing a hot-journal rollback or a write to some file other than a
- * normal database file) and we truncate the file to zero length,
- * that effectively updates the change counter.
- */
- if (pFile->inNormalWrite && nByte == 0) {
- pFile->transCntrChng = 1;
- }
-#endif
-
-#if SQLITE_MAX_MMAP_SIZE>0
- /* If the file was just truncated to a size smaller than the currently
- * mapped region, reduce the effective mapping size as well. SQLite will
- * use read() and write() to access data beyond this point from now on.
- */
- if (nByte < pFile->mmapSize) {
- pFile->mmapSize = nByte;
- }
-#endif
-
- return SQLITE_OK;
- }
-}
-
-/*
- * Determine the current size of a file in bytes
- */
-static int
-unixFileSize(sqlite3_file * id, i64 * pSize)
-{
- int rc;
- struct stat buf;
- assert(id);
- rc = osFstat(((unixFile *) id)->h, &buf);
- SimulateIOError(rc = 1);
- if (rc != 0) {
- storeLastErrno((unixFile *) id, errno);
- return SQLITE_IOERR_FSTAT;
- }
- *pSize = buf.st_size;
-
- /* When opening a zero-size database, the findInodeInfo() procedure
- * writes a single byte into that file in order to work around a bug
- * in the OS-X msdos filesystem. In order to avoid problems with upper
- * layers, we need to report this file size as zero even though it is
- * really 1. Ticket #3260.
- */
- if (*pSize == 1)
- *pSize = 0;
-
- return SQLITE_OK;
-}
-
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
-/*
- * Handler for proxy-locking file-control verbs. Defined below in the
- * proxying locking division.
- */
-static int proxyFileControl(sqlite3_file *, int, void *);
-#endif
-
-/*
- * This function is called to handle the SQLITE_FCNTL_SIZE_HINT
- * file-control operation. Enlarge the database to nBytes in size
- * (rounded up to the next chunk-size). If the database is already
- * nBytes or larger, this routine is a no-op.
- */
-static int
-fcntlSizeHint(unixFile * pFile, i64 nByte)
-{
- if (pFile->szChunk > 0) {
- i64 nSize; /* Required file size */
- struct stat buf; /* Used to hold return values of fstat() */
-
- if (osFstat(pFile->h, &buf)) {
- return SQLITE_IOERR_FSTAT;
- }
-
- nSize =
- ((nByte + pFile->szChunk -
- 1) / pFile->szChunk) * pFile->szChunk;
- if (nSize > (i64) buf.st_size) {
-
-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
- /* The code below is handling the return value of osFallocate()
- * correctly. posix_fallocate() is defined to "returns zero on success,
- * or an error number on failure". See the manpage for details.
- */
- int err;
- do {
- err =
- osFallocate(pFile->h, buf.st_size,
- nSize - buf.st_size);
- } while (err == EINTR);
- if (err)
- return SQLITE_IOERR_WRITE;
-#else
- /* If the OS does not have posix_fallocate(), fake it. Write a
- * single byte to the last byte in each block that falls entirely
- * within the extended region. Then, if required, a single byte
- * at offset (nSize-1), to set the size of the file correctly.
- * This is a similar technique to that used by glibc on systems
- * that do not have a real fallocate() call.
- */
- int nBlk = buf.st_blksize; /* File-system block size */
- int nWrite = 0; /* Number of bytes written by seekAndWrite */
- i64 iWrite; /* Next offset to write to */
-
- iWrite = (buf.st_size / nBlk) * nBlk + nBlk - 1;
- assert(iWrite >= buf.st_size);
- assert(((iWrite + 1) % nBlk) == 0);
- for ( /*no-op */ ; iWrite < nSize + nBlk - 1;
- iWrite += nBlk) {
- if (iWrite >= nSize)
- iWrite = nSize - 1;
- nWrite = seekAndWrite(pFile, iWrite, "", 1);
- if (nWrite != 1)
- return SQLITE_IOERR_WRITE;
- }
-#endif
- }
- }
-#if SQLITE_MAX_MMAP_SIZE>0
- if (pFile->mmapSizeMax > 0 && nByte > pFile->mmapSize) {
- int rc;
- if (pFile->szChunk <= 0) {
- if (robust_ftruncate(pFile->h, nByte)) {
- storeLastErrno(pFile, errno);
- return unixLogError(SQLITE_IOERR_TRUNCATE,
- "ftruncate", pFile->zPath);
- }
- }
-
- rc = unixMapfile(pFile, nByte);
- return rc;
- }
-#endif
-
- return SQLITE_OK;
-}
-
-/* Forward declaration */
-static int unixGetTempname(int nBuf, char *zBuf);
-
-/*
- * Information and control of an open file handle.
- */
-static int
-unixFileControl(sqlite3_file * id, int op, void *pArg)
-{
- unixFile *pFile = (unixFile *) id;
- switch (op) {
- case SQLITE_FCNTL_LOCKSTATE:{
- *(int *)pArg = pFile->eFileLock;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_LAST_ERRNO:{
- *(int *)pArg = pFile->lastErrno;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_CHUNK_SIZE:{
- pFile->szChunk = *(int *)pArg;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_SIZE_HINT:{
- int rc;
- SimulateIOErrorBenign(1);
- rc = fcntlSizeHint(pFile, *(i64 *) pArg);
- SimulateIOErrorBenign(0);
- return rc;
- }
- case SQLITE_FCNTL_VFSNAME:{
- *(char **)pArg =
- sqlite3_mprintf("%s", pFile->pVfs->zName);
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_TEMPFILENAME:{
- char *zTFile =
- sqlite3_malloc64(pFile->pVfs->mxPathname);
- if (zTFile) {
- unixGetTempname(pFile->pVfs->mxPathname,
- zTFile);
- *(char **)pArg = zTFile;
- }
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_HAS_MOVED:{
- *(int *)pArg = fileHasMoved(pFile);
- return SQLITE_OK;
- }
-#if SQLITE_MAX_MMAP_SIZE>0
- case SQLITE_FCNTL_MMAP_SIZE:{
- i64 newLimit = *(i64 *) pArg;
- int rc = SQLITE_OK;
- if (newLimit > sqlite3GlobalConfig.mxMmap) {
- newLimit = sqlite3GlobalConfig.mxMmap;
- }
- *(i64 *) pArg = pFile->mmapSizeMax;
- if (newLimit >= 0 && newLimit != pFile->mmapSizeMax
- && pFile->nFetchOut == 0) {
- pFile->mmapSizeMax = newLimit;
- if (pFile->mmapSize > 0) {
- unixUnmapfile(pFile);
- rc = unixMapfile(pFile, -1);
- }
- }
- return rc;
- }
-#endif
-#ifdef SQLITE_DEBUG
- /* The pager calls this method to signal that it has done
- * a rollback and that the database is therefore unchanged and
- * it hence it is OK for the transaction change counter to be
- * unchanged.
- */
- case SQLITE_FCNTL_DB_UNCHANGED:{
- ((unixFile *) id)->dbUpdate = 0;
- return SQLITE_OK;
- }
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- case SQLITE_FCNTL_SET_LOCKPROXYFILE:
- case SQLITE_FCNTL_GET_LOCKPROXYFILE:{
- return proxyFileControl(id, op, pArg);
- }
-#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
- }
- return SQLITE_NOTFOUND;
-}
-
-/*
- * 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
-unixSectorSize(sqlite3_file * NotUsed)
-{
- UNUSED_PARAMETER(NotUsed);
- return SQLITE_DEFAULT_SECTOR_SIZE;
-}
-
-/*
- * Return the device characteristics for the file.
- *
- * This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
- * However, that choice is controversial since technically the underlying
- * file system does not always provide powersafe overwrites. (In other
- * words, after a power-loss event, parts of the file that were never
- * written might end up being altered.) However, non-PSOW behavior is very,
- * very rare. And asserting PSOW makes a large reduction in the amount
- * of required I/O for journaling, since a lot of padding is eliminated.
- * Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
- * available to turn it off and URI query parameter available to turn it off.
- */
-static int
-unixDeviceCharacteristics(sqlite3_file * pNotUsed)
-{
- UNUSED_PARAMETER(pNotUsed);
- return SQLITE_OK;
-}
-
-#if SQLITE_MAX_MMAP_SIZE>0
-
-/*
- * Return the system page size.
- *
- * This function should not be called directly by other code in this file.
- * Instead, it should be called via macro osGetpagesize().
- */
-static int
-unixGetpagesize(void)
-{
- return (int)sysconf(_SC_PAGESIZE);
-}
-
-#endif /* SQLITE_MAX_MMAP_SIZE>0 */
-
-#define unixShmMap 0
-#define unixShmLock 0
-#define unixShmBarrier 0
-#define unixShmUnmap 0
-
-#if SQLITE_MAX_MMAP_SIZE>0
-/*
- * If it is currently memory mapped, unmap file pFd.
- */
-static void
-unixUnmapfile(unixFile * pFd)
-{
- assert(pFd->nFetchOut == 0);
- if (pFd->pMapRegion) {
- osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
- pFd->pMapRegion = 0;
- pFd->mmapSize = 0;
- pFd->mmapSizeActual = 0;
- }
-}
-
-/*
- * Attempt to set the size of the memory mapping maintained by file
- * descriptor pFd to nNew bytes. Any existing mapping is discarded.
- *
- * If successful, this function sets the following variables:
- *
- * unixFile.pMapRegion
- * unixFile.mmapSize
- * unixFile.mmapSizeActual
- *
- * If unsuccessful, an error message is logged via sqlite3_log() and
- * the three variables above are zeroed. In this case SQLite should
- * continue accessing the database using the xRead() and xWrite()
- * methods.
- */
-static void
-unixRemapfile(unixFile * pFd, /* File descriptor object */
- i64 nNew /* Required mapping size */
- )
-{
- const char *zErr = "mmap";
- int h = pFd->h; /* File descriptor open on db file */
- u8 *pOrig = (u8 *) pFd->pMapRegion; /* Pointer to current file mapping */
- i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
- u8 *pNew = 0; /* Location of new mapping */
- int flags = PROT_READ; /* Flags to pass to mmap() */
-
- assert(pFd->nFetchOut == 0);
- assert(nNew > pFd->mmapSize);
- assert(nNew <= pFd->mmapSizeMax);
- assert(nNew > 0);
- assert(pFd->mmapSizeActual >= pFd->mmapSize);
- assert(MAP_FAILED != 0);
-
-#ifdef SQLITE_MMAP_READWRITE
- if ((pFd->ctrlFlags & UNIXFILE_RDONLY) == 0)
- flags |= PROT_WRITE;
-#endif
-
- if (pOrig) {
-#if HAVE_MREMAP
- i64 nReuse = pFd->mmapSize;
-#else
- const int szSyspage = osGetpagesize();
- i64 nReuse = (pFd->mmapSize & ~(szSyspage - 1));
-#endif
- u8 *pReq = &pOrig[nReuse];
-
- /* Unmap any pages of the existing mapping that cannot be reused. */
- if (nReuse != nOrig) {
- osMunmap(pReq, nOrig - nReuse);
- }
-#if HAVE_MREMAP
- pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
- zErr = "mremap";
-#else
- pNew =
- osMmap(pReq, nNew - nReuse, flags, MAP_SHARED, h, nReuse);
- if (pNew != MAP_FAILED) {
- if (pNew != pReq) {
- osMunmap(pNew, nNew - nReuse);
- pNew = 0;
- } else {
- pNew = pOrig;
- }
- }
-#endif
-
- /* The attempt to extend the existing mapping failed. Free it. */
- if (pNew == MAP_FAILED || pNew == 0) {
- osMunmap(pOrig, nReuse);
- }
- }
-
- /* If pNew is still NULL, try to create an entirely new mapping. */
- if (pNew == 0) {
- pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
- }
-
- if (pNew == MAP_FAILED) {
- pNew = 0;
- nNew = 0;
- unixLogError(SQLITE_OK, zErr, pFd->zPath);
-
- /* If the mmap() above failed, assume that all subsequent mmap() calls
- * will probably fail too. Fall back to using xRead/xWrite exclusively
- * in this case.
- */
- pFd->mmapSizeMax = 0;
- }
- pFd->pMapRegion = (void *)pNew;
- pFd->mmapSize = pFd->mmapSizeActual = nNew;
-}
-
-/*
- * Memory map or remap the file opened by file-descriptor pFd (if the file
- * is already mapped, the existing mapping is replaced by the new). Or, if
- * there already exists a mapping for this file, and there are still
- * outstanding xFetch() references to it, this function is a no-op.
- *
- * If parameter nByte is non-negative, then it is the requested size of
- * the mapping to create. Otherwise, if nByte is less than zero, then the
- * requested size is the size of the file on disk. The actual size of the
- * created mapping is either the requested size or the value configured
- * using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
- *
- * SQLITE_OK is returned if no error occurs (even if the mapping is not
- * recreated as a result of outstanding references) or an SQLite error
- * code otherwise.
- */
-static int
-unixMapfile(unixFile * pFd, i64 nMap)
-{
- assert(nMap >= 0 || pFd->nFetchOut == 0);
- assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
- if (pFd->nFetchOut > 0)
- return SQLITE_OK;
-
- if (nMap < 0) {
- struct stat statbuf; /* Low-level file information */
- if (osFstat(pFd->h, &statbuf)) {
- return SQLITE_IOERR_FSTAT;
- }
- nMap = statbuf.st_size;
- }
- if (nMap > pFd->mmapSizeMax) {
- nMap = pFd->mmapSizeMax;
- }
-
- assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
- if (nMap != pFd->mmapSize) {
- unixRemapfile(pFd, nMap);
- }
-
- return SQLITE_OK;
-}
-#endif /* SQLITE_MAX_MMAP_SIZE>0 */
-
-/*
- * If possible, return a pointer to a mapping of file fd starting at offset
- * iOff. The mapping must be valid for at least nAmt bytes.
- *
- * If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
- * Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
- * Finally, if an error does occur, return an SQLite error code. The final
- * value of *pp is undefined in this case.
- *
- * If this function does return a pointer, the caller must eventually
- * release the reference by calling unixUnfetch().
- */
-static int
-unixFetch(sqlite3_file * fd MAYBE_UNUSED,
- i64 iOff MAYBE_UNUSED,
- int nAmt MAYBE_UNUSED, void **pp)
-{
-#if SQLITE_MAX_MMAP_SIZE>0
- unixFile *pFd = (unixFile *) fd; /* The underlying database file */
-#endif
- *pp = 0;
-
-#if SQLITE_MAX_MMAP_SIZE>0
- if (pFd->mmapSizeMax > 0) {
- if (pFd->pMapRegion == 0) {
- int rc = unixMapfile(pFd, -1);
- if (rc != SQLITE_OK)
- return rc;
- }
- if (pFd->mmapSize >= iOff + nAmt) {
- *pp = &((u8 *) pFd->pMapRegion)[iOff];
- pFd->nFetchOut++;
- }
- }
-#endif
- return SQLITE_OK;
-}
-
-/*
- * If the third argument is non-NULL, then this function releases a
- * reference obtained by an earlier call to unixFetch(). The second
- * argument passed to this function must be the same as the corresponding
- * argument that was passed to the unixFetch() invocation.
- *
- * Or, if the third argument is NULL, then this function is being called
- * to inform the VFS layer that, according to POSIX, any existing mapping
- * may now be invalid and should be unmapped.
- */
-static int
-unixUnfetch(sqlite3_file * fd, i64 iOff, void *p)
-{
-#if SQLITE_MAX_MMAP_SIZE>0
- unixFile *pFd = (unixFile *) fd; /* The underlying database file */
- UNUSED_PARAMETER(iOff);
-
- /* If p==0 (unmap the entire file) then there must be no outstanding
- * xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
- * then there must be at least one outstanding.
- */
- assert((p == 0) == (pFd->nFetchOut == 0));
-
- /* If p!=0, it must match the iOff value. */
- assert(p == 0 || p == &((u8 *) pFd->pMapRegion)[iOff]);
-
- if (p) {
- pFd->nFetchOut--;
- } else {
- unixUnmapfile(pFd);
- }
-
- assert(pFd->nFetchOut >= 0);
-#else
- UNUSED_PARAMETER(fd);
- UNUSED_PARAMETER(p);
- UNUSED_PARAMETER(iOff);
-#endif
- return SQLITE_OK;
-}
-
-/*
- * Here ends the implementation of all sqlite3_file methods.
- *
- ********************* End sqlite3_file Methods *******************************
- *****************************************************************************/
-
-/*
- * 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.
- *
- * For finder-function F, two objects are created:
- *
- * (1) The real finder-function named "FImpt()".
- *
- * (2) A constant pointer to this function named just "F".
- *
- *
- * A pointer to the F pointer is used as the pAppData value for VFS
- * objects. We have to do this instead of letting pAppData point
- * directly at the finder-function since C90 rules prevent a void*
- * from be cast into a function pointer.
- *
- *
- * Each instance of this macro generates two objects:
- *
- * * A constant sqlite3_io_methods object call METHOD that has locking
- * methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
- *
- * * An I/O method finder function called FINDER that returns a pointer
- * to the METHOD object in the previous bullet.
- */
-#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \
-static const sqlite3_io_methods METHOD = { \
- VERSION, /* iVersion */ \
- CLOSE, /* xClose */ \
- unixRead, /* xRead */ \
- unixWrite, /* xWrite */ \
- unixTruncate, /* xTruncate */ \
- unixSync, /* xSync */ \
- unixFileSize, /* xFileSize */ \
- LOCK, /* xLock */ \
- UNLOCK, /* xUnlock */ \
- CKLOCK, /* xCheckReservedLock */ \
- unixFileControl, /* xFileControl */ \
- unixSectorSize, /* xSectorSize */ \
- unixDeviceCharacteristics, /* xDeviceCapabilities */ \
- SHMMAP, /* xShmMap */ \
- unixShmLock, /* xShmLock */ \
- unixShmBarrier, /* xShmBarrier */ \
- unixShmUnmap, /* xShmUnmap */ \
- unixFetch, /* xFetch */ \
- unixUnfetch, /* xUnfetch */ \
-}; \
-static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
- UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
- return &METHOD; \
-} \
-static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
- = FINDER##Impl;
-
-/*
- * Here are all of the sqlite3_io_methods objects for each of the
- * locking strategies. Functions that return pointers to these methods
- * are also created.
- */
-IOMETHODS(posixIoFinder, /* Finder function name */
- posixIoMethods, /* sqlite3_io_methods object name */
- 3, /* shared memory and mmap are enabled */
- unixClose, /* xClose method */
- unixLock, /* xLock method */
- unixUnlock, /* xUnlock method */
- unixCheckReservedLock, /* xCheckReservedLock method */
- unixShmMap /* xShmMap method */
- )
- IOMETHODS(nolockIoFinder, /* Finder function name */
- nolockIoMethods, /* sqlite3_io_methods object name */
- 3, /* shared memory is disabled */
- nolockClose, /* xClose method */
- nolockLock, /* xLock method */
- nolockUnlock, /* xUnlock method */
- nolockCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
- IOMETHODS(dotlockIoFinder, /* Finder function name */
- dotlockIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- dotlockClose, /* xClose method */
- dotlockLock, /* xLock method */
- dotlockUnlock, /* xUnlock method */
- dotlockCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#if SQLITE_ENABLE_LOCKING_STYLE
- IOMETHODS(flockIoFinder, /* Finder function name */
- flockIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- flockClose, /* xClose method */
- flockLock, /* xLock method */
- flockUnlock, /* xUnlock method */
- flockCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- IOMETHODS(afpIoFinder, /* Finder function name */
- afpIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- afpClose, /* xClose method */
- afpLock, /* xLock method */
- afpUnlock, /* xUnlock method */
- afpCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-/*
- * The proxy locking method is a "super-method" in the sense that it
- * opens secondary file descriptors for the conch and lock files and
- * it uses proxy, dot-file, AFP, and flock() locking methods on those
- * secondary files. For this reason, the division that implements
- * proxy locking is located much further down in the file. But we need
- * to go ahead and define the sqlite3_io_methods and finder function
- * for proxy locking here. So we forward declare the I/O methods.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-static int
-proxyClose(sqlite3_file *);
-static int
-proxyLock(sqlite3_file *, int);
-static int
-proxyUnlock(sqlite3_file *, int);
-static int
-proxyCheckReservedLock(sqlite3_file *, int *);
-IOMETHODS(proxyIoFinder, /* Finder function name */
- proxyIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- proxyClose, /* xClose method */
- proxyLock, /* xLock method */
- proxyUnlock, /* xUnlock method */
- proxyCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- IOMETHODS(nfsIoFinder, /* Finder function name */
- nfsIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- unixClose, /* xClose method */
- unixLock, /* xLock method */
- nfsUnlock, /* xUnlock method */
- unixCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
- * 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.
- */
-static const sqlite3_io_methods *
-autolockIoFinderImpl(const char *filePath, /* name of the database file */
- unixFile * pNew /* open file object for the database file */
- )
-{
- static const struct Mapping {
- const char *zFilesystem; /* Filesystem type name */
- const sqlite3_io_methods *pMethods; /* Appropriate locking method */
- } aMap[] = {
- {
- "hfs", &posixIoMethods}, {
- "ufs", &posixIoMethods}, {
- "afpfs", &afpIoMethods}, {
- "smbfs", &afpIoMethods}, {
- "webdav", &nolockIoMethods}, {
- 0, 0}
- };
- int i;
- struct statfs fsInfo;
- 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) {
- if (fsInfo.f_flags & MNT_RDONLY) {
- return &nolockIoMethods;
- }
- for (i = 0; aMap[i].zFilesystem; i++) {
- if (strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem) ==
- 0) {
- return aMap[i].pMethods;
- }
- }
- }
-
- /* Default case. Handles, amongst others, "nfs".
- * Test byte-range lock using fcntl(). If the call succeeds,
- * assume that the file-system supports POSIX style locks.
- */
- lockInfo.l_len = 1;
- lockInfo.l_start = 0;
- lockInfo.l_whence = SEEK_SET;
- lockInfo.l_type = F_RDLCK;
- if (osFcntl(pNew->h, F_GETLK, &lockInfo) != -1) {
- if (strcmp(fsInfo.f_fstypename, "nfs") == 0) {
- return &nfsIoMethods;
- } else {
- return &posixIoMethods;
- }
- } else {
- return &dotlockIoMethods;
- }
-}
-
-static const sqlite3_io_methods
- * (*const autolockIoFinder)(const char *, unixFile *) =
- autolockIoFinderImpl;
-
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
-
-/*
- * An abstract type for a pointer to an IO method finder function:
- */
-typedef const sqlite3_io_methods *(*finder_type) (const char *, unixFile *);
-
-/****************************************************************************
- *************************** sqlite3_vfs methods ****************************
- *
- * This division contains the implementation of methods on the
- * sqlite3_vfs object.
- */
-
-/*
- * Initialize the contents of the unixFile structure pointed to by pId.
- */
-static int
-fillInUnixFile(sqlite3_vfs * pVfs, /* Pointer to vfs object */
- int h, /* Open file descriptor of file being opened */
- sqlite3_file * pId, /* Write to the unixFile structure here */
- const char *zFilename, /* Name of the file being opened */
- int ctrlFlags /* Zero or more UNIXFILE_* values */
- )
-{
- const sqlite3_io_methods *pLockingStyle;
- unixFile *pNew = (unixFile *) pId;
- int rc = SQLITE_OK;
-
- assert(pNew->pInode == NULL);
-
- /* Usually the path zFilename should not be a relative pathname. The
- * exception is when opening the proxy "conch" file in builds that
- * include the special Apple locking styles.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- assert(zFilename == 0 || zFilename[0] == '/'
- || pVfs->pAppData == (void *)&autolockIoFinder);
-#else
- assert(zFilename == 0 || zFilename[0] == '/');
-#endif
-
- /* No locking occurs in temporary files */
- assert(zFilename != 0 || (ctrlFlags & UNIXFILE_NOLOCK) != 0);
-
- pNew->h = h;
- pNew->pVfs = pVfs;
- pNew->zPath = zFilename;
- pNew->ctrlFlags = (u8) ctrlFlags;
-#if SQLITE_MAX_MMAP_SIZE>0
- pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
-#endif
- if (strcmp(pVfs->zName, "unix-excl") == 0) {
- pNew->ctrlFlags |= UNIXFILE_EXCL;
- }
- if (ctrlFlags & UNIXFILE_NOLOCK) {
- pLockingStyle = &nolockIoMethods;
- } else {
- pLockingStyle =
- (**(finder_type *) pVfs->pAppData) (zFilename, pNew);
-#if SQLITE_ENABLE_LOCKING_STYLE
- /* Cache zFilename in the locking context (AFP and dotlock override) for
- * proxyLock activation is possible (remote proxy is based on db name)
- * zFilename remains valid until file is closed, to support
- */
- pNew->lockingContext = (void *)zFilename;
-#endif
- }
-
- if (pLockingStyle == &posixIoMethods
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- || pLockingStyle == &nfsIoMethods
-#endif
- ) {
- rc = findInodeInfo(pNew, &pNew->pInode);
- if (rc != SQLITE_OK) {
- /* If an error occurred in findInodeInfo(), close the file descriptor
- * immediately. findInodeInfo() may fail
- * in two scenarios:
- *
- * (a) A call to fstat() failed.
- * (b) A malloc failed.
- *
- * Scenario (b) may only occur if the process is holding no other
- * file descriptors open on the same file. If there were other file
- * descriptors on this file, then no malloc would be required by
- * findInodeInfo(). If this is the case, it is quite safe to close
- * handle h - as it is guaranteed that no posix locks will be released
- * by doing so.
- *
- * If scenario (a) caused the error then things are not so safe. The
- * implicit assumption here is that if fstat() fails, things are in
- * such bad shape that dropping a lock or two doesn't matter much.
- */
- robust_close(pNew, h, __LINE__);
- h = -1;
- }
- }
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- else if (pLockingStyle == &afpIoMethods) {
- /* AFP locking uses the file path so it needs to be included in
- * the afpLockingContext.
- */
- afpLockingContext *pCtx;
- pNew->lockingContext = pCtx = sqlite3_malloc64(sizeof(*pCtx));
- if (pCtx == 0) {
- rc = SQLITE_NOMEM_BKPT;
- } else {
- /* NB: zFilename exists and remains valid until the file is closed
- * according to requirement F11141. So we do not need to make a
- * copy of the filename.
- */
- pCtx->dbPath = zFilename;
- pCtx->reserved = 0;
- srandomdev();
- rc = findInodeInfo(pNew, &pNew->pInode);
- if (rc != SQLITE_OK) {
- sqlite3_free(pNew->lockingContext);
- robust_close(pNew, h, __LINE__);
- h = -1;
- }
- }
- }
-#endif
-
- else if (pLockingStyle == &dotlockIoMethods) {
- /* Dotfile locking uses the file path so it needs to be included in
- * the dotlockLockingContext
- */
- char *zLockFile;
- int nFilename;
- assert(zFilename != 0);
- nFilename = (int)strlen(zFilename) + 6;
- zLockFile = (char *)sqlite3_malloc64(nFilename);
- if (zLockFile == 0) {
- rc = SQLITE_NOMEM_BKPT;
- } else {
- sqlite3_snprintf(nFilename, zLockFile,
- "%s" DOTLOCK_SUFFIX, zFilename);
- }
- pNew->lockingContext = zLockFile;
- }
- storeLastErrno(pNew, 0);
- if (rc != SQLITE_OK) {
- if (h >= 0)
- robust_close(pNew, h, __LINE__);
- } else {
- pNew->pMethod = pLockingStyle;
- OpenCounter(+1);
- verifyDbFile(pNew);
- }
- return rc;
-}
-
-/*
- * Return the name of a directory in which to put temporary files.
- * If no suitable temporary file directory can be found, return NULL.
- */
-static const char *
-unixTempFileDir(void)
-{
- static const char *azDirs[] = {
- 0,
- 0,
- "/var/tmp",
- "/usr/tmp",
- "/tmp",
- "."
- };
- unsigned int i = 0;
- struct stat buf;
- const char *zDir = sqlite3_temp_directory;
-
- if (!azDirs[0])
- azDirs[0] = getenv("SQLITE_TMPDIR");
- if (!azDirs[1])
- azDirs[1] = getenv("TMPDIR");
- while (1) {
- if (zDir != 0 && osStat(zDir, &buf) == 0 && S_ISDIR(buf.st_mode)
- && osAccess(zDir, 03) == 0) {
- return zDir;
- }
- if (i >= sizeof(azDirs) / sizeof(azDirs[0]))
- break;
- zDir = azDirs[i++];
- }
- return 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(int nBuf, char *zBuf)
-{
- const char *zDir;
- int iLimit = 0;
-
- /* 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.
- */
- zBuf[0] = 0;
- SimulateIOError(return SQLITE_IOERR);
-
- zDir = unixTempFileDir();
- if (zDir == 0)
- return SQLITE_IOERR_GETTEMPPATH;
- do {
- u64 r;
- sqlite3_randomness(sizeof(r), &r);
- assert(nBuf > 2);
- zBuf[nBuf - 2] = 0;
- sqlite3_snprintf(nBuf, zBuf,
- "%s/" SQLITE_TEMP_FILE_PREFIX "%llx%c", zDir,
- r, 0);
- if (zBuf[nBuf - 2] != 0 || (iLimit++) > 10)
- return SQLITE_ERROR;
- } while (osAccess(zBuf, 0) == 0);
- return SQLITE_OK;
-}
-
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
-/*
- * Routine to transform a unixFile into a proxy-locking unixFile.
- * Implementation in the proxy-lock division, but used by unixOpen()
- * if SQLITE_PREFER_PROXY_LOCKING is defined.
- */
-static int proxyTransformUnixFile(unixFile *, const char *);
-#endif
-
-/*
- * Search for an unused file descriptor that was opened on the database
- * file (not a journal or master-journal file) identified by pathname
- * zPath with SQLITE_OPEN_XXX flags matching those passed as the second
- * argument to this function.
- *
- * Such a file descriptor may exist if a database connection was closed
- * but the associated file descriptor could not be closed because some
- * other file descriptor open on the same file is holding a file-lock.
- * Refer to comments in the unixClose() function and the lengthy comment
- * describing "Posix Advisory Locking" at the start of this file for
- * further details. Also, ticket #4018.
- *
- * If a suitable file descriptor is found, then it is returned. If no
- * such file descriptor is located, -1 is returned.
- */
-static UnixUnusedFd *
-findReusableFd(const char *zPath, int flags)
-{
- UnixUnusedFd *pUnused = 0;
-
- struct stat sStat; /* Results of stat() call */
-
- /* A stat() call may fail for various reasons. If this happens, it is
- * almost certain that an open() call on the same path will also fail.
- * For this reason, if an error occurs in the stat() call here, it is
- * ignored and -1 is returned. The caller will try to open a new file
- * descriptor on the same path, fail, and return an error to SQLite.
- *
- * Even if a subsequent open() call does succeed, the consequences of
- * not searching for a reusable file descriptor are not dire.
- */
- if (0 == osStat(zPath, &sStat)) {
- unixInodeInfo *pInode;
-
- pInode = inodeList;
- while (pInode && (pInode->fileId.dev != sStat.st_dev
- || pInode->fileId.ino !=
- (u64) sStat.st_ino)) {
- pInode = pInode->pNext;
- }
- if (pInode) {
- UnixUnusedFd **pp;
- for (pp = &pInode->pUnused;
- *pp && (*pp)->flags != flags;
- pp = &((*pp)->pNext)) ;
- pUnused = *pp;
- if (pUnused) {
- *pp = pUnused->pNext;
- }
- }
- }
- return pUnused;
-}
-
-/*
- * Find the mode, uid and gid of file zFile.
- */
-static int
-getFileMode(const char *zFile, /* File name */
- mode_t * pMode, /* OUT: Permissions of zFile */
- uid_t * pUid, /* OUT: uid of zFile. */
- gid_t * pGid /* OUT: gid of zFile. */
- )
-{
- struct stat sStat; /* Output of stat() on database file */
- int rc = SQLITE_OK;
- if (0 == osStat(zFile, &sStat)) {
- *pMode = sStat.st_mode & 0777;
- *pUid = sStat.st_uid;
- *pGid = sStat.st_gid;
- } else {
- rc = SQLITE_IOERR_FSTAT;
- }
- return rc;
-}
-
-/*
- * This function is called by unixOpen() to determine the unix permissions
- * to create new files with. If no error occurs, then SQLITE_OK is returned
- * and a value suitable for passing as the third argument to open(2) is
- * written to *pMode. If an IO error occurs, an SQLite error code is
- * returned and the value of *pMode is not modified.
- *
- * In most cases, this routine sets *pMode to 0, which will become
- * an indication to robust_open() to create the file using
- * SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
- * But if the file being opened is a regular journal file, then
- * this function queries the file-system for the permissions on the
- * corresponding database file and sets *pMode to this value. Whenever
- * possible, journal files are created using the same permissions
- * as the associated database file.
- *
- * If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
- * original filename is unavailable. But 8_3_NAMES is only used for
- * FAT filesystems and permissions do not matter there, so just use
- * the default permissions.
- */
-static int
-findCreateFileMode(const char *zPath, /* Path of file (possibly) being created */
- int flags, /* Flags passed as 4th argument to xOpen() */
- mode_t * pMode, /* OUT: Permissions to open file with */
- uid_t * pUid, /* OUT: uid to set on the file */
- gid_t * pGid /* OUT: gid to set on the file */
- )
-{
- int rc = SQLITE_OK; /* Return Code */
- *pMode = 0;
- *pUid = 0;
- *pGid = 0;
- if (flags & SQLITE_OPEN_DELETEONCLOSE) {
- *pMode = 0600;
- } else if (flags & SQLITE_OPEN_URI) {
- /* If this is a main database file and the file was opened using a URI
- * filename, check for the "modeof" parameter. If present, interpret
- * its value as a filename and try to copy the mode, uid and gid from
- * that file.
- */
- const char *z = sqlite3_uri_parameter(zPath, "modeof");
- if (z) {
- rc = getFileMode(z, pMode, pUid, pGid);
- }
- }
- return rc;
-}
-
-/*
- * 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, /* 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 */
- )
-{
- unixFile *p = (unixFile *) pFile;
- int fd = -1; /* File descriptor returned by 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; /* Function Return Code */
- int ctrlFlags = 0; /* UNIXFILE_* flags */
-
- 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 SQLITE_ENABLE_LOCKING_STYLE
- int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
-#endif
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
- struct statfs fsInfo;
-#endif
-
- /* 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 syncDir = isCreate;
-
- /* If argument zPath is a NULL pointer, this function is required to open
- * a temporary file. Use this buffer to store the file name in.
- */
- char zTmpname[MAX_PATHNAME + 2];
- const char *zName = zPath;
-
- /* 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);
-
- /* Detect a pid change and reset the PRNG. There is a race condition
- * here such that two or more threads all trying to open databases at
- * the same instant might all reset the PRNG. But multiple resets
- * are harmless.
- */
- if (randomnessPid != getpid()) {
- randomnessPid = getpid();
- sqlite3_randomness(0, 0);
- }
-
- memset(p, 0, sizeof(unixFile));
-
- if (eType == SQLITE_OPEN_MAIN_DB) {
- UnixUnusedFd *pUnused;
- pUnused = findReusableFd(zName, flags);
- if (pUnused) {
- fd = pUnused->fd;
- } else {
- pUnused = sqlite3_malloc64(sizeof(*pUnused));
- if (!pUnused) {
- return SQLITE_NOMEM_BKPT;
- }
- }
- p->pUnused = pUnused;
-
- /* Database filenames are double-zero terminated if they are not
- * URIs with parameters. Hence, they can always be passed into
- * sqlite3_uri_parameter().
- */
- assert((flags & SQLITE_OPEN_URI)
- || zName[strlen(zName) + 1] == 0);
-
- } else if (!zName) {
- /* If zName is NULL, the upper layer is requesting a temp file. */
- assert(isDelete);
- rc = unixGetTempname(pVfs->mxPathname, zTmpname);
- if (rc != SQLITE_OK) {
- return rc;
- }
- zName = zTmpname;
-
- /* Generated temporary filenames are always double-zero terminated
- * for use by sqlite3_uri_parameter().
- */
- assert(zName[strlen(zName) + 1] == 0);
- }
-
- /* Determine the value of the flags parameter passed to POSIX function
- * open(). These must be calculated even if open() is not called, as
- * they may be stored as part of the file handle and used by the
- * 'conch file' locking functions later on.
- */
- if (isReadonly)
- openFlags |= O_RDONLY;
- if (isReadWrite)
- openFlags |= O_RDWR;
- if (isCreate)
- openFlags |= O_CREAT;
- if (isExclusive)
- openFlags |= (O_EXCL | O_NOFOLLOW);
- openFlags |= (O_LARGEFILE | O_BINARY);
-
- if (fd < 0) {
- mode_t openMode; /* Permissions to create file with */
- uid_t uid; /* Userid for the file */
- gid_t gid; /* Groupid for the file */
- rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
- if (rc != SQLITE_OK) {
- assert(!p->pUnused);
- return rc;
- }
- fd = robust_open(zName, openFlags, openMode);
- assert(!isExclusive || (openFlags & O_CREAT) != 0);
- if (fd < 0 && errno != EISDIR && isReadWrite) {
- /* Failed to open the file for read/write access. Try read-only. */
- flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
- openFlags &= ~(O_RDWR | O_CREAT);
- flags |= SQLITE_OPEN_READONLY;
- openFlags |= O_RDONLY;
- isReadonly = 1;
- fd = robust_open(zName, openFlags, openMode);
- }
- if (fd < 0) {
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
- goto open_finished;
- }
-
- }
- assert(fd >= 0);
- if (pOutFlags) {
- *pOutFlags = flags;
- }
-
- if (p->pUnused) {
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
- }
-
- if (isDelete) {
-
-#if defined(SQLITE_UNLINK_AFTER_CLOSE)
- zPath = sqlite3_mprintf("%s", zName);
- if (zPath == 0) {
- robust_close(p, fd, __LINE__);
- return SQLITE_NOMEM_BKPT;
- }
-#else
- osUnlink(zName);
-#endif
- }
-#if SQLITE_ENABLE_LOCKING_STYLE
- else {
- p->openFlags = openFlags;
- }
-#endif
-
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
- if (fstatfs(fd, &fsInfo) == -1) {
- storeLastErrno(p, errno);
- robust_close(p, fd, __LINE__);
- return SQLITE_IOERR_ACCESS;
- }
- if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
- ((unixFile *) pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
- }
- if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
- ((unixFile *) pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
- }
-#endif
-
- /* Set up appropriate ctrlFlags */
- if (isDelete)
- ctrlFlags |= UNIXFILE_DELETE;
- if (isReadonly)
- ctrlFlags |= UNIXFILE_RDONLY;
- noLock = eType != SQLITE_OPEN_MAIN_DB;
- if (noLock)
- ctrlFlags |= UNIXFILE_NOLOCK;
- if (syncDir)
- ctrlFlags |= UNIXFILE_DIRSYNC;
- if (flags & SQLITE_OPEN_URI)
- ctrlFlags |= UNIXFILE_URI;
-
-#if SQLITE_ENABLE_LOCKING_STYLE
-#if SQLITE_PREFER_PROXY_LOCKING
- isAutoProxy = 1;
-#endif
- if (isAutoProxy && (zPath != NULL) && (!noLock) && pVfs->xOpen) {
- char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
- int useProxy = 0;
-
- /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
- * never use proxy, NULL means use proxy for non-local files only.
- */
- if (envforce != NULL) {
- useProxy = atoi(envforce) > 0;
- } else {
- useProxy = !(fsInfo.f_flags & MNT_LOCAL);
- }
- if (useProxy) {
- rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
- if (rc == SQLITE_OK) {
- rc = proxyTransformUnixFile((unixFile *) pFile,
- ":auto:");
- if (rc != SQLITE_OK) {
- /* Use unixClose to clean up the resources added in fillInUnixFile
- * and clear all the structure's references. Specifically,
- * pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
- */
- unixClose(pFile);
- return rc;
- }
- }
- goto open_finished;
- }
- }
-#endif
-
- rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
-
- open_finished:
- if (rc != SQLITE_OK) {
- sqlite3_free(p->pUnused);
- }
- return rc;
-}
-
-/*
- * Delete the file at zPath. If the dirSync argument is true, fsync()
- * the directory after deleting the file.
- */
-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);
- if (osUnlink(zPath) == (-1)) {
- if (errno == ENOENT) {
- rc = SQLITE_IOERR_DELETE_NOENT;
- } else {
- rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
- }
- return rc;
- }
-#ifndef SQLITE_DISABLE_DIRSYNC
- if ((dirSync & 1) != 0) {
- int fd;
- rc = osOpenDirectory(zPath, &fd);
- if (rc == SQLITE_OK) {
- if (full_fsync(fd, 0, 0)) {
- rc = unixLogError(SQLITE_IOERR_DIR_FSYNC,
- "fsync", zPath);
- }
- robust_close(0, fd, __LINE__);
- } else {
- assert(rc == SQLITE_CANTOPEN);
- rc = SQLITE_OK;
- }
- }
-#endif
- return rc;
-}
-
-/*
- * Test the existence 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 * 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 */
- )
-{
- UNUSED_PARAMETER(NotUsed);
- SimulateIOError(return SQLITE_IOERR_ACCESS;
- );
- assert(pResOut != 0);
-
- /* The spec says there are three possible values for flags. But only
- * two of them are actually used
- */
- assert(flags == SQLITE_ACCESS_EXISTS
- || flags == SQLITE_ACCESS_READWRITE);
-
- if (flags == SQLITE_ACCESS_EXISTS) {
- struct stat buf;
- *pResOut = (0 == osStat(zPath, &buf) && buf.st_size > 0);
- } else {
- *pResOut = osAccess(zPath, W_OK | R_OK) == 0;
- }
- return SQLITE_OK;
-}
-
-/*
- *
- */
-static int
-mkFullPathname(const char *zPath, /* Input path */
- char *zOut, /* Output buffer */
- int nOut /* Allocated size of buffer zOut */
- )
-{
- int nPath = sqlite3Strlen30(zPath);
- int iOff = 0;
- if (zPath[0] != '/') {
- if (osGetcwd(zOut, nOut - 2) == 0) {
- return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd",
- zPath);
- }
- iOff = sqlite3Strlen30(zOut);
- zOut[iOff++] = '/';
- }
- if ((iOff + nPath + 1) > nOut) {
- /* SQLite assumes that xFullPathname() nul-terminates the output buffer
- * even if it returns an error.
- */
- zOut[iOff] = '\0';
- return SQLITE_CANTOPEN_BKPT;
- }
- sqlite3_snprintf(nOut - iOff, &zOut[iOff], "%s", zPath);
- 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 */
- )
-{
- (void)pVfs;
-#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
- return mkFullPathname(zPath, zOut, nOut);
-#else
- int rc = SQLITE_OK;
- int nByte;
- int nLink = 1; /* Number of symbolic links followed so far */
- const char *zIn = zPath; /* Input path for each iteration of loop */
- char *zDel = 0;
-
- assert(pVfs->mxPathname == MAX_PATHNAME);
- UNUSED_PARAMETER(pVfs);
-
- /* 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 directory has been unlinked.
- */
- SimulateIOError(return SQLITE_ERROR);
-
- do {
-
- /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
- * link, or false otherwise.
- */
- int bLink = 0;
- struct stat buf;
- if (osLstat(zIn, &buf) != 0) {
- if (errno != ENOENT) {
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat",
- zIn);
- }
- } else {
- bLink = S_ISLNK(buf.st_mode);
- }
-
- if (bLink) {
- if (zDel == 0) {
- zDel = sqlite3_malloc(nOut);
- if (zDel == 0)
- rc = SQLITE_NOMEM_BKPT;
- } else if (++nLink > SQLITE_MAX_SYMLINKS) {
- rc = SQLITE_CANTOPEN_BKPT;
- }
-
- if (rc == SQLITE_OK) {
- nByte = osReadlink(zIn, zDel, nOut - 1);
- if (nByte < 0) {
- rc = unixLogError(SQLITE_CANTOPEN_BKPT,
- "readlink", zIn);
- } else {
- if (zDel[0] != '/') {
- int n;
- for (n = sqlite3Strlen30(zIn);
- n > 0 && zIn[n - 1] != '/';
- n--) ;
- if (nByte + n + 1 > nOut) {
- rc = SQLITE_CANTOPEN_BKPT;
- } else {
- memmove(&zDel[n], zDel,
- nByte + 1);
- memcpy(zDel, zIn, n);
- nByte += n;
- }
- }
- zDel[nByte] = '\0';
- }
- }
-
- zIn = zDel;
- }
-
- assert(rc != SQLITE_OK || zIn != zOut || zIn[0] == '/');
- if (rc == SQLITE_OK && zIn != zOut) {
- rc = mkFullPathname(zIn, zOut, nOut);
- }
- if (bLink == 0)
- break;
- zIn = zOut;
- } while (rc == SQLITE_OK);
-
- sqlite3_free(zDel);
- return rc;
-#endif /* HAVE_READLINK && HAVE_LSTAT */
-}
-
-#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 * NotUsed, const char *zFilename)
-{
- UNUSED_PARAMETER(NotUsed);
- 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 * NotUsed, int nBuf, char *zBufOut)
-{
- const char *zErr;
- UNUSED_PARAMETER(NotUsed);
- zErr = dlerror();
- if (zErr) {
- sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
- }
-}
-
-static
- void (*unixDlSym(sqlite3_vfs * NotUsed, void *p, const char *zSym)) (void) {
- /*
- * GCC with -pedantic-errors says that C90 does not allow a void* to be
- * cast into a pointer to a function. And yet the library dlsym() routine
- * returns a void* which is really a pointer to a function. So how do we
- * use dlsym() with -pedantic-errors?
- *
- * Variable x below is defined to be a pointer to a function taking
- * parameters void* and const char* and returning a pointer to a function.
- * We initialize x by assigning it a pointer to the dlsym() function.
- * (That assignment requires a cast.) Then we call the function that
- * x points to.
- *
- * This work-around is unlikely to work correctly on any system where
- * you really cannot cast a function pointer into void*. But then, on the
- * other hand, dlsym() will not work on such a system either, so we have
- * not really lost anything.
- */
- void (*(*x) (void *, const char *)) (void);
- UNUSED_PARAMETER(NotUsed);
- x = (void (*(*)(void *, const char *))(void))dlsym;
- return (*x) (p, zSym);
-}
-
-static void
-unixDlClose(sqlite3_vfs * NotUsed, void *pHandle)
-{
- UNUSED_PARAMETER(NotUsed);
- dlclose(pHandle);
-}
-#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
-#define unixDlOpen 0
-#define unixDlError 0
-#define unixDlSym 0
-#define unixDlClose 0
-#endif
-
-/*
- * Write nBuf bytes of random data to the supplied buffer zBuf.
- */
-static int
-unixRandomness(sqlite3_vfs * NotUsed, int nBuf, char *zBuf)
-{
- UNUSED_PARAMETER(NotUsed);
- assert((size_t) 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
- * uninitialized space in zBuf - but valgrind errors tend to worry
- * some users. Rather than argue, it seems easier just to initialize
- * the whole array and silence valgrind, even if that means less randomness
- * in the random seed.
- *
- * When testing, initializing zBuf[] to zero is all we do. That means
- * that we always use the same random number sequence. This makes the
- * tests repeatable.
- */
- memset(zBuf, 0, nBuf);
- randomnessPid = getpid();
-#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
- {
- int fd, got;
- fd = robust_open("/dev/urandom", O_RDONLY, 0);
- if (fd < 0) {
- time_t t;
- time(&t);
- memcpy(zBuf, &t, sizeof(t));
- memcpy(&zBuf[sizeof(t)], &randomnessPid,
- sizeof(randomnessPid));
- assert(sizeof(t) + sizeof(randomnessPid) <=
- (size_t) nBuf);
- nBuf = sizeof(t) + sizeof(randomnessPid);
- } else {
- do {
- got = osRead(fd, zBuf, nBuf);
- } while (got < 0 && errno == EINTR);
- robust_close(0, fd, __LINE__);
- }
- }
-#endif
- return nBuf;
-}
-
-/*
- * Sleep for a little while. Return the amount of time slept.
- * 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.
- */
-static int
-unixSleep(sqlite3_vfs * NotUsed, int microseconds)
-{
-#if defined(HAVE_USLEEP) && HAVE_USLEEP
- usleep(microseconds);
- UNUSED_PARAMETER(NotUsed);
- return microseconds;
-#else
- int seconds = (microseconds + 999999) / 1000000;
- sleep(seconds);
- UNUSED_PARAMETER(NotUsed);
- return seconds * 1000000;
-#endif
-}
-
-/*
- * 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; /* Fake system time in seconds since 1970. */
-#endif
-
-/*
- * Find the current time (in Universal Coordinated Time). Write into *piNow
- * the current time and date as a Julian Day number times 86_400_000. In
- * other words, write into *piNow the number of milliseconds since the Julian
- * epoch of noon in Greenwich on November 24, 4714 B.C according to the
- * proleptic Gregorian calendar.
- *
- * On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
- * cannot be found.
- */
-static int
-unixCurrentTimeInt64(sqlite3_vfs * NotUsed, sqlite3_int64 * piNow)
-{
- static const sqlite3_int64 unixEpoch =
- 24405875 * (sqlite3_int64) 8640000;
- int rc = SQLITE_OK;
-#if defined(NO_GETTOD)
- time_t t;
- time(&t);
- *piNow = ((sqlite3_int64) t) * 1000 + unixEpoch;
-#else
- struct timeval sNow;
- (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
- *piNow =
- unixEpoch + 1000 * (sqlite3_int64) sNow.tv_sec +
- sNow.tv_usec / 1000;
-#endif
+ /* If p==0 (unmap the entire file) then there must be no outstanding
+ * xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
+ * then there must be at least one outstanding.
+ */
+ assert((p == 0) == (pFd->nFetchOut == 0));
-#ifdef SQLITE_TEST
- if (sqlite3_current_time) {
- *piNow =
- 1000 * (sqlite3_int64) sqlite3_current_time + unixEpoch;
+ /* If p!=0, it must match the iOff value. */
+ assert(p == 0 || p == &((u8 *) pFd->pMapRegion)[iOff]);
+
+ if (p) {
+ pFd->nFetchOut--;
+ } else {
+ unixUnmapfile(pFd);
}
-#endif
- UNUSED_PARAMETER(NotUsed);
- return rc;
-}
-/*
- * The xGetLastError() method is designed to return a better
- * low-level error message when operating-system problems come up
- * during SQLite operation. Only the integer return code is currently
- * used.
- */
-static int
-unixGetLastError(sqlite3_vfs * NotUsed, int NotUsed2, char *NotUsed3)
-{
- UNUSED_PARAMETER(NotUsed);
- UNUSED_PARAMETER(NotUsed2);
- UNUSED_PARAMETER(NotUsed3);
- return errno;
+ assert(pFd->nFetchOut >= 0);
+ return SQLITE_OK;
}
/*
- *********************** End of sqlite3_vfs methods ***************************
+ * Here ends the implementation of all sqlite3_file methods.
+ *
+ ********************* End sqlite3_file Methods *******************************
*****************************************************************************/
-/******************************************************************************
- ************************* Begin Proxy Locking ********************************
- *
- * Proxy locking is a "uber-locking-method" in this sense: It uses the
- * other locking methods on secondary lock files. Proxy locking is a
- * meta-layer over top of the primitive locking implemented above. For
- * this reason, the division that implements of proxy locking is deferred
- * until late in the file (here) after all of the other I/O methods have
- * been defined - so that the primitive locking methods are available
- * as services to help with the implementation of proxy locking.
- *
- ***
- *
- * The default locking schemes in SQLite use byte-range locks on the
- * database file to coordinate safe, concurrent access by multiple readers
- * and writers [http://sqlite.org/lockingv3.html]. The five file locking
- * states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented
- * as POSIX read & write locks over fixed set of locations (via fsctl),
- * on AFP and SMB only exclusive byte-range locks are available via fsctl
- * with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states.
- * To simulate a F_RDLCK on the shared range, on AFP a randomly selected
- * address in the shared range is taken for a SHARED lock, the entire
- * shared range is taken for an EXCLUSIVE lock):
- *
- * PENDING_BYTE 0x40000000
- * RESERVED_BYTE 0x40000001
- * SHARED_RANGE 0x40000002 -> 0x40000200
- *
- * This works well on the local file system, but shows a nearly 100x
- * slowdown in read performance on AFP because the AFP client disables
- * the read cache when byte-range locks are present. Enabling the read
- * cache exposes a cache coherency problem that is present on all OS X
- * supported network file systems. NFS and AFP both observe the
- * close-to-open semantics for ensuring cache coherency
- * [http://nfs.sourceforge.net/#faq_a8], which does not effectively
- * address the requirements for concurrent database access by multiple
- * readers and writers
- * [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html].
- *
- * To address the performance and cache coherency issues, proxy file locking
- * changes the way database access is controlled by limiting access to a
- * single host at a time and moving file locks off of the database file
- * and onto a proxy file on the local file system.
- *
- *
- * Using proxy locks
- * -----------------
- *
- * C APIs
- *
- * sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE,
- * <proxy_path> | ":auto:");
- * sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE,
- * &<proxy_path>);
- *
- *
- * SQL pragmas
- *
- * PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto:
- * PRAGMA [database.]lock_proxy_file
- *
- * Specifying ":auto:" means that if there is a conch file with a matching
- * host ID in it, the proxy path in the conch file will be used, otherwise
- * a proxy path based on the user's temp dir
- * (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the
- * actual proxy file name is generated from the name and path of the
- * database file. For example:
- *
- * For database path "/Users/me/foo.db"
- * The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
- *
- * Once a lock proxy is configured for a database connection, it can not
- * be removed, however it may be switched to a different proxy path via
- * the above APIs (assuming the conch file is not being held by another
- * connection or process).
- *
- *
- * How proxy locking works
- * -----------------------
- *
- * Proxy file locking relies primarily on two new supporting files:
- *
- * * conch file to limit access to the database file to a single host
- * at a time
- *
- * * proxy file to act as a proxy for the advisory locks normally
- * taken on the database
- *
- * The conch file - to use a proxy file, sqlite must first "hold the conch"
- * by taking an sqlite-style shared lock on the conch file, reading the
- * contents and comparing the host's unique host ID (see below) and lock
- * proxy path against the values stored in the conch. The conch file is
- * stored in the same directory as the database file and the file name
- * is patterned after the database file name as ".<databasename>-conch".
- * If the conch file does not exist, or its contents do not match the
- * host ID and/or proxy path, then the lock is escalated to an exclusive
- * lock and the conch file contents is updated with the host ID and proxy
- * path and the lock is downgraded to a shared lock again. If the conch
- * is held by another process (with a shared lock), the exclusive lock
- * will fail and SQLITE_BUSY is returned.
- *
- * The proxy file - a single-byte file used for all advisory file locks
- * normally taken on the database file. This allows for safe sharing
- * of the database file for multiple readers and writers on the same
- * host (the conch ensures that they all use the same local lock file).
- *
- * Requesting the lock proxy does not immediately take the conch, it is
- * only taken when the first request to lock database file is made.
- * This matches the semantics of the traditional locking behavior, where
- * opening a connection to a database file does not take a lock on it.
- * The shared lock and an open file descriptor are maintained until
- * the connection to the database is closed.
- *
- * The proxy file and the lock file are never deleted so they only need
- * to be created the first time they are used.
+/*
+ * 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.
*
- * Configuration options
- * ---------------------
+ * 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.
*
- * SQLITE_PREFER_PROXY_LOCKING
+ * For finder-function F, two objects are created:
*
- * Database files accessed on non-local file systems are
- * automatically configured for proxy locking, lock files are
- * named automatically using the same logic as
- * PRAGMA lock_proxy_file=":auto:"
+ * (1) The real finder-function named "FImpt()".
*
- * SQLITE_PROXY_DEBUG
+ * (2) A constant pointer to this function named just "F".
*
- * Enables the logging of error messages during host id file
- * retrieval and creation
*
- * LOCKPROXYDIR
+ * A pointer to the F pointer is used as the pAppData value for VFS
+ * objects. We have to do this instead of letting pAppData point
+ * directly at the finder-function since C90 rules prevent a void*
+ * from be cast into a function pointer.
*
- * Overrides the default directory used for lock proxy files that
- * are named automatically via the ":auto:" setting
*
- * SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
+ * Each instance of this macro generates two objects:
*
- * Permissions to use when creating a directory for storing the
- * lock proxy files, only used when LOCKPROXYDIR is not set.
+ * * A constant sqlite3_io_methods object call METHOD that has locking
+ * methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
*
+ * * An I/O method finder function called FINDER that returns a pointer
+ * to the METHOD object in the previous bullet.
+ */
+#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,SHMMAP) \
+static const sqlite3_io_methods METHOD = { \
+ VERSION, /* iVersion */ \
+ CLOSE, /* xClose */ \
+ unixRead, /* xRead */ \
+ unixWrite, /* xWrite */ \
+ unixTruncate, /* xTruncate */ \
+ unixSync, /* xSync */ \
+ unixFileSize, /* xFileSize */ \
+ LOCK, /* xLock */ \
+ UNLOCK, /* xUnlock */ \
+ unixFileControl, /* xFileControl */ \
+ unixSectorSize, /* xSectorSize */ \
+ unixDeviceCharacteristics, /* xDeviceCapabilities */ \
+ SHMMAP, /* xShmMap */ \
+ unixShmLock, /* xShmLock */ \
+ unixShmBarrier, /* xShmBarrier */ \
+ unixShmUnmap, /* xShmUnmap */ \
+ unixFetch, /* xFetch */ \
+ unixUnfetch, /* xUnfetch */ \
+}; \
+static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
+ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
+ return &METHOD; \
+} \
+static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
+ = FINDER##Impl;
+
+/*
+ * Here are all of the sqlite3_io_methods objects for each of the
+ * locking strategies. Functions that return pointers to these methods
+ * are also created.
+ */
+IOMETHODS(posixIoFinder, /* Finder function name */
+ posixIoMethods, /* sqlite3_io_methods object name */
+ 3, /* shared memory and mmap are enabled */
+ unixClose, /* xClose method */
+ unixLock, /* xLock method */
+ unixUnlock, /* xUnlock method */
+ unixShmMap /* xShmMap method */
+ )
+ IOMETHODS(nolockIoFinder, /* Finder function name */
+ nolockIoMethods, /* sqlite3_io_methods object name */
+ 3, /* shared memory is disabled */
+ nolockClose, /* xClose method */
+ nolockLock, /* xLock method */
+ nolockUnlock, /* xUnlock method */
+ NULL /* xShmMap method */
+ )
+
+/*
+ * An abstract type for a pointer to an IO method finder function:
+ */
+typedef const sqlite3_io_methods *(*finder_type) (const char *, unixFile *);
+
+/****************************************************************************
+ *************************** sqlite3_vfs methods ****************************
*
- * As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
- * setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
- * force proxy locking to be used for every database file opened, and 0
- * will force automatic proxy locking to be disabled for all database
- * files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or
- * sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
+ * This division contains the implementation of methods on the
+ * sqlite3_vfs object.
*/
/*
- * Proxy locking is only available on MacOSX
+ * Initialize the contents of the unixFile structure pointed to by pId.
*/
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+static int
+fillInUnixFile(sqlite3_vfs * pVfs, /* Pointer to vfs object */
+ int h, /* Open file descriptor of file being opened */
+ sqlite3_file * pId, /* Write to the unixFile structure here */
+ const char *zFilename, /* Name of the file being opened */
+ int ctrlFlags /* Zero or more UNIXFILE_* values */
+ )
+{
+ const sqlite3_io_methods *pLockingStyle;
+ unixFile *pNew = (unixFile *) pId;
+ int rc = SQLITE_OK;
+
+ assert(pNew->pInode == NULL);
+
+ /* Usually the path zFilename should not be a relative pathname. The
+ * exception is when opening the proxy "conch" file in builds that
+ * include the special Apple locking styles.
+ */
+ assert(zFilename == 0 || zFilename[0] == '/');
+
+ /* No locking occurs in temporary files */
+ assert(zFilename != 0 || (ctrlFlags & UNIXFILE_NOLOCK) != 0);
+
+ pNew->h = h;
+ pNew->pVfs = pVfs;
+ pNew->zPath = zFilename;
+ pNew->ctrlFlags = (u8) ctrlFlags;
+#if SQLITE_MAX_MMAP_SIZE>0
+ pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
+#endif
+ if (strcmp(pVfs->zName, "unix-excl") == 0) {
+ pNew->ctrlFlags |= UNIXFILE_EXCL;
+ }
+ if (ctrlFlags & UNIXFILE_NOLOCK) {
+ pLockingStyle = &nolockIoMethods;
+ } else {
+ pLockingStyle =
+ (**(finder_type *) pVfs->pAppData) (zFilename, pNew);
+ assert(pLockingStyle == &posixIoMethods);
+ }
+
+ if (pLockingStyle == &posixIoMethods) {
+ rc = findInodeInfo(pNew, &pNew->pInode);
+ if (rc != SQLITE_OK) {
+ /* If an error occurred in findInodeInfo(), close the file descriptor
+ * immediately. findInodeInfo() may fail
+ * in two scenarios:
+ *
+ * (a) A call to fstat() failed.
+ * (b) A malloc failed.
+ *
+ * Scenario (b) may only occur if the process is holding no other
+ * file descriptors open on the same file. If there were other file
+ * descriptors on this file, then no malloc would be required by
+ * findInodeInfo(). If this is the case, it is quite safe to close
+ * handle h - as it is guaranteed that no posix locks will be released
+ * by doing so.
+ *
+ * If scenario (a) caused the error then things are not so safe. The
+ * implicit assumption here is that if fstat() fails, things are in
+ * such bad shape that dropping a lock or two doesn't matter much.
+ */
+ robust_close(pNew, h, __LINE__);
+ h = -1;
+ }
+ }
+ storeLastErrno(pNew, 0);
+ if (rc != SQLITE_OK) {
+ if (h >= 0)
+ robust_close(pNew, h, __LINE__);
+ } else {
+ pNew->pMethod = pLockingStyle;
+ OpenCounter(+1);
+ verifyDbFile(pNew);
+ }
+ return rc;
+}
/*
- * The proxyLockingContext has the path and file structures for the remote
- * and local proxy files in it
+ * Return the name of a directory in which to put temporary files.
+ * If no suitable temporary file directory can be found, return NULL.
*/
-typedef struct proxyLockingContext proxyLockingContext;
-struct proxyLockingContext {
- 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; /* 1 if the conch is held, -1 if lockless */
- int nFails; /* Number of conch taking failures */
- void *oldLockingContext; /* Original lockingcontext to restore on close */
- sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
-};
+static const char *
+unixTempFileDir(void)
+{
+ static const char *azDirs[] = {
+ 0,
+ 0,
+ "/var/tmp",
+ "/usr/tmp",
+ "/tmp",
+ "."
+ };
+ unsigned int i = 0;
+ struct stat buf;
+ const char *zDir = sqlite3_temp_directory;
+
+ if (!azDirs[0])
+ azDirs[0] = getenv("SQLITE_TMPDIR");
+ if (!azDirs[1])
+ azDirs[1] = getenv("TMPDIR");
+ while (1) {
+ if (zDir != 0 && stat(zDir, &buf) == 0 &&
+ S_ISDIR(buf.st_mode) && access(zDir, 03) == 0)
+ return zDir;
+ if (i >= sizeof(azDirs) / sizeof(azDirs[0]))
+ break;
+ zDir = azDirs[i++];
+ }
+ return 0;
+}
/*
- * The proxy lock file path for the database at dbPath is written into lPath,
- * which must point to valid, writable memory large enough for a maxLen length
- * file path.
+ * 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
-proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen)
+unixGetTempname(int nBuf, char *zBuf)
{
- int len;
- int dbLen;
- int i;
-
-#ifdef LOCKPROXYDIR
- len = strlcpy(lPath, LOCKPROXYDIR, maxLen);
-#else
-#ifdef _CS_DARWIN_USER_TEMP_DIR
- {
- if (!confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen)) {
- return SQLITE_IOERR_LOCK;
- }
- len = strlcat(lPath, "sqliteplocks", maxLen);
- }
-#else
- len = strlcpy(lPath, "/tmp/", maxLen);
-#endif
-#endif
+ const char *zDir;
+ int iLimit = 0;
- if (lPath[len - 1] != '/') {
- len = strlcat(lPath, "/", maxLen);
- }
+ /* 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.
+ */
+ zBuf[0] = 0;
+ SimulateIOError(return SQLITE_IOERR);
- /* transform the db path to a unique cache name */
- dbLen = (int)strlen(dbPath);
- for (i = 0; i < dbLen && (i + len + 7) < (int)maxLen; i++) {
- char c = dbPath[i];
- lPath[i + len] = (c == '/') ? '_' : c;
- }
- lPath[i + len] = '\0';
- strlcat(lPath, ":auto:", maxLen);
+ zDir = unixTempFileDir();
+ if (zDir == 0)
+ return SQLITE_IOERR_GETTEMPPATH;
+ do {
+ u64 r;
+ sqlite3_randomness(sizeof(r), &r);
+ assert(nBuf > 2);
+ zBuf[nBuf - 2] = 0;
+ sqlite3_snprintf(nBuf, zBuf,
+ "%s/" SQLITE_TEMP_FILE_PREFIX "%llx%c", zDir,
+ r, 0);
+ if (zBuf[nBuf - 2] != 0 || (iLimit++) > 10)
+ return SQLITE_ERROR;
+ } while (access(zBuf, 0) == 0);
return SQLITE_OK;
}
/*
- ** Creates the lock file and any missing directories in lockPath
+ * Search for an unused file descriptor that was opened on the database
+ * file (not a journal or master-journal file) identified by pathname
+ * zPath with SQLITE_OPEN_XXX flags matching those passed as the second
+ * argument to this function.
+ *
+ * Such a file descriptor may exist if a database connection was closed
+ * but the associated file descriptor could not be closed because some
+ * other file descriptor open on the same file is holding a file-lock.
+ * Refer to comments in the unixClose() function and the lengthy comment
+ * describing "Posix Advisory Locking" at the start of this file for
+ * further details. Also, ticket #4018.
+ *
+ * If a suitable file descriptor is found, then it is returned. If no
+ * such file descriptor is located, -1 is returned.
*/
-static int
-proxyCreateLockPath(const char *lockPath)
+static UnixUnusedFd *
+findReusableFd(const char *zPath, int flags)
{
- int i, len;
- char buf[MAXPATHLEN];
- int start = 0;
-
- assert(lockPath != NULL);
- /* try to create all the intermediate directories */
- len = (int)strlen(lockPath);
- buf[0] = lockPath[0];
- for (i = 1; i < len; i++) {
- if (lockPath[i] == '/' && (i - start > 0)) {
- /* only mkdir if leaf dir != "." or "/" or ".." */
- if (i - start > 2
- || (i - start == 1 && buf[start] != '.'
- && buf[start] != '/')
- || (i - start == 2 && buf[start] != '.'
- && buf[start + 1] != '.')) {
- buf[i] = '\0';
- if (osMkdir
- (buf,
- SQLITE_DEFAULT_PROXYDIR_PERMISSIONS)) {
- int err = errno;
- if (err != EEXIST) {
- return err;
- }
- }
+ UnixUnusedFd *pUnused = 0;
+
+ struct stat sStat; /* Results of stat() call */
+
+ /* A stat() call may fail for various reasons. If this happens, it is
+ * almost certain that an open() call on the same path will also fail.
+ * For this reason, if an error occurs in the stat() call here, it is
+ * ignored and -1 is returned. The caller will try to open a new file
+ * descriptor on the same path, fail, and return an error to SQLite.
+ *
+ * Even if a subsequent open() call does succeed, the consequences of
+ * not searching for a reusable file descriptor are not dire.
+ */
+ if (0 == stat(zPath, &sStat)) {
+ unixInodeInfo *pInode;
+
+ pInode = inodeList;
+ while (pInode && (pInode->fileId.dev != sStat.st_dev
+ || pInode->fileId.ino !=
+ (u64) sStat.st_ino)) {
+ pInode = pInode->pNext;
+ }
+ if (pInode) {
+ UnixUnusedFd **pp;
+ for (pp = &pInode->pUnused;
+ *pp && (*pp)->flags != flags;
+ pp = &((*pp)->pNext)) ;
+ pUnused = *pp;
+ if (pUnused) {
+ *pp = pUnused->pNext;
}
- start = i + 1;
}
- buf[i] = lockPath[i];
}
-
- return 0;
+ return pUnused;
}
/*
- * 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.
+ * Find the mode, uid and gid of file zFile.
*/
static int
-proxyCreateUnixFile(const char *path, /* path for the new unixFile */
- unixFile ** ppFile, /* unixFile created and returned by ref */
- int islockfile /* if non zero missing dirs will be created */
+getFileMode(const char *zFile, /* File name */
+ mode_t * pMode, /* OUT: Permissions of zFile */
+ uid_t * pUid, /* OUT: uid of zFile. */
+ gid_t * pGid /* OUT: gid of zFile. */
)
{
- int fd = -1;
- unixFile *pNew;
+ struct stat sStat; /* Output of stat() on database file */
int rc = SQLITE_OK;
- int openFlags = O_RDWR | O_CREAT;
- sqlite3_vfs dummyVfs;
- int terrno = 0;
- UnixUnusedFd *pUnused = NULL;
-
- /* 1. first try to open/create the file
- * 2. if that fails, and this is a lock file (not-conch), try creating
- * the parent directories and then try again.
- * 3. if that fails, try to open the file read-only
- * otherwise return BUSY (if lock file) or CANTOPEN for the conch file
- */
- pUnused = findReusableFd(path, openFlags);
- if (pUnused) {
- fd = pUnused->fd;
+ if (0 == stat(zFile, &sStat)) {
+ *pMode = sStat.st_mode & 0777;
+ *pUid = sStat.st_uid;
+ *pGid = sStat.st_gid;
} else {
- pUnused = sqlite3_malloc64(sizeof(*pUnused));
- if (!pUnused) {
- return SQLITE_NOMEM_BKPT;
- }
- }
- if (fd < 0) {
- fd = robust_open(path, openFlags, 0);
- terrno = errno;
- if (fd < 0 && errno == ENOENT && islockfile) {
- if (proxyCreateLockPath(path) == SQLITE_OK) {
- fd = robust_open(path, openFlags, 0);
- }
- }
- }
- if (fd < 0) {
- openFlags = O_RDONLY;
- fd = robust_open(path, openFlags, 0);
- terrno = errno;
- }
- if (fd < 0) {
- if (islockfile) {
- return SQLITE_BUSY;
- }
- switch (terrno) {
- case EACCES:
- return SQLITE_PERM;
- case EIO:
- return SQLITE_IOERR_LOCK; /* even though it is the conch */
- default:
- return SQLITE_CANTOPEN_BKPT;
- }
- }
-
- pNew = (unixFile *) sqlite3_malloc64(sizeof(*pNew));
- if (pNew == NULL) {
- rc = SQLITE_NOMEM_BKPT;
- goto end_create_proxy;
- }
- memset(pNew, 0, sizeof(unixFile));
- pNew->openFlags = openFlags;
- memset(&dummyVfs, 0, sizeof(dummyVfs));
- dummyVfs.pAppData = (void *)&autolockIoFinder;
- dummyVfs.zName = "dummy";
- pUnused->fd = fd;
- pUnused->flags = openFlags;
- pNew->pUnused = pUnused;
-
- rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file *) pNew, path, 0);
- if (rc == SQLITE_OK) {
- *ppFile = pNew;
- return SQLITE_OK;
+ rc = SQLITE_IOERR_FSTAT;
}
- end_create_proxy:
- robust_close(pNew, fd, __LINE__);
- sqlite3_free(pNew);
- sqlite3_free(pUnused);
return rc;
}
-#ifdef SQLITE_TEST
-/* simulate multiple hosts by creating unique hostid file paths */
-int sqlite3_hostid_num = 0;
-#endif
-
-#define PROXY_HOSTIDLEN 16 /* conch file host id length */
-
-#ifdef HAVE_GETHOSTUUID
-/* Not always defined in the headers as it ought to be */
-extern int gethostuuid(uuid_t id, const struct timespec *wait);
-#endif
-
-/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
- * bytes of writable memory.
+/*
+ * This function is called by unixOpen() to determine the unix permissions
+ * to create new files with. If no error occurs, then SQLITE_OK is returned
+ * and a value suitable for passing as the third argument to open(2) is
+ * written to *pMode. If an IO error occurs, an SQLite error code is
+ * returned and the value of *pMode is not modified.
+ *
+ * In most cases, this routine sets *pMode to 0, which will become
+ * an indication to robust_open() to create the file using
+ * SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
+ * But if the file being opened is a regular journal file, then
+ * this function queries the file-system for the permissions on the
+ * corresponding database file and sets *pMode to this value. Whenever
+ * possible, journal files are created using the same permissions
+ * as the associated database file.
+ *
+ * If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
+ * original filename is unavailable. But 8_3_NAMES is only used for
+ * FAT filesystems and permissions do not matter there, so just use
+ * the default permissions.
*/
static int
-proxyGetHostID(unsigned char *pHostID, int *pError)
+findCreateFileMode(const char *zPath, /* Path of file (possibly) being created */
+ int flags, /* Flags passed as 4th argument to xOpen() */
+ mode_t * pMode, /* OUT: Permissions to open file with */
+ uid_t * pUid, /* OUT: uid to set on the file */
+ gid_t * pGid /* OUT: gid to set on the file */
+ )
{
- assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
- memset(pHostID, 0, PROXY_HOSTIDLEN);
-#ifdef HAVE_GETHOSTUUID
- {
- struct timespec timeout = { 1, 0 }; /* 1 sec timeout */
- if (gethostuuid(pHostID, &timeout)) {
- int err = errno;
- if (pError) {
- *pError = err;
- }
- return SQLITE_IOERR;
+ int rc = SQLITE_OK; /* Return Code */
+ *pMode = 0;
+ *pUid = 0;
+ *pGid = 0;
+ if (flags & SQLITE_OPEN_DELETEONCLOSE) {
+ *pMode = 0600;
+ } else if (flags & SQLITE_OPEN_URI) {
+ /* If this is a main database file and the file was opened using a URI
+ * filename, check for the "modeof" parameter. If present, interpret
+ * its value as a filename and try to copy the mode, uid and gid from
+ * that file.
+ */
+ const char *z = sqlite3_uri_parameter(zPath, "modeof");
+ if (z) {
+ rc = getFileMode(z, pMode, pUid, pGid);
}
}
-#else
- UNUSED_PARAMETER(pError);
-#endif
-#ifdef SQLITE_TEST
- /* simulate multiple hosts by creating unique hostid file paths */
- if (sqlite3_hostid_num != 0) {
- pHostID[0] =
- (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
- }
-#endif
-
- return SQLITE_OK;
+ return rc;
}
-/* The conch file contains the header, host id and lock file path
- */
-#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */
-#define PROXY_HEADERLEN 1 /* conch file header length */
-#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
-#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
-
/*
- * Takes an open conch file, copies the contents to a new path and then moves
- * it back. The newly created file's file descriptor is assigned to the
- * conch file structure and finally the original conch file descriptor is
- * closed. Returns zero if successful.
+ * 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
-proxyBreakConchLock(unixFile * pFile, uuid_t myHostID)
+unixOpen(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 */
+ )
{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- unixFile *conchFile = pCtx->conchFile;
- char tPath[MAXPATHLEN];
- char buf[PROXY_MAXCONCHLEN];
- char *cPath = pCtx->conchFilePath;
- size_t readLen = 0;
- size_t pathLen = 0;
- char errmsg[64] = "";
- int fd = -1;
- int rc = -1;
- UNUSED_PARAMETER(myHostID);
-
- /* create a new path by replace the trailing '-conch' with '-break' */
- pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
- if (pathLen > MAXPATHLEN || pathLen < 6 ||
- (strlcpy(&tPath[pathLen - 5], "break", 6) != 5)) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "path error (len %d)",
- (int)pathLen);
- goto end_breaklock;
- }
- /* read the conch content */
- readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
- if (readLen < PROXY_PATHINDEX) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "read error (len %d)",
- (int)readLen);
- goto end_breaklock;
- }
- /* write it out to the temporary break file */
- fd = robust_open(tPath, (O_RDWR | O_CREAT | O_EXCL), 0);
- if (fd < 0) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)",
- errno);
- goto end_breaklock;
- }
- if (osPwrite(fd, buf, readLen, 0) != (ssize_t) readLen) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)",
- errno);
- goto end_breaklock;
- }
- if (rename(tPath, cPath)) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)",
- errno);
- goto end_breaklock;
- }
- rc = 0;
- fprintf(stderr, "broke stale lock on %s\n", cPath);
- robust_close(pFile, conchFile->h, __LINE__);
- conchFile->h = fd;
- conchFile->openFlags = O_RDWR | O_CREAT;
+ unixFile *p = (unixFile *) pFile;
+ int fd = -1; /* File descriptor returned by 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; /* Function Return Code */
+ int ctrlFlags = 0; /* UNIXFILE_* flags */
- end_breaklock:
- if (rc) {
- if (fd >= 0) {
- osUnlink(tPath);
- robust_close(pFile, fd, __LINE__);
- }
- fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath,
- errmsg);
- }
- return rc;
-}
+ 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);
-/* Take the requested lock on the conch file and break a stale lock if the
- * host id matches.
- */
-static int
-proxyConchLock(unixFile * pFile, uuid_t myHostID, int lockType)
-{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- unixFile *conchFile = pCtx->conchFile;
- int rc = SQLITE_OK;
- int nTries = 0;
- struct timespec conchModTime;
+ /* 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 syncDir = isCreate;
- memset(&conchModTime, 0, sizeof(conchModTime));
- do {
- rc = conchFile->pMethod->xLock((sqlite3_file *) conchFile,
- lockType);
- nTries++;
- if (rc == SQLITE_BUSY) {
- /* If the lock failed (busy):
- * 1st try: get the mod time of the conch, wait 0.5s and try again.
- * 2nd try: fail if the mod time changed or host id is different, wait
- * 10 sec and try again
- * 3rd try: break the lock unless the mod time has changed.
- */
- struct stat buf;
- if (osFstat(conchFile->h, &buf)) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR_LOCK;
- }
+ /* If argument zPath is a NULL pointer, this function is required to open
+ * a temporary file. Use this buffer to store the file name in.
+ */
+ char zTmpname[MAX_PATHNAME + 2];
+ const char *zName = zPath;
+
+ /* 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);
+
+ /* Detect a pid change and reset the PRNG. There is a race condition
+ * here such that two or more threads all trying to open databases at
+ * the same instant might all reset the PRNG. But multiple resets
+ * are harmless.
+ */
+ if (randomnessPid != getpid()) {
+ randomnessPid = getpid();
+ sqlite3_randomness(0, 0);
+ }
- if (nTries == 1) {
- conchModTime = buf.st_mtimespec;
- usleep(500000); /* wait 0.5 sec and try the lock again */
- continue;
- }
+ memset(p, 0, sizeof(unixFile));
- assert(nTries > 1);
- if (conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
- conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec) {
- return SQLITE_BUSY;
+ if (eType == SQLITE_OPEN_MAIN_DB) {
+ UnixUnusedFd *pUnused;
+ pUnused = findReusableFd(zName, flags);
+ if (pUnused) {
+ fd = pUnused->fd;
+ } else {
+ pUnused = sqlite3_malloc64(sizeof(*pUnused));
+ if (!pUnused) {
+ return SQLITE_NOMEM_BKPT;
}
+ }
+ p->pUnused = pUnused;
- if (nTries == 2) {
- char tBuf[PROXY_MAXCONCHLEN];
- int len =
- osPread(conchFile->h, tBuf,
- PROXY_MAXCONCHLEN, 0);
- if (len < 0) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR_LOCK;
- }
- if (len > PROXY_PATHINDEX
- && tBuf[0] == (char)PROXY_CONCHVERSION) {
- /* don't break the lock if the host id doesn't match */
- if (0 !=
- memcmp(&tBuf[PROXY_HEADERLEN],
- myHostID, PROXY_HOSTIDLEN)) {
- return SQLITE_BUSY;
- }
- } else {
- /* don't break the lock on short read or a version mismatch */
- return SQLITE_BUSY;
- }
- usleep(10000000); /* wait 10 sec and try the lock again */
- continue;
- }
+ /* Database filenames are double-zero terminated if they are not
+ * URIs with parameters. Hence, they can always be passed into
+ * sqlite3_uri_parameter().
+ */
+ assert((flags & SQLITE_OPEN_URI)
+ || zName[strlen(zName) + 1] == 0);
- assert(nTries == 3);
- if (0 == proxyBreakConchLock(pFile, myHostID)) {
- rc = SQLITE_OK;
- if (lockType == EXCLUSIVE_LOCK) {
- rc = conchFile->pMethod->
- xLock((sqlite3_file *) conchFile,
- SHARED_LOCK);
- }
- if (!rc) {
- rc = conchFile->pMethod->
- xLock((sqlite3_file *) conchFile,
- lockType);
- }
- }
+ } else if (!zName) {
+ /* If zName is NULL, the upper layer is requesting a temp file. */
+ assert(isDelete);
+ rc = unixGetTempname(pVfs->mxPathname, zTmpname);
+ if (rc != SQLITE_OK) {
+ return rc;
}
- } while (rc == SQLITE_BUSY && nTries < 3);
+ zName = zTmpname;
- return rc;
-}
+ /* Generated temporary filenames are always double-zero terminated
+ * for use by sqlite3_uri_parameter().
+ */
+ assert(zName[strlen(zName) + 1] == 0);
+ }
-/* 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
-proxyTakeConch(unixFile * pFile)
-{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
+ /* Determine the value of the flags parameter passed to POSIX function
+ * open(). These must be calculated even if open() is not called, as
+ * they may be stored as part of the file handle and used by the
+ * 'conch file' locking functions later on.
+ */
+ if (isReadonly)
+ openFlags |= O_RDONLY;
+ if (isReadWrite)
+ openFlags |= O_RDWR;
+ if (isCreate)
+ openFlags |= O_CREAT;
+ if (isExclusive)
+ openFlags |= (O_EXCL | O_NOFOLLOW);
+ openFlags |= O_BINARY;
+ #ifndef __APPLE__
+ openFlags |= O_LARGEFILE;
+ #endif
- if (pCtx->conchHeld != 0) {
- return SQLITE_OK;
- } else {
- unixFile *conchFile = pCtx->conchFile;
- uuid_t myHostID;
- int pError = 0;
- char readBuf[PROXY_MAXCONCHLEN];
- char lockPath[MAXPATHLEN];
- char *tempLockPath = NULL;
- int rc = SQLITE_OK;
- int createConch = 0;
- int hostIdMatch = 0;
- int readLen = 0;
- int tryOldLockPath = 0;
- int forceNewLockPath = 0;
-
- rc = proxyGetHostID(myHostID, &pError);
- if ((rc & 0xff) == SQLITE_IOERR) {
- storeLastErrno(pFile, pError);
- goto end_takeconch;
- }
- rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
+ if (fd < 0) {
+ mode_t openMode; /* Permissions to create file with */
+ uid_t uid; /* Userid for the file */
+ gid_t gid; /* Groupid for the file */
+ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
if (rc != SQLITE_OK) {
- goto end_takeconch;
+ assert(!p->pUnused);
+ return rc;
}
- /* read the existing conch file */
- readLen =
- seekAndRead((unixFile *) conchFile, 0, readBuf,
- PROXY_MAXCONCHLEN);
- if (readLen < 0) {
- /* I/O error: lastErrno set by seekAndRead */
- storeLastErrno(pFile, conchFile->lastErrno);
- rc = SQLITE_IOERR_READ;
- goto end_takeconch;
- } else if (readLen <= (PROXY_HEADERLEN + PROXY_HOSTIDLEN) ||
- readBuf[0] != (char)PROXY_CONCHVERSION) {
- /* a short read or version format mismatch means we need to create a new
- * conch file.
- */
- createConch = 1;
+ fd = robust_open(zName, openFlags, openMode);
+ assert(!isExclusive || (openFlags & O_CREAT) != 0);
+ if (fd < 0 && errno != EISDIR && isReadWrite) {
+ /* Failed to open the file for read/write access. Try read-only. */
+ flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+ openFlags &= ~(O_RDWR | O_CREAT);
+ flags |= SQLITE_OPEN_READONLY;
+ openFlags |= O_RDONLY;
+ isReadonly = 1;
+ fd = robust_open(zName, openFlags, openMode);
}
- /* if the host id matches and the lock path already exists in the conch
- * we'll try to use the path there, if we can't open that path, we'll
- * retry with a new auto-generated path
- */
- do { /* in case we need to try again for an :auto: named lock file */
-
- if (!createConch && !forceNewLockPath) {
- hostIdMatch =
- !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
- PROXY_HOSTIDLEN);
- /* if the conch has data compare the contents */
- if (!pCtx->lockProxyPath) {
- /* for auto-named local lock file, just check the host ID and we'll
- * use the local lock file path that's already in there
- */
- if (hostIdMatch) {
- size_t pathLen =
- (readLen - PROXY_PATHINDEX);
-
- if (pathLen >= MAXPATHLEN) {
- pathLen =
- MAXPATHLEN - 1;
- }
- memcpy(lockPath,
- &readBuf
- [PROXY_PATHINDEX],
- pathLen);
- lockPath[pathLen] = 0;
- tempLockPath = lockPath;
- tryOldLockPath = 1;
- /* create a copy of the lock path if the conch is taken */
- goto end_takeconch;
- }
- } else if (hostIdMatch
- && !strncmp(pCtx->lockProxyPath,
- &readBuf
- [PROXY_PATHINDEX],
- readLen -
- PROXY_PATHINDEX)
- ) {
- /* conch host and lock path match */
- goto end_takeconch;
- }
- }
+ if (fd < 0) {
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
+ goto open_finished;
+ }
+
+ }
+ assert(fd >= 0);
+ if (pOutFlags) {
+ *pOutFlags = flags;
+ }
- /* if the conch isn't writable and doesn't match, we can't take it */
- if ((conchFile->openFlags & O_RDWR) == 0) {
- rc = SQLITE_BUSY;
- goto end_takeconch;
- }
+ if (p->pUnused) {
+ p->pUnused->fd = fd;
+ p->pUnused->flags = flags;
+ }
- /* either the conch didn't match or we need to create a new one */
- if (!pCtx->lockProxyPath) {
- proxyGetLockPath(pCtx->dbPath, lockPath,
- MAXPATHLEN);
- tempLockPath = lockPath;
- /* create a copy of the lock path _only_ if the conch is taken */
- }
+ if (isDelete)
+ unlink(zName);
- /* update conch with host and path (this will fail if other process
- * has a shared lock already), if the host id matches, use the big
- * stick.
- */
- futimes(conchFile->h, NULL);
- if (hostIdMatch && !createConch) {
- if (conchFile->pInode
- && conchFile->pInode->nShared > 1) {
- /* We are trying for an exclusive lock but another thread in this
- * same process is still holding a shared lock.
- */
- rc = SQLITE_BUSY;
- } else {
- rc = proxyConchLock(pFile, myHostID,
- EXCLUSIVE_LOCK);
- }
- } else {
- rc = proxyConchLock(pFile, myHostID,
- EXCLUSIVE_LOCK);
- }
- if (rc == SQLITE_OK) {
- char writeBuffer[PROXY_MAXCONCHLEN];
- int writeSize = 0;
-
- writeBuffer[0] = (char)PROXY_CONCHVERSION;
- memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID,
- PROXY_HOSTIDLEN);
- if (pCtx->lockProxyPath != NULL) {
- strlcpy(&writeBuffer[PROXY_PATHINDEX],
- pCtx->lockProxyPath,
- MAXPATHLEN);
- } else {
- strlcpy(&writeBuffer[PROXY_PATHINDEX],
- tempLockPath, MAXPATHLEN);
- }
- writeSize =
- PROXY_PATHINDEX +
- strlen(&writeBuffer[PROXY_PATHINDEX]);
- robust_ftruncate(conchFile->h, writeSize);
- rc = unixWrite((sqlite3_file *) conchFile,
- writeBuffer, writeSize, 0);
- full_fsync(conchFile->h, 0, 0);
- /* If we created a new conch file (not just updated the contents of a
- * valid conch file), try to match the permissions of the database
- */
- if (rc == SQLITE_OK && createConch) {
- struct stat buf;
- int err = osFstat(pFile->h, &buf);
- if (err == 0) {
- mode_t cmode =
- buf.
- st_mode & (S_IRUSR | S_IWUSR
- | S_IRGRP |
- S_IWGRP | S_IROTH
- | S_IWOTH);
- /* try to match the database file R/W permissions, ignore failure */
-#ifndef SQLITE_PROXY_DEBUG
- osFchmod(conchFile->h, cmode);
-#else
- do {
- rc = osFchmod
- (conchFile->h,
- cmode);
- } while (rc == (-1)
- && errno == EINTR);
- if (rc != 0) {
- int code = errno;
- fprintf(stderr,
- "fchmod %o FAILED with %d %s\n",
- cmode, code,
- strerror(code));
- } else {
- fprintf(stderr,
- "fchmod %o SUCCEDED\n",
- cmode);
- }
- } else {
- int code = errno;
- fprintf(stderr,
- "STAT FAILED[%d] with %d %s\n",
- err, code,
- strerror(code));
-#endif
- }
- }
- }
- conchFile->pMethod->xUnlock((sqlite3_file *) conchFile,
- SHARED_LOCK);
-
- end_takeconch:
- if (rc == SQLITE_OK && pFile->openFlags) {
- int fd;
- if (pFile->h >= 0) {
- robust_close(pFile, pFile->h, __LINE__);
- }
- pFile->h = -1;
- fd = robust_open(pCtx->dbPath, pFile->openFlags,
- 0);
- if (fd >= 0) {
- pFile->h = fd;
- } else {
- rc = SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called
- during locking */
- }
- }
- if (rc == SQLITE_OK && !pCtx->lockProxy) {
- char *path =
- tempLockPath ? tempLockPath : pCtx->
- lockProxyPath;
- rc = proxyCreateUnixFile(path, &pCtx->lockProxy,
- 1);
- if (rc != SQLITE_OK && rc != SQLITE_NOMEM
- && tryOldLockPath) {
- /* we couldn't create the proxy lock file with the old lock file path
- * so try again via auto-naming
- */
- forceNewLockPath = 1;
- tryOldLockPath = 0;
- continue; /* go back to the do {} while start point, try again */
- }
- }
- if (rc == SQLITE_OK) {
- /* Need to make a copy of path if we extracted the value
- * from the conch file or the path was allocated on the stack
- */
- if (tempLockPath) {
- pCtx->lockProxyPath =
- sqlite3DbStrDup(0, tempLockPath);
- if (!pCtx->lockProxyPath) {
- rc = SQLITE_NOMEM_BKPT;
- }
- }
- }
- if (rc == SQLITE_OK) {
- pCtx->conchHeld = 1;
-
- if (pCtx->lockProxy->pMethod == &afpIoMethods) {
- afpLockingContext *afpCtx;
- afpCtx =
- (afpLockingContext *) pCtx->
- lockProxy->lockingContext;
- afpCtx->dbPath = pCtx->lockProxyPath;
- }
- } else {
- conchFile->pMethod->
- xUnlock((sqlite3_file *) conchFile,
- NO_LOCK);
- }
- return rc;
- } while (1); /* in case we need to retry the :auto: lock file -
- * we should never get here except via the 'continue' call.
- */
+ /* Set up appropriate ctrlFlags */
+ if (isDelete)
+ ctrlFlags |= UNIXFILE_DELETE;
+ if (isReadonly)
+ ctrlFlags |= UNIXFILE_RDONLY;
+ noLock = eType != SQLITE_OPEN_MAIN_DB;
+ if (noLock)
+ ctrlFlags |= UNIXFILE_NOLOCK;
+ if (syncDir)
+ ctrlFlags |= UNIXFILE_DIRSYNC;
+ if (flags & SQLITE_OPEN_URI)
+ ctrlFlags |= UNIXFILE_URI;
+
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+
+ open_finished:
+ if (rc != SQLITE_OK) {
+ sqlite3_free(p->pUnused);
}
+ return rc;
}
/*
- * If pFile holds a lock on a conch file, then release that lock.
+ * Delete the file at zPath. If the dirSync argument is true, fsync()
+ * the directory after deleting the file.
*/
static int
-proxyReleaseConch(unixFile * pFile)
+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; /* 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;
- if (pCtx->conchHeld > 0) {
- rc = conchFile->pMethod->xUnlock((sqlite3_file *) conchFile,
- NO_LOCK);
+ int rc = SQLITE_OK;
+ UNUSED_PARAMETER(NotUsed);
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ if (unlink(zPath) == (-1)) {
+ if (errno == ENOENT) {
+ rc = SQLITE_IOERR_DELETE_NOENT;
+ } else {
+ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ }
+ return rc;
+ }
+#ifndef SQLITE_DISABLE_DIRSYNC
+ if ((dirSync & 1) != 0) {
+ int fd;
+ rc = openDirectory(zPath, &fd);
+ if (rc == SQLITE_OK) {
+ if (full_fsync(fd, 0, 0)) {
+ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC,
+ "fsync", zPath);
+ }
+ robust_close(0, fd, __LINE__);
+ } else {
+ assert(rc == SQLITE_CANTOPEN);
+ rc = SQLITE_OK;
+ }
}
- pCtx->conchHeld = 0;
+#endif
return rc;
}
/*
- * Given the name of a database file, compute the name of its conch file.
- * Store the conch filename in memory obtained from sqlite3_malloc64().
- * Make *pConchPath point to the new name. Return SQLITE_OK on success
- * or SQLITE_NOMEM if unable to obtain memory.
+ * Test the existence of or access permissions of file zPath. The
+ * test performed depends on the value of flags:
*
- * The caller is responsible for ensuring that the allocated memory
- * space is eventually freed.
+ * 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.
*
- * *pConchPath is set to NULL if a memory allocation error occurs.
+ * Otherwise return 0.
*/
static int
-proxyCreateConchPathname(char *dbPath, char **pConchPath)
+unixAccess(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 i; /* Loop counter */
- int len = (int)strlen(dbPath); /* Length of database filename - dbPath */
- char *conchPath; /* buffer in which to construct conch name */
+ UNUSED_PARAMETER(NotUsed);
+ SimulateIOError(return SQLITE_IOERR_ACCESS;
+ );
+ assert(pResOut != 0);
- /* Allocate space for the conch filename and initialize the name to
- * the name of the original database file.
+ /* The spec says there are three possible values for flags. But only
+ * two of them are actually used
*/
- *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
- if (conchPath == 0) {
- return SQLITE_NOMEM_BKPT;
- }
- memcpy(conchPath, dbPath, len + 1);
+ assert(flags == SQLITE_ACCESS_EXISTS
+ || flags == SQLITE_ACCESS_READWRITE);
- /* now insert a "." before the last / character */
- for (i = (len - 1); i >= 0; i--) {
- if (conchPath[i] == '/') {
- i++;
- break;
- }
- }
- conchPath[i] = '.';
- while (i < len) {
- conchPath[i + 1] = dbPath[i];
- i++;
+ if (flags == SQLITE_ACCESS_EXISTS) {
+ struct stat buf;
+ *pResOut = (0 == stat(zPath, &buf) && buf.st_size > 0);
+ } else {
+ *pResOut = access(zPath, W_OK | R_OK) == 0;
}
-
- /* append the "-conch" suffix to the file */
- memcpy(&conchPath[i + 1], "-conch", 7);
- assert((int)strlen(conchPath) == len + 7);
-
return SQLITE_OK;
}
-/* Takes a fully configured proxy locking-style unix file and switches
- * the local lock file path
- */
static int
-switchLockProxyPath(unixFile * pFile, const char *path)
+mkFullPathname(const char *zPath, /* Input path */
+ char *zOut, /* Output buffer */
+ int nOut /* Allocated size of buffer zOut */
+ )
{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- char *oldPath = pCtx->lockProxyPath;
- int rc = SQLITE_OK;
-
- if (pFile->eFileLock != NO_LOCK) {
- return SQLITE_BUSY;
- }
-
- /* nothing to do if the path is NULL, :auto: or matches the existing path */
- if (!path || path[0] == '\0' || !strcmp(path, ":auto:") ||
- (oldPath && !strncmp(oldPath, path, MAXPATHLEN))) {
- return SQLITE_OK;
- } else {
- unixFile *lockProxy = pCtx->lockProxy;
- pCtx->lockProxy = NULL;
- pCtx->conchHeld = 0;
- if (lockProxy != NULL) {
- rc = lockProxy->pMethod->
- xClose((sqlite3_file *) lockProxy);
- if (rc)
- return rc;
- sqlite3_free(lockProxy);
+ int nPath = sqlite3Strlen30(zPath);
+ int iOff = 0;
+ if (zPath[0] != '/') {
+ if (getcwd(zOut, nOut - 2) == 0) {
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd",
+ zPath);
}
- sqlite3_free(oldPath);
- pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
+ iOff = sqlite3Strlen30(zOut);
+ zOut[iOff++] = '/';
}
-
- return rc;
+ if ((iOff + nPath + 1) > nOut) {
+ /* SQLite assumes that xFullPathname() nul-terminates the output buffer
+ * even if it returns an error.
+ */
+ zOut[iOff] = '\0';
+ return SQLITE_CANTOPEN_BKPT;
+ }
+ sqlite3_snprintf(nOut - iOff, &zOut[iOff], "%s", zPath);
+ return SQLITE_OK;
}
/*
- * 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.
+ * 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.
*
- * This routine find the filename associated with pFile and writes it
- * int dbPath.
+ * 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
-proxyGetDbPathForUnixFile(unixFile * pFile, char *dbPath)
+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 */
+ )
{
-#if defined(__APPLE__)
- if (pFile->pMethod == &afpIoMethods) {
- /* afp style keeps a reference to the db path in the filePath field
- * of the struct
- */
- assert((int)strlen((char *)pFile->lockingContext) <=
- MAXPATHLEN);
- strlcpy(dbPath,
- ((afpLockingContext *) pFile->lockingContext)->dbPath,
- MAXPATHLEN);
- } 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);
- strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN);
- }
- return SQLITE_OK;
+ (void)pVfs;
+ return mkFullPathname(zPath, zOut, nOut);
}
/*
- * 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
- * the unix structure properly cleaned up at close time:
- * ->lockingContext
- * ->pMethod
+ * Interfaces for opening a shared library, finding entry points
+ * within the shared library, and closing the shared library.
*/
-static int
-proxyTransformUnixFile(unixFile * pFile, const char *path)
+#include <dlfcn.h>
+static void *
+unixDlOpen(sqlite3_vfs * NotUsed, const char *zFilename)
{
- proxyLockingContext *pCtx;
- char dbPath[MAXPATHLEN + 1]; /* Name of the database file */
- char *lockPath = NULL;
- int rc = SQLITE_OK;
-
- if (pFile->eFileLock != NO_LOCK) {
- return SQLITE_BUSY;
- }
- proxyGetDbPathForUnixFile(pFile, dbPath);
- if (!path || path[0] == '\0' || !strcmp(path, ":auto:")) {
- lockPath = NULL;
- } else {
- lockPath = (char *)path;
- }
-
- pCtx = sqlite3_malloc64(sizeof(*pCtx));
- if (pCtx == 0) {
- return SQLITE_NOMEM_BKPT;
- }
- memset(pCtx, 0, sizeof(*pCtx));
-
- rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath);
- if (rc == SQLITE_OK) {
- rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile,
- 0);
- if (rc == SQLITE_CANTOPEN && ((pFile->openFlags & O_RDWR) == 0)) {
- /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and
- * (c) the file system is read-only, then enable no-locking access.
- * Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts
- * that openFlags will have only one of O_RDONLY or O_RDWR.
- */
- struct statfs fsInfo;
- struct stat conchInfo;
- int goLockless = 0;
-
- if (osStat(pCtx->conchFilePath, &conchInfo) == -1) {
- int err = errno;
- if ((err == ENOENT)
- && (statfs(dbPath, &fsInfo) != -1)) {
- goLockless =
- (fsInfo.f_flags & MNT_RDONLY) ==
- MNT_RDONLY;
- }
- }
- if (goLockless) {
- pCtx->conchHeld = -1; /* read only FS/ lockless */
- rc = SQLITE_OK;
- }
- }
- }
- if (rc == SQLITE_OK && lockPath) {
- pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
- }
-
- if (rc == SQLITE_OK) {
- pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
- if (pCtx->dbPath == NULL) {
- rc = SQLITE_NOMEM_BKPT;
- }
- }
- if (rc == SQLITE_OK) {
- /* all memory is allocated, proxys are created and assigned,
- * switch the locking context and pMethod then return.
- */
- pCtx->oldLockingContext = pFile->lockingContext;
- pFile->lockingContext = pCtx;
- pCtx->pOldMethod = pFile->pMethod;
- pFile->pMethod = &proxyIoMethods;
- } else {
- if (pCtx->conchFile) {
- pCtx->conchFile->pMethod->xClose((sqlite3_file *) pCtx->
- conchFile);
- sqlite3_free(pCtx->conchFile);
- }
- sqlite3DbFree(0, pCtx->lockProxyPath);
- sqlite3_free(pCtx->conchFilePath);
- sqlite3_free(pCtx);
- }
- return rc;
+ UNUSED_PARAMETER(NotUsed);
+ return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
}
/*
- * This routine handles sqlite3_file_control() calls that are specific
- * to proxy locking.
+ * 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 int
-proxyFileControl(sqlite3_file * id, int op, void *pArg)
+static void
+unixDlError(sqlite3_vfs * NotUsed, int nBuf, char *zBufOut)
{
- switch (op) {
- case SQLITE_FCNTL_GET_LOCKPROXYFILE:{
- unixFile *pFile = (unixFile *) id;
- if (pFile->pMethod == &proxyIoMethods) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->
- lockingContext;
- proxyTakeConch(pFile);
- if (pCtx->lockProxyPath) {
- *(const char **)pArg =
- pCtx->lockProxyPath;
- } else {
- *(const char **)pArg =
- ":auto: (not held)";
- }
- } else {
- *(const char **)pArg = NULL;
- }
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_SET_LOCKPROXYFILE:{
- unixFile *pFile = (unixFile *) id;
- int rc = SQLITE_OK;
- int isProxyStyle = (pFile->pMethod == &proxyIoMethods);
- if (pArg == NULL || (const char *)pArg == 0) {
- if (isProxyStyle) {
- rc = SQLITE_ERROR;
- } else {
- /* turn off proxy locking - already off - NOOP */
- rc = SQLITE_OK;
- }
- } else {
- const char *proxyPath = (const char *)pArg;
- if (isProxyStyle) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->
- lockingContext;
- if (!strcmp(pArg, ":auto:")
- || (pCtx->lockProxyPath &&
- !strncmp(pCtx->lockProxyPath,
- proxyPath, MAXPATHLEN))
- ) {
- rc = SQLITE_OK;
- } else {
- rc = switchLockProxyPath(pFile,
- proxyPath);
- }
- } else {
- /* turn on proxy file locking */
- rc = proxyTransformUnixFile(pFile,
- proxyPath);
- }
- }
- return rc;
- }
- default:{
- assert(0); /* The call assures that only valid opcodes are sent */
- }
+ const char *zErr;
+ UNUSED_PARAMETER(NotUsed);
+ zErr = dlerror();
+ if (zErr) {
+ sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
}
- /*NOTREACHED*/ return SQLITE_ERROR;
}
-/*
- * 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.
- */
+static
+ void (*unixDlSym(sqlite3_vfs * NotUsed, void *p, const char *zSym)) (void) {
+ /*
+ * GCC with -pedantic-errors says that C90 does not allow a void* to be
+ * cast into a pointer to a function. And yet the library dlsym() routine
+ * returns a void* which is really a pointer to a function. So how do we
+ * use dlsym() with -pedantic-errors?
+ *
+ * Variable x below is defined to be a pointer to a function taking
+ * parameters void* and const char* and returning a pointer to a function.
+ * We initialize x by assigning it a pointer to the dlsym() function.
+ * (That assignment requires a cast.) Then we call the function that
+ * x points to.
+ *
+ * This work-around is unlikely to work correctly on any system where
+ * you really cannot cast a function pointer into void*. But then, on the
+ * other hand, dlsym() will not work on such a system either, so we have
+ * not really lost anything.
+ */
+ void (*(*x) (void *, const char *)) (void);
+ UNUSED_PARAMETER(NotUsed);
+ x = (void (*(*)(void *, const char *))(void))dlsym;
+ return (*x) (p, zSym);
+}
+
+static void
+unixDlClose(sqlite3_vfs * NotUsed, void *pHandle)
+{
+ UNUSED_PARAMETER(NotUsed);
+ dlclose(pHandle);
+}
/*
- * 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.
+ * Write nBuf bytes of random data to the supplied buffer zBuf.
*/
static int
-proxyCheckReservedLock(sqlite3_file * id, int *pResOut)
+unixRandomness(sqlite3_vfs * NotUsed, int nBuf, char *zBuf)
{
- unixFile *pFile = (unixFile *) id;
- int rc = proxyTakeConch(pFile);
- if (rc == SQLITE_OK) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- if (pCtx->conchHeld > 0) {
- unixFile *proxy = pCtx->lockProxy;
- return proxy->pMethod->
- xCheckReservedLock((sqlite3_file *) proxy, pResOut);
- } else { /* conchHeld < 0 is lockless */
- pResOut = 0;
- }
- }
- return rc;
+ UNUSED_PARAMETER(NotUsed);
+ assert((size_t) 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
+ * uninitialized space in zBuf - but valgrind errors tend to worry
+ * some users. Rather than argue, it seems easier just to initialize
+ * the whole array and silence valgrind, even if that means less randomness
+ * in the random seed.
+ *
+ * When testing, initializing zBuf[] to zero is all we do. That means
+ * that we always use the same random number sequence. This makes the
+ * tests repeatable.
+ */
+ memset(zBuf, 0, nBuf);
+ randomnessPid = getpid();
+ return nBuf;
}
/*
- * Lock the file with the lock specified by parameter eFileLock - 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.
+ * Sleep for a little while. Return the amount of time slept.
+ * 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.
*/
static int
-proxyLock(sqlite3_file * id, int eFileLock)
+unixSleep(sqlite3_vfs * NotUsed, int microseconds)
{
- unixFile *pFile = (unixFile *) id;
- int rc = proxyTakeConch(pFile);
- if (rc == SQLITE_OK) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- if (pCtx->conchHeld > 0) {
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xLock((sqlite3_file *) proxy,
- eFileLock);
- pFile->eFileLock = proxy->eFileLock;
- } else {
- /* conchHeld < 0 is lockless */
- }
- }
- return rc;
+ int seconds = (microseconds + 999999) / 1000000;
+ sleep(seconds);
+ UNUSED_PARAMETER(NotUsed);
+ return seconds * 1000000;
}
+/* Fake system time in seconds since 1970. */
+int sqlite3_current_time = 0;
+
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * must be either NO_LOCK or SHARED_LOCK.
+ * Find the current time (in Universal Coordinated Time). Write into *piNow
+ * the current time and date as a Julian Day number times 86_400_000. In
+ * other words, write into *piNow the number of milliseconds since the Julian
+ * epoch of noon in Greenwich on November 24, 4714 B.C according to the
+ * proleptic Gregorian calendar.
*
- * If the locking level of the file descriptor is already at or below
- * the requested locking level, this routine is a no-op.
+ * On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
+ * cannot be found.
*/
static int
-proxyUnlock(sqlite3_file * id, int eFileLock)
+unixCurrentTimeInt64(sqlite3_vfs * NotUsed, sqlite3_int64 * piNow)
{
- unixFile *pFile = (unixFile *) id;
- int rc = proxyTakeConch(pFile);
- if (rc == SQLITE_OK) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- if (pCtx->conchHeld > 0) {
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xUnlock((sqlite3_file *) proxy,
- eFileLock);
- pFile->eFileLock = proxy->eFileLock;
- } else {
- /* conchHeld < 0 is lockless */
- }
+ static const sqlite3_int64 unixEpoch =
+ 24405875 * (sqlite3_int64) 8640000;
+ int rc = SQLITE_OK;
+ struct timeval sNow;
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
+ *piNow =
+ unixEpoch + 1000 * (sqlite3_int64) sNow.tv_sec +
+ sNow.tv_usec / 1000;
+
+#ifdef SQLITE_TEST
+ if (sqlite3_current_time) {
+ *piNow =
+ 1000 * (sqlite3_int64) sqlite3_current_time + unixEpoch;
}
+#endif
+ UNUSED_PARAMETER(NotUsed);
return rc;
}
/*
- * Close a file that uses proxy locks.
+ * The xGetLastError() method is designed to return a better
+ * low-level error message when operating-system problems come up
+ * during SQLite operation. Only the integer return code is currently
+ * used.
*/
static int
-proxyClose(sqlite3_file * id)
+unixGetLastError(sqlite3_vfs * NotUsed, int NotUsed2, char *NotUsed3)
{
- if (ALWAYS(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);
- }
- sqlite3DbFree(0, pCtx->lockProxyPath);
- sqlite3_free(pCtx->conchFilePath);
- sqlite3DbFree(0, 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;
+ UNUSED_PARAMETER(NotUsed);
+ UNUSED_PARAMETER(NotUsed2);
+ UNUSED_PARAMETER(NotUsed3);
+ return errno;
}
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+/*
+ *********************** End of sqlite3_vfs methods ***************************
+ *****************************************************************************/
+
/*
* The proxy locking style is intended for use with AFP filesystems.
* And since AFP is only supported on MacOSX, the proxy locking is also
@@ -6205,47 +2737,11 @@ proxyClose(sqlite3_file * id)
****************** End of the proxy lock implementation **********************
*****************************************************************************/
-/*
- * Initialize the operating system interface.
- *
- * This routine registers all VFS implementations for unix-like operating
- * 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 subsystem have not
- * necessarily been initialized when this routine \is called, and so they
- * should not be used.
- */
-int
-sqlite3_os_init(void)
-{
- /*
- * 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 pointer
- * to the "finder" function. (pAppData is a pointer to a pointer because
- * silly C90 rules prohibit a void* from being cast to a function pointer
- * and so we have to go through the intermediate pointer to avoid problems
- * when compiling with -pedantic-errors on GCC.)
- *
- * The FINDER parameter to this macro is the name of the pointer to 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) { \
3, /* iVersion */ \
sizeof(unixFile), /* szOsFile */ \
MAX_PATHNAME, /* mxPathname */ \
- 0, /* pNext */ \
+ NULL, /* pNext */ \
VFSNAME, /* zName */ \
(void*)&FINDER, /* pAppData */ \
unixOpen, /* xOpen */ \
@@ -6258,14 +2754,30 @@ sqlite3_os_init(void)
unixDlClose, /* xDlClose */ \
unixRandomness, /* xRandomness */ \
unixSleep, /* xSleep */ \
- 0, /* xCurrentTime */ \
+ NULL, /* xCurrentTime */ \
unixGetLastError, /* xGetLastError */ \
unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
- unixSetSystemCall, /* xSetSystemCall */ \
- unixGetSystemCall, /* xGetSystemCall */ \
- unixNextSystemCall, /* xNextSystemCall */ \
+ NULL, /* xSetSystemCall */ \
+ NULL, /* xGetSystemCall */ \
+ NULL, /* xNextSystemCall */ \
}
+/*
+ * Initialize the operating system interface.
+ *
+ * This routine registers all VFS implementations for unix-like operating
+ * 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 subsystem have not
+ * necessarily been initialized when this routine \is called, and so they
+ * should not be used.
+ */
+int
+sqlite3_os_init(void)
+{
/*
* All default VFSes for unix are contained in the following array.
*
@@ -6274,36 +2786,13 @@ sqlite3_os_init(void)
* array cannot be const.
*/
static sqlite3_vfs aVfs[] = {
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- UNIXVFS("unix", autolockIoFinder),
-#endif
UNIXVFS("unix-none", nolockIoFinder),
- UNIXVFS("unix-dotfile", dotlockIoFinder),
- UNIXVFS("unix-excl", posixIoFinder),
-
-#if SQLITE_ENABLE_LOCKING_STYLE
- UNIXVFS("unix-posix", posixIoFinder),
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
- UNIXVFS("unix-flock", flockIoFinder),
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- UNIXVFS("unix-afp", afpIoFinder),
- UNIXVFS("unix-nfs", nfsIoFinder),
- UNIXVFS("unix-proxy", proxyIoFinder),
-#endif
+ UNIXVFS("unix-excl", posixIoFinder)
};
- unsigned int i; /* Loop counter */
-
- /* Double-check that the aSyscall[] array has been constructed
- * correctly. See ticket [bb3a86e890c8e96ab]
- */
- assert(ArraySize(aSyscall) == 28);
- /* Register all VFSes defined in the aVfs[] array */
- for (i = 0; i < (sizeof(aVfs) / sizeof(sqlite3_vfs)); i++) {
+ /* Register all VFSes defined in the aVfs[] array. */
+ for (unsigned int i = 0; i < (sizeof(aVfs) / sizeof(sqlite3_vfs)); i++)
sqlite3_vfs_register(&aVfs[i], i == 0);
- }
return SQLITE_OK;
}
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index e7a02dc..69debfc 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -866,7 +866,6 @@ struct sqlite3_io_methods {
int (*xFileSize) (sqlite3_file *, sqlite3_int64 * pSize);
int (*xLock) (sqlite3_file *, int);
int (*xUnlock) (sqlite3_file *, int);
- int (*xCheckReservedLock) (sqlite3_file *, int *pResOut);
int (*xFileControl) (sqlite3_file *, int op, void *pArg);
int (*xSectorSize) (sqlite3_file *);
int (*xDeviceCharacteristics) (sqlite3_file *);
--
2.7.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-06-28 15:21 [tarantool-patches] [PATCH v1 1/1] sql: drop useless code from os_unix.c Kirill Shcherbatov
@ 2018-07-02 11:22 ` Vladislav Shpilevoy
2018-07-02 14:55 ` Kirill Shcherbatov
2018-08-14 7:45 ` Kirill Yukhin
1 sibling, 1 reply; 9+ messages in thread
From: Vladislav Shpilevoy @ 2018-07-02 11:22 UTC (permalink / raw)
To: Kirill Shcherbatov, tarantool-patches
Hello. Thanks for the patch! See 2 comments below.
On 28/06/2018 18:21, Kirill Shcherbatov wrote:
> Resolves #3284.
> ---
> https://github.com/tarantool/tarantool/tree/kshch/gh-3284-no-os-unix
> https://github.com/tarantool/tarantool/issues/3284
> src/box/sql/os.c | 168 --
> src/box/sql/os_unix.c | 6195 ++++++++++-------------------------------------
> src/box/sql/sqliteInt.h | 1 -
> 3 files changed, 1342 insertions(+), 5022 deletions(-)
>
> diff --git a/src/box/sql/os.c b/src/box/sql/os.c
> index 38d3585..5a04edb 100644
> --- a/src/box/sql/os.c
> +++ b/src/box/sql/os.c
> @@ -123,123 +123,12 @@ sqlite3OsWrite(sqlite3_file * id, const void *pBuf, int amt, i64 offset)
> return id->pMethods->xWrite(id, pBuf, amt, offset);
> }
>
> -int
> -sqlite3OsTruncate(sqlite3_file * id, i64 size)
> -{
> - return id->pMethods->xTruncate(id, size);
> -}
1. These functions still are visible in grep results.
2. And much more functions and constants are either unused, or just
declared, but has no implementation. Please, complete the patch. I have
pushed some of removals on the branch as a separate commit. Please,
squash and finalize.
> -
> -int
> -sqlite3OsSync(sqlite3_file * id, int flags)
> -{
> - DO_OS_MALLOC_TEST(id);
> - return id->pMethods->xSync(id, flags);
> -}
> -
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-07-02 11:22 ` [tarantool-patches] " Vladislav Shpilevoy
@ 2018-07-02 14:55 ` Kirill Shcherbatov
2018-07-02 18:29 ` Vladislav Shpilevoy
0 siblings, 1 reply; 9+ messages in thread
From: Kirill Shcherbatov @ 2018-07-02 14:55 UTC (permalink / raw)
To: tarantool-patches; +Cc: Vladislav Shpilevoy
> Hello. Thanks for the patch! See 2 comments below.
Hi! Thank you for review and fixes.
> 1. These functions still are visible in grep results.
> 2. And much more functions and constants are either unused, or just
> declared, but has no implementation. Please, complete the patch. I have
> pushed some of removals on the branch as a separate commit. Please,
> squash and finalize.
I've find a few functions to drop. Is it enough?
diff --git a/src/box/sql/os.c b/src/box/sql/os.c
index bec868b..7c11318 100644
--- a/src/box/sql/os.c
+++ b/src/box/sql/os.c
@@ -70,11 +70,7 @@ int sqlite3_open_file_count = 0;
*
* sqlite3OsRead()
* sqlite3OsWrite()
- * sqlite3OsShmMap()
* sqlite3OsOpen()
- * sqlite3OsDelete()
- * sqlite3OsAccess()
- * sqlite3OsFullPathname()
*
*/
#if defined(SQLITE_TEST)
diff --git a/src/box/sql/os.h b/src/box/sql/os.h
index aaadd80..9476583 100644
--- a/src/box/sql/os.h
+++ b/src/box/sql/os.h
@@ -41,13 +41,6 @@
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_
-/* If the SET_FULLSYNC macro is not defined above, then make it
- * a no-op
- */
-#ifndef SET_FULLSYNC
-#define SET_FULLSYNC(x,y)
-#endif
-
/*
* The default size of a disk sector
*/
@@ -128,11 +121,7 @@
* 1GB boundary.
*
*/
-#ifdef SQLITE_OMIT_WSD
-#define PENDING_BYTE (0x40000000)
-#else
#define PENDING_BYTE sqlite3PendingByte
-#endif
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
@@ -149,12 +138,6 @@ void sqlite3OsClose(sqlite3_file *);
int sqlite3OsRead(sqlite3_file *, void *, int amt, i64 offset);
int sqlite3OsWrite(sqlite3_file *, const void *, int amt, i64 offset);
void sqlite3OsFileControlHint(sqlite3_file *, int, void *);
-#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
-int sqlite3OsDeviceCharacteristics(sqlite3_file * id);
-int sqlite3OsShmMap(sqlite3_file *, int, int, int, void volatile **);
-int sqlite3OsShmLock(sqlite3_file * id, int, int, int);
-void sqlite3OsShmBarrier(sqlite3_file * id);
-int sqlite3OsShmUnmap(sqlite3_file * id, int);
int sqlite3OsFetch(sqlite3_file * id, i64, int, void **);
int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
@@ -162,14 +145,6 @@ int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
* Functions for accessing sqlite3_vfs methods
*/
int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int *);
-int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
-int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
-int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
-void sqlite3OsDlError(sqlite3_vfs *, int, char *);
-void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *)) (void);
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
int sqlite3OsSleep(sqlite3_vfs *, int);
int sqlite3OsGetLastError(sqlite3_vfs *);
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 5fb29c7..334a257 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -43,14 +43,6 @@
#include "box/schema.h"
#include "box/session.h"
-#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
-#if defined(__APPLE__)
-#define SQLITE_ENABLE_LOCKING_STYLE 1
-#else
-#define SQLITE_ENABLE_LOCKING_STYLE 0
-#endif
-#endif
-
/*
************************************************************************
* pragma.h contains several pragmas, including utf's pragmas.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-07-02 14:55 ` Kirill Shcherbatov
@ 2018-07-02 18:29 ` Vladislav Shpilevoy
2018-07-03 11:27 ` Kirill Shcherbatov
0 siblings, 1 reply; 9+ messages in thread
From: Vladislav Shpilevoy @ 2018-07-02 18:29 UTC (permalink / raw)
To: Kirill Shcherbatov, tarantool-patches
On 02/07/2018 17:55, Kirill Shcherbatov wrote:
>> Hello. Thanks for the patch! See 2 comments below.
> Hi! Thank you for review and fixes.
>
>> 1. These functions still are visible in grep results.
>> 2. And much more functions and constants are either unused, or just
>> declared, but has no implementation. Please, complete the patch. I have
>> pushed some of removals on the branch as a separate commit. Please,
>> squash and finalize.
> I've find a few functions to drop. Is it enough?
Unfortunately no. I have removed 642 lines in the patch I pushed on
the branch. Please, squash and then LGTM.
>
> diff --git a/src/box/sql/os.c b/src/box/sql/os.c
> index bec868b..7c11318 100644
> --- a/src/box/sql/os.c
> +++ b/src/box/sql/os.c
> @@ -70,11 +70,7 @@ int sqlite3_open_file_count = 0;
> *
> * sqlite3OsRead()
> * sqlite3OsWrite()
> - * sqlite3OsShmMap()
> * sqlite3OsOpen()
> - * sqlite3OsDelete()
> - * sqlite3OsAccess()
> - * sqlite3OsFullPathname()
> *
> */
> #if defined(SQLITE_TEST)
> diff --git a/src/box/sql/os.h b/src/box/sql/os.h
> index aaadd80..9476583 100644
> --- a/src/box/sql/os.h
> +++ b/src/box/sql/os.h
> @@ -41,13 +41,6 @@
> #ifndef _SQLITE_OS_H_
> #define _SQLITE_OS_H_
>
> -/* If the SET_FULLSYNC macro is not defined above, then make it
> - * a no-op
> - */
> -#ifndef SET_FULLSYNC
> -#define SET_FULLSYNC(x,y)
> -#endif
> -
> /*
> * The default size of a disk sector
> */
> @@ -128,11 +121,7 @@
> * 1GB boundary.
> *
> */
> -#ifdef SQLITE_OMIT_WSD
> -#define PENDING_BYTE (0x40000000)
> -#else
> #define PENDING_BYTE sqlite3PendingByte
> -#endif
> #define RESERVED_BYTE (PENDING_BYTE+1)
> #define SHARED_FIRST (PENDING_BYTE+2)
> #define SHARED_SIZE 510
> @@ -149,12 +138,6 @@ void sqlite3OsClose(sqlite3_file *);
> int sqlite3OsRead(sqlite3_file *, void *, int amt, i64 offset);
> int sqlite3OsWrite(sqlite3_file *, const void *, int amt, i64 offset);
> void sqlite3OsFileControlHint(sqlite3_file *, int, void *);
> -#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
> -int sqlite3OsDeviceCharacteristics(sqlite3_file * id);
> -int sqlite3OsShmMap(sqlite3_file *, int, int, int, void volatile **);
> -int sqlite3OsShmLock(sqlite3_file * id, int, int, int);
> -void sqlite3OsShmBarrier(sqlite3_file * id);
> -int sqlite3OsShmUnmap(sqlite3_file * id, int);
> int sqlite3OsFetch(sqlite3_file * id, i64, int, void **);
> int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
>
> @@ -162,14 +145,6 @@ int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
> * Functions for accessing sqlite3_vfs methods
> */
> int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int *);
> -int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
> -int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
> -int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
> -#ifndef SQLITE_OMIT_LOAD_EXTENSION
> -void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
> -void sqlite3OsDlError(sqlite3_vfs *, int, char *);
> -void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *)) (void);
> -#endif /* SQLITE_OMIT_LOAD_EXTENSION */
> int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
> int sqlite3OsSleep(sqlite3_vfs *, int);
> int sqlite3OsGetLastError(sqlite3_vfs *);
> diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
> index 5fb29c7..334a257 100644
> --- a/src/box/sql/pragma.c
> +++ b/src/box/sql/pragma.c
> @@ -43,14 +43,6 @@
> #include "box/schema.h"
> #include "box/session.h"
>
> -#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
> -#if defined(__APPLE__)
> -#define SQLITE_ENABLE_LOCKING_STYLE 1
> -#else
> -#define SQLITE_ENABLE_LOCKING_STYLE 0
> -#endif
> -#endif
> -
> /*
> ************************************************************************
> * pragma.h contains several pragmas, including utf's pragmas.
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-07-02 18:29 ` Vladislav Shpilevoy
@ 2018-07-03 11:27 ` Kirill Shcherbatov
2018-07-04 13:28 ` n.pettik
0 siblings, 1 reply; 9+ messages in thread
From: Kirill Shcherbatov @ 2018-07-03 11:27 UTC (permalink / raw)
To: tarantool-patches, Nikita Pettik; +Cc: Vladislav Shpilevoy
> Unfortunately no. I have removed 642 lines in the patch I pushed on
> the branch. Please, squash and then LGTM.
Thank you for review. I've have squashed your changes.
I've also tested branch on FreeBSD and returned missing LARGE_FILE macro definition.
Nikita, please, take a look.
==========================================
Resolves #3284.
---
src/box/sql/os.c | 154 --
src/box/sql/os.h | 38 +-
src/box/sql/os_unix.c | 6167 ++++++++---------------------------------------
src/box/sql/pragma.c | 8 -
src/box/sql/sqliteInt.h | 34 -
5 files changed, 1069 insertions(+), 5332 deletions(-)
diff --git a/src/box/sql/os.c b/src/box/sql/os.c
index 19841bf..7c11318 100644
--- a/src/box/sql/os.c
+++ b/src/box/sql/os.c
@@ -70,16 +70,7 @@ int sqlite3_open_file_count = 0;
*
* sqlite3OsRead()
* sqlite3OsWrite()
- * sqlite3OsSync()
- * sqlite3OsFileSize()
- * sqlite3OsLock()
- * sqlite3OsCheckReservedLock()
- * sqlite3OsFileControl()
- * sqlite3OsShmMap()
* sqlite3OsOpen()
- * sqlite3OsDelete()
- * sqlite3OsAccess()
- * sqlite3OsFullPathname()
*
*/
#if defined(SQLITE_TEST)
@@ -123,123 +114,12 @@ sqlite3OsWrite(sqlite3_file * id, const void *pBuf, int amt, i64 offset)
return id->pMethods->xWrite(id, pBuf, amt, offset);
}
-int
-sqlite3OsTruncate(sqlite3_file * id, i64 size)
-{
- return id->pMethods->xTruncate(id, size);
-}
-
-int
-sqlite3OsSync(sqlite3_file * id, int flags)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xSync(id, flags);
-}
-
-int
-sqlite3OsFileSize(sqlite3_file * id, i64 * pSize)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xFileSize(id, pSize);
-}
-
-int
-sqlite3OsLock(sqlite3_file * id, int lockType)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xLock(id, lockType);
-}
-
-int
-sqlite3OsUnlock(sqlite3_file * id, int lockType)
-{
- return id->pMethods->xUnlock(id, lockType);
-}
-
-int
-sqlite3OsCheckReservedLock(sqlite3_file * id, int *pResOut)
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xCheckReservedLock(id, pResOut);
-}
-
-/*
- * Use sqlite3OsFileControl() when we are doing something that might fail
- * and we need to know about the failures. Use sqlite3OsFileControlHint()
- * when simply tossing information over the wall to the VFS and we do not
- * really care if the VFS receives and understands the information since it
- * is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
- * routine has no return value since the return value would be meaningless.
- */
-int
-sqlite3OsFileControl(sqlite3_file * id, int op, void *pArg)
-{
-#ifdef SQLITE_TEST
- if (op != SQLITE_FCNTL_COMMIT_PHASETWO) {
- /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
- * is using a regular VFS, it is called after the corresponding
- * transaction has been committed. Injecting a fault at this point
- * confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
- * but the transaction is committed anyway.
- *
- * The core must call OsFileControl() though, not OsFileControlHint(),
- * as if a custom VFS (e.g. zipvfs) returns an error here, it probably
- * means the commit really has failed and an error should be returned
- * to the user.
- */
- DO_OS_MALLOC_TEST(id);
- }
-#endif
- return id->pMethods->xFileControl(id, op, pArg);
-}
-
void
sqlite3OsFileControlHint(sqlite3_file * id, int op, void *pArg)
{
(void)id->pMethods->xFileControl(id, op, pArg);
}
-int
-sqlite3OsSectorSize(sqlite3_file * id)
-{
- int (*xSectorSize) (sqlite3_file *) = id->pMethods->xSectorSize;
- return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
-}
-
-int
-sqlite3OsDeviceCharacteristics(sqlite3_file * id)
-{
- return id->pMethods->xDeviceCharacteristics(id);
-}
-
-int
-sqlite3OsShmLock(sqlite3_file * id, int offset, int n, int flags)
-{
- return id->pMethods->xShmLock(id, offset, n, flags);
-}
-
-void
-sqlite3OsShmBarrier(sqlite3_file * id)
-{
- id->pMethods->xShmBarrier(id);
-}
-
-int
-sqlite3OsShmUnmap(sqlite3_file * id, int deleteFlag)
-{
- return id->pMethods->xShmUnmap(id, deleteFlag);
-}
-
-int
-sqlite3OsShmMap(sqlite3_file * id, /* Database file handle */
- int iPage, int pgsz, int bExtend, /* True to extend file if necessary */
- void volatile **pp /* OUT: Pointer to mapping */
- )
-{
- DO_OS_MALLOC_TEST(id);
- return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
-}
-
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
int
@@ -296,30 +176,6 @@ sqlite3OsOpen(sqlite3_vfs * pVfs,
}
int
-sqlite3OsDelete(sqlite3_vfs * pVfs, const char *zPath, int dirSync)
-{
- DO_OS_MALLOC_TEST(0);
- assert(dirSync == 0 || dirSync == 1);
- return pVfs->xDelete(pVfs, zPath, dirSync);
-}
-
-int
-sqlite3OsAccess(sqlite3_vfs * pVfs, const char *zPath, int flags, int *pResOut)
-{
- DO_OS_MALLOC_TEST(0);
- return pVfs->xAccess(pVfs, zPath, flags, pResOut);
-}
-
-int
-sqlite3OsFullPathname(sqlite3_vfs * pVfs,
- const char *zPath, int nPathOut, char *zPathOut)
-{
- DO_OS_MALLOC_TEST(0);
- zPathOut[0] = 0;
- return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
-}
-
-int
sqlite3OsRandomness(sqlite3_vfs * pVfs, int nByte, char *zBufOut)
{
return pVfs->xRandomness(pVfs, nByte, zBufOut);
@@ -480,13 +336,3 @@ sqlite3_vfs_register(sqlite3_vfs * pVfs, int makeDflt)
assert(vfsList);
return SQLITE_OK;
}
-
-/*
- * Unregister a VFS so that it is no longer accessible.
- */
-int
-sqlite3_vfs_unregister(sqlite3_vfs * pVfs)
-{
- vfsUnlink(pVfs);
- return SQLITE_OK;
-}
diff --git a/src/box/sql/os.h b/src/box/sql/os.h
index 500b864..9476583 100644
--- a/src/box/sql/os.h
+++ b/src/box/sql/os.h
@@ -41,13 +41,6 @@
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_
-/* If the SET_FULLSYNC macro is not defined above, then make it
- * a no-op
- */
-#ifndef SET_FULLSYNC
-#define SET_FULLSYNC(x,y)
-#endif
-
/*
* The default size of a disk sector
*/
@@ -81,8 +74,7 @@
#endif
/*
- * The following values may be passed as the second argument to
- * sqlite3OsLock(). The various locks exhibit the following semantics:
+ * The various locks exhibit the following semantics:
*
* SHARED: Any number of processes may hold a SHARED lock simultaneously.
* RESERVED: A single process may hold a RESERVED lock on a file at
@@ -92,10 +84,9 @@
* SHARED locks may be obtained by other processes.
* EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
*
- * PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
- * process that requests an EXCLUSIVE lock may actually obtain a PENDING
- * lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
- * sqlite3OsLock().
+ * PENDING_LOCK A process that requests an EXCLUSIVE lock may
+ * actually obtain a PENDING lock. This can be upgraded to an
+ * EXCLUSIVE lock.
*/
#define NO_LOCK 0
#define SHARED_LOCK 1
@@ -130,11 +121,7 @@
* 1GB boundary.
*
*/
-#ifdef SQLITE_OMIT_WSD
-#define PENDING_BYTE (0x40000000)
-#else
#define PENDING_BYTE sqlite3PendingByte
-#endif
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
@@ -150,21 +137,7 @@ int sqlite3OsInit(void);
void sqlite3OsClose(sqlite3_file *);
int sqlite3OsRead(sqlite3_file *, void *, int amt, i64 offset);
int sqlite3OsWrite(sqlite3_file *, const void *, int amt, i64 offset);
-int sqlite3OsTruncate(sqlite3_file *, i64 size);
-int sqlite3OsSync(sqlite3_file *, int);
-int sqlite3OsFileSize(sqlite3_file *, i64 * pSize);
-int sqlite3OsLock(sqlite3_file *, int);
-int sqlite3OsUnlock(sqlite3_file *, int);
-int sqlite3OsCheckReservedLock(sqlite3_file * id, int *pResOut);
-int sqlite3OsFileControl(sqlite3_file *, int, void *);
void sqlite3OsFileControlHint(sqlite3_file *, int, void *);
-#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
-int sqlite3OsSectorSize(sqlite3_file * id);
-int sqlite3OsDeviceCharacteristics(sqlite3_file * id);
-int sqlite3OsShmMap(sqlite3_file *, int, int, int, void volatile **);
-int sqlite3OsShmLock(sqlite3_file * id, int, int, int);
-void sqlite3OsShmBarrier(sqlite3_file * id);
-int sqlite3OsShmUnmap(sqlite3_file * id, int);
int sqlite3OsFetch(sqlite3_file * id, i64, int, void **);
int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
@@ -172,9 +145,6 @@ int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
* Functions for accessing sqlite3_vfs methods
*/
int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int *);
-int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
-int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
-int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
int sqlite3OsSleep(sqlite3_vfs *, int);
int sqlite3OsGetLastError(sqlite3_vfs *);
diff --git a/src/box/sql/os_unix.c b/src/box/sql/os_unix.c
index 262d178..ce21e44 100644
--- a/src/box/sql/os_unix.c
+++ b/src/box/sql/os_unix.c
@@ -29,80 +29,7 @@
* SUCH DAMAGE.
*/
-/*
- *
- * This file contains the VFS implementation for unix-like operating systems.
- *
- * There are actually several different VFS implementations in this file.
- * The differences are in the way that file locking is done. The default
- * implementation uses Posix Advisory Locks. Alternative implementations
- * use flock(), dot-files, various proprietary locking schemas, or simply
- * skip locking all together.
- *
- * This source file is organized into divisions where the logic for various
- * subfunctions is contained within the appropriate division. PLEASE
- * KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
- * in the correct division and should be clearly labeled.
- *
- * The layout of divisions is as follows:
- *
- * * General-purpose declarations and utility functions.
- * * Various locking primitive implementations (all except proxy locking):
- * + for Posix Advisory Locks
- * + for no-op locks
- * + for dot-file locks
- * + for flock() locking
- * + for AFP filesystem locks (MacOSX only)
- * * sqlite3_file methods not associated with locking.
- * * Definitions of sqlite3_io_methods objects for all locking
- * methods plus "finder" functions for each locking method.
- * * sqlite3_vfs method implementations.
- * * Locking primitives for the proxy uber-locking-method. (MacOSX only)
- * * Definitions of sqlite3_vfs objects for all locking methods
- * plus implementations of sqlite3_os_init() and sqlite3_os_end().
- */
#include "sqliteInt.h"
-
-/*
- * There are various methods for file locking used for concurrency
- * control:
- *
- * 1. POSIX locking (the default),
- * 2. No locking,
- * 3. Dot-file locking,
- * 4. flock() locking,
- * 5. AFP locking (OSX only),
- * 6. proxy locking. (OSX only)
- *
- * Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE
- * is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic
- * selection of the appropriate locking style based on the filesystem
- * where the database is located.
- */
-#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
-#if defined(__APPLE__)
-#define SQLITE_ENABLE_LOCKING_STYLE 1
-#else
-#define SQLITE_ENABLE_LOCKING_STYLE 0
-#endif
-#endif
-
-/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
-#define HAVE_PREAD 1
-#define HAVE_PWRITE 1
-#endif
-#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
-#undef USE_PREAD
-#define USE_PREAD64 1
-#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
-#undef USE_PREAD64
-#define USE_PREAD 1
-#endif
-
-/*
- * standard include files.
- */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -110,28 +37,8 @@
#include <time.h>
#include <sys/time.h>
#include <errno.h>
-#if SQLITE_MAX_MMAP_SIZE>0
#include <sys/mman.h>
-#endif
-
-#if SQLITE_ENABLE_LOCKING_STYLE
-#include <sys/ioctl.h>
-#include <sys/file.h>
-#include <sys/param.h>
-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
-#include <sys/mount.h>
-#endif
-
-#ifdef HAVE_UTIME
-#include <utime.h>
-#endif
-/*
- * Allowed values of unixFile.fsFlags
- */
-#define SQLITE_FSFLAGS_IS_MSDOS 0x1
/*
* Default permissions when creating a new file
@@ -152,19 +59,6 @@
*/
#define MAX_PATHNAME 512
-/*
- * Maximum supported symbolic links
- */
-#define SQLITE_MAX_SYMLINKS 100
-
-/*
- * Only set the lastErrno if the error code is a real error and not
- * a normal expected return code of SQLITE_BUSY or SQLITE_OK
- */
-#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
-
-/* Forward references */
-typedef struct unixShm unixShm; /* Connection shared memory */
typedef struct unixShmNode unixShmNode; /* Shared memory instance */
typedef struct unixInodeInfo unixInodeInfo; /* An i-node */
typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */
@@ -194,44 +88,14 @@ struct unixFile {
unsigned char eFileLock; /* The type of lock held on this fd */
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
- void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
- unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
-#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch refs */
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
- int openFlags; /* The flags specified at open() */
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
- unsigned fsFlags; /* cached details from statfs() */
-#endif
-#ifdef SQLITE_DEBUG
- /* The next group of variables are used to track whether or not the
- * transaction counter in bytes 24-27 of database files are updated
- * whenever any part of the database changes. An assertion fault will
- * occur if a file is updated without also updating the transaction
- * counter. This test is made to avoid new problems similar to the
- * one described by ticket #3584.
- */
- unsigned char transCntrChng; /* True if the transaction counter changed */
- unsigned char dbUpdate; /* True if any part of database file changed */
- unsigned char inNormalWrite; /* True if in a normal write operation */
-
-#endif
-
-#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
};
/* This variable holds the process id (pid) from when the xRandomness()
@@ -245,11 +109,7 @@ static pid_t randomnessPid = 0;
*/
#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
-#ifndef SQLITE_DISABLE_DIRSYNC
#define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
-#else
-#define UNIXFILE_DIRSYNC 0x00
-#endif
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
@@ -262,6 +122,9 @@ static pid_t randomnessPid = 0;
/*
* Define various macros that are missing from some systems.
*/
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
@@ -272,293 +135,6 @@ static pid_t randomnessPid = 0;
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 0
#endif
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-/*
- * HAVE_MREMAP defaults to true on Linux and false everywhere else.
- */
-#if !defined(HAVE_MREMAP)
-#if defined(__linux__) && defined(_GNU_SOURCE)
-#define HAVE_MREMAP 1
-#else
-#define HAVE_MREMAP 0
-#endif
-#endif
-
-
-
-/*
- * Different Unix systems declare open() in different ways. Same use
- * open(const char*,int,mode_t). Others use open(const char*,int,...).
- * The difference is important when using a pointer to the function.
- *
- * The safest way to deal with the problem is to always use this wrapper
- * which always has the same well-defined interface.
- */
-static int
-posixOpen(const char *zFile, int flags, int mode)
-{
- return open(zFile, flags, mode);
-}
-
-/* Forward reference */
-static int openDirectory(const char *, int *);
-#if SQLITE_MAX_MMAP_SIZE > 0
-static int unixGetpagesize(void);
-#endif
-
-/*
- * Many system calls are accessed through pointer-to-functions so that
- * they may be overridden at runtime to facilitate fault injection during
- * testing and sandboxing. The following array holds the names and pointers
- * to all overrideable system calls.
- */
-static struct unix_syscall {
- const char *zName; /* Name of the system call */
- sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
- sqlite3_syscall_ptr pDefault; /* Default value */
-} aSyscall[] = {
- {
- "open", (sqlite3_syscall_ptr) posixOpen, 0},
-#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
- {
- "close", (sqlite3_syscall_ptr) close, 0},
-#define osClose ((int(*)(int))aSyscall[1].pCurrent)
- {
- "access", (sqlite3_syscall_ptr) access, 0},
-#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent)
- {
- "getcwd", (sqlite3_syscall_ptr) getcwd, 0},
-#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
- {
- "stat", (sqlite3_syscall_ptr) stat, 0},
-#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
- {
- "fstat", (sqlite3_syscall_ptr) fstat, 0},
-#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
- {
- "ftruncate", (sqlite3_syscall_ptr) ftruncate, 0},
-#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent)
- {
- "fcntl", (sqlite3_syscall_ptr) fcntl, 0},
-#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
- {
- "read", (sqlite3_syscall_ptr) read, 0},
-#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
-#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
- {
- "pread", (sqlite3_syscall_ptr) pread, 0},
-#else
- {
- "pread", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
-#if defined(USE_PREAD64)
- {
- "pread64", (sqlite3_syscall_ptr) pread64, 0},
-#else
- {
- "pread64", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
- {
- "write", (sqlite3_syscall_ptr) write, 0},
-#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
-#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
- {
- "pwrite", (sqlite3_syscall_ptr) pwrite, 0},
-#else
- {
- "pwrite", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
- aSyscall[12].pCurrent)
-#if defined(USE_PREAD64)
- {
- "pwrite64", (sqlite3_syscall_ptr) pwrite64, 0},
-#else
- {
- "pwrite64", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
- aSyscall[13].pCurrent)
- {
- "fchmod", (sqlite3_syscall_ptr) fchmod, 0},
-#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
- {
- "fallocate", (sqlite3_syscall_ptr) posix_fallocate, 0},
-#else
- {
- "fallocate", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent)
- {
- "unlink", (sqlite3_syscall_ptr) unlink, 0},
-#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent)
- {
- "openDirectory", (sqlite3_syscall_ptr) openDirectory, 0},
-#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent)
- {
- "mkdir", (sqlite3_syscall_ptr) mkdir, 0},
-#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
- {
- "rmdir", (sqlite3_syscall_ptr) rmdir, 0},
-#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
-#if defined(HAVE_FCHOWN)
- {
- "fchown", (sqlite3_syscall_ptr) fchown, 0},
-#else
- {
- "fchown", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
- {
- "geteuid", (sqlite3_syscall_ptr) geteuid, 0},
-#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
-
-#if SQLITE_MAX_MMAP_SIZE>0
- {
- "mmap", (sqlite3_syscall_ptr) mmap, 0},
-#else
- {
- "mmap", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
-#if SQLITE_MAX_MMAP_SIZE>0
- {
- "munmap", (sqlite3_syscall_ptr) munmap, 0},
-#else
- {
- "munmap", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
-#if HAVE_MREMAP && (SQLITE_MAX_MMAP_SIZE>0)
- {
- "mremap", (sqlite3_syscall_ptr) mremap, 0},
-#else
- {
- "mremap", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
-#if SQLITE_MAX_MMAP_SIZE>0
- {
- "getpagesize", (sqlite3_syscall_ptr) unixGetpagesize, 0},
-#else
- {
- "getpagesize", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
-#if defined(HAVE_READLINK)
- {
- "readlink", (sqlite3_syscall_ptr) readlink, 0},
-#else
- {
- "readlink", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
-#if defined(HAVE_LSTAT)
- {
- "lstat", (sqlite3_syscall_ptr) lstat, 0},
-#else
- {
- "lstat", (sqlite3_syscall_ptr) 0, 0},
-#endif
-#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
-}; /* End of the overrideable system calls */
-
-
-/*
- * This is the xSetSystemCall() method of sqlite3_vfs for all of the
- * "unix" VFSes. Return SQLITE_OK opon successfully updating the
- * system call pointer, or SQLITE_NOTFOUND if there is no configurable
- * system call named zName.
- */
-static int
-unixSetSystemCall(sqlite3_vfs * pNotUsed, /* The VFS pointer. Not used */
- const char *zName, /* Name of system call to override */
- sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
- )
-{
- unsigned int i;
- int rc = SQLITE_NOTFOUND;
-
- UNUSED_PARAMETER(pNotUsed);
- if (zName == 0) {
- /* If no zName is given, restore all system calls to their default
- * settings and return NULL
- */
- rc = SQLITE_OK;
- for (i = 0; i < sizeof(aSyscall) / sizeof(aSyscall[0]); i++) {
- if (aSyscall[i].pDefault) {
- aSyscall[i].pCurrent = aSyscall[i].pDefault;
- }
- }
- } else {
- /* If zName is specified, operate on only the one system call
- * specified.
- */
- for (i = 0; i < sizeof(aSyscall) / sizeof(aSyscall[0]); i++) {
- if (strcmp(zName, aSyscall[i].zName) == 0) {
- if (aSyscall[i].pDefault == 0) {
- aSyscall[i].pDefault =
- aSyscall[i].pCurrent;
- }
- rc = SQLITE_OK;
- if (pNewFunc == 0)
- pNewFunc = aSyscall[i].pDefault;
- aSyscall[i].pCurrent = pNewFunc;
- break;
- }
- }
- }
- return rc;
-}
-
-/*
- * Return the value of a system call. Return NULL if zName is not a
- * recognized system call name. NULL is also returned if the system call
- * is currently undefined.
- */
-static sqlite3_syscall_ptr
-unixGetSystemCall(sqlite3_vfs * pNotUsed, const char *zName)
-{
- unsigned int i;
-
- UNUSED_PARAMETER(pNotUsed);
- for (i = 0; i < sizeof(aSyscall) / sizeof(aSyscall[0]); i++) {
- if (strcmp(zName, aSyscall[i].zName) == 0)
- return aSyscall[i].pCurrent;
- }
- return 0;
-}
-
-/*
- * Return the name of the first system call after zName. If zName==NULL
- * then return the name of the first system call. Return NULL if zName
- * is the last system call or if zName is not the name of a valid
- * system call.
- */
-static const char *
-unixNextSystemCall(sqlite3_vfs * p, const char *zName)
-{
- int i = -1;
-
- UNUSED_PARAMETER(p);
- if (zName) {
- for (i = 0; i < ArraySize(aSyscall) - 1; i++) {
- if (strcmp(zName, aSyscall[i].zName) == 0)
- break;
- }
- }
- for (i++; i < ArraySize(aSyscall); i++) {
- if (aSyscall[i].pCurrent != 0)
- return aSyscall[i].zName;
- }
- return 0;
-}
/*
* Do not accept any file descriptor less than this value, in order to avoid
@@ -592,11 +168,7 @@ robust_open(const char *z, int f, mode_t m)
int fd;
mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
while (1) {
-#if defined(O_CLOEXEC)
- fd = osOpen(z, f | O_CLOEXEC, m2);
-#else
- fd = osOpen(z, f, m2);
-#endif
+ fd = open(z, f | O_CLOEXEC, m2);
if (fd < 0) {
if (errno == EINTR)
continue;
@@ -604,95 +176,26 @@ robust_open(const char *z, int f, mode_t m)
}
if (fd >= SQLITE_MINIMUM_FILE_DESCRIPTOR)
break;
- osClose(fd);
+ close(fd);
sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z,
fd);
fd = -1;
- if (osOpen("/dev/null", f, m) < 0)
+ if (open("/dev/null", f, m) < 0)
break;
}
if (fd >= 0) {
if (m != 0) {
struct stat statbuf;
- if (osFstat(fd, &statbuf) == 0
- && statbuf.st_size == 0
- && (statbuf.st_mode & 0777) != m) {
- osFchmod(fd, m);
- }
+ if (fstat(fd, &statbuf) == 0 &&
+ statbuf.st_size == 0 &&
+ (statbuf.st_mode & 0777) != m)
+ fchmod(fd, m);
}
-#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
}
return fd;
}
-#ifdef SQLITE_LOCK_TRACE
-/*
- * Print out information about all locking operations.
- *
- * This routine is used for troubleshooting locks on multithreaded
- * platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE
- * command-line option on the compiler. This code is normally
- * turned off.
- */
-static int
-lockTrace(int fd, int op, struct flock *p)
-{
- char *zOpName, *zType;
- int s;
- int savedErrno;
- if (op == F_GETLK) {
- zOpName = "GETLK";
- } else if (op == F_SETLK) {
- zOpName = "SETLK";
- } else {
- s = osFcntl(fd, op, p);
- sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
- return s;
- }
- if (p->l_type == F_RDLCK) {
- zType = "RDLCK";
- } else if (p->l_type == F_WRLCK) {
- zType = "WRLCK";
- } else if (p->l_type == F_UNLCK) {
- zType = "UNLCK";
- } else {
- assert(0);
- }
- assert(p->l_whence == SEEK_SET);
- s = osFcntl(fd, op, p);
- savedErrno = errno;
- sqlite3DebugPrintf("fcntl %d %s %s %d %d %d %d\n",
- fd, zOpName, zType, (int)p->l_start,
- (int)p->l_len, (int)p->l_pid, s);
- if (s == (-1) && op == F_SETLK
- && (p->l_type == F_RDLCK || p->l_type == F_WRLCK)) {
- struct flock l2;
- l2 = *p;
- osFcntl(fd, F_GETLK, &l2);
- if (l2.l_type == F_RDLCK) {
- zType = "RDLCK";
- } else if (l2.l_type == F_WRLCK) {
- zType = "WRLCK";
- } else if (l2.l_type == F_UNLCK) {
- zType = "UNLCK";
- } else {
- assert(0);
- }
- sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n",
- zType, (int)l2.l_start, (int)l2.l_len,
- (int)l2.l_pid);
- }
- errno = savedErrno;
- return s;
-}
-
-#undef osFcntl
-#define osFcntl lockTrace
-#endif /* SQLITE_LOCK_TRACE */
-
/*
* Retry ftruncate() calls that fail due to EINTR
*
@@ -704,48 +207,11 @@ robust_ftruncate(int h, sqlite3_int64 sz)
{
int rc;
do {
- rc = osFtruncate(h, sz);
+ rc = ftruncate(h, sz);
} while (rc < 0 && errno == EINTR);
return rc;
}
-/*
- * This routine translates a standard POSIX errno code into something
- * useful to the clients of the sqlite3 functions. Specifically, it is
- * intended to translate a variety of "try again" errors into SQLITE_BUSY
- * and a variety of "please close the file descriptor NOW" errors into
- * SQLITE_IOERR
- *
- * Errors during initialization of locks, or file system support for locks,
- * should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
- */
-static int
-sqliteErrorFromPosixError(int posixError, int sqliteIOErr)
-{
- assert((sqliteIOErr == SQLITE_IOERR_LOCK) ||
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
- (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
- (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK));
- switch (posixError) {
- case EACCES:
- case EAGAIN:
- case ETIMEDOUT:
- case EBUSY:
- case EINTR:
- case ENOLCK:
- /* random NFS retry error, unless during file system support
- * introspection, in which it actually means what it says
- */
- return SQLITE_BUSY;
-
- case EPERM:
- return SQLITE_PERM;
-
- default:
- return sqliteIOErr;
- }
-}
-
/******************************************************************************
************************** Posix Advisory Locking ****************************
*
@@ -861,9 +327,6 @@ struct unixInodeInfo {
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
unixInodeInfo *pPrev; /* .... doubly linked */
-#if SQLITE_ENABLE_LOCKING_STYLE
- unsigned long long sharedByte; /* for AFP simulated shared lock */
-#endif
};
/*
@@ -925,7 +388,7 @@ unixLogErrorAtLine(int errcode, /* SQLite error code */
static void
robust_close(unixFile * pFile, int h, int lineno)
{
- if (osClose(h)) {
+ if (close(h) != 0) {
unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
pFile ? pFile->zPath : 0, lineno);
}
@@ -1008,38 +471,11 @@ findInodeInfo(unixFile * pFile, /* Unix file with file desc used in the key */
* create a unique name for the file.
*/
fd = pFile->h;
- rc = osFstat(fd, &statbuf);
+ rc = fstat(fd, &statbuf);
if (rc != 0) {
storeLastErrno(pFile, errno);
return SQLITE_IOERR;
}
-#ifdef __APPLE__
- /* On OS X on an msdos filesystem, the inode number is reported
- * incorrectly for zero-size files. See ticket #3260. To work
- * around this problem (we consider it a bug in OS X, not SQLite)
- * we always increase the file size to 1 by writing a single byte
- * prior to accessing the inode number. The one byte written is
- * an ASCII 'S' character which also happens to be the first byte
- * in the header of every SQLite database. In this way, if there
- * is a race condition such that another thread has already populated
- * the first page of the database, no damage is done.
- */
- if (statbuf.st_size == 0
- && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) {
- do {
- rc = osWrite(fd, "S", 1);
- } while (rc < 0 && errno == EINTR);
- if (rc != 1) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR;
- }
- rc = osFstat(fd, &statbuf);
- if (rc != 0) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR;
- }
- }
-#endif
memset(&fileId, 0, sizeof(fileId));
fileId.dev = statbuf.st_dev;
@@ -1075,9 +511,9 @@ static int
fileHasMoved(unixFile * pFile)
{
struct stat buf;
- return pFile->pInode != 0 &&
- (osStat(pFile->zPath, &buf) != 0
- || (u64) buf.st_ino != pFile->pInode->fileId.ino);
+ return pFile->pInode != NULL && (stat(pFile->zPath, &buf) != 0 ||
+ (u64) buf.st_ino !=
+ pFile->pInode->fileId.ino);
}
/*
@@ -1099,7 +535,7 @@ verifyDbFile(unixFile * pFile)
if (pFile->ctrlFlags & UNIXFILE_NOLOCK)
return;
- rc = osFstat(pFile->h, &buf);
+ rc = fstat(pFile->h, &buf);
if (rc != 0) {
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s",
pFile->zPath);
@@ -1123,34 +559,6 @@ verifyDbFile(unixFile * pFile)
}
/*
- * 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
-unixCheckReservedLock(sqlite3_file * id, int *pResOut)
-{
- int rc = SQLITE_OK;
- int reserved = 0;
- unixFile *pFile = (unixFile *) id;
-
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
-
- assert(pFile);
- assert(pFile->eFileLock <= SHARED_LOCK);
-
- /* Check if a thread in this process holds such a lock */
- if (pFile->pInode->eFileLock > SHARED_LOCK) {
- reserved = 1;
- }
-
- *pResOut = reserved;
- return rc;
-}
-
-/*
* Attempt to set a system-lock on the file pFile. The lock is
* described by pLock.
*
@@ -1184,7 +592,7 @@ unixFileLock(unixFile * pFile, struct flock *pLock)
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
lock.l_type = F_WRLCK;
- rc = osFcntl(pFile->h, F_SETLK, &lock);
+ rc = fcntl(pFile->h, F_SETLK, &lock);
if (rc < 0)
return rc;
pInode->bProcessLock = 1;
@@ -1193,235 +601,8 @@ unixFileLock(unixFile * pFile, struct flock *pLock)
rc = 0;
}
} else {
- rc = osFcntl(pFile->h, F_SETLK, pLock);
- }
- return rc;
-}
-
-/*
- * Lock the file with the lock specified by parameter eFileLock - 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
-unixLock(sqlite3_file * id, int eFileLock)
-{
- /* 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
- * confusion with SQLite lock names).
- *
- * Symbols defined in os.h indentify the 'pending byte' and the 'reserved
- * byte', each single bytes at well known offsets, and the 'shared byte
- * range', a range of 510 bytes at a well known offset.
- *
- * To obtain a SHARED lock, a read-lock is obtained on the 'pending
- * byte'. If this is successful, 'shared byte range' is read-locked
- * and the lock on the 'pending byte' released.
- *
- * A process may only obtain a RESERVED lock after it has a SHARED lock.
- * A RESERVED lock is implemented by grabbing a write-lock on the
- * 'reserved byte'.
- *
- * A process may only obtain a PENDING lock after it has obtained a
- * SHARED lock. A PENDING lock is implemented by obtaining a write-lock
- * on the 'pending byte'. This ensures that no new SHARED locks can be
- * obtained, but existing SHARED locks are allowed to persist. A process
- * does not have to obtain a RESERVED lock on the way to a PENDING lock.
- * This property is used by the algorithm for rolling back a journal file
- * after a crash.
- *
- * An EXCLUSIVE lock, obtained after a PENDING lock is held, is
- * implemented by obtaining a write-lock on the entire 'shared byte
- * range'. Since all other locks require a read-lock on one of the bytes
- * within this range, this ensures that no other locks are held on the
- * database.
- */
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
- unixInodeInfo *pInode;
- struct flock lock;
- int tErrno = 0;
-
- assert(pFile);
-
- /* If there is already a lock of this type or more restrictive on the
- * unixFile, do nothing.
- */
- if (pFile->eFileLock >= eFileLock)
- return SQLITE_OK;
-
- /* Make sure the locking sequence is correct.
- * (1) We never move from unlocked to anything higher than shared lock.
- * (2) SQLite never explicitly requests a pendig lock.
- * (3) A shared lock is always held when a reserve lock is requested.
- */
- assert(pFile->eFileLock != NO_LOCK || eFileLock == SHARED_LOCK);
- assert(eFileLock != PENDING_LOCK);
- assert(eFileLock != RESERVED_LOCK || pFile->eFileLock == SHARED_LOCK);
-
- pInode = pFile->pInode;
-
- /* If some thread using this PID has a lock via a different unixFile*
- * handle that precludes the requested lock, return BUSY.
- */
- if ((pFile->eFileLock != pInode->eFileLock &&
- (pInode->eFileLock >= PENDING_LOCK || eFileLock > SHARED_LOCK))
- ) {
- rc = SQLITE_BUSY;
- goto end_lock;
- }
-
- /* If a SHARED lock is requested, and some thread using this PID already
- * has a SHARED or RESERVED lock, then increment reference counts and
- * return SQLITE_OK.
- */
- if (eFileLock == SHARED_LOCK &&
- (pInode->eFileLock == SHARED_LOCK
- || pInode->eFileLock == RESERVED_LOCK)) {
- assert(eFileLock == SHARED_LOCK);
- assert(pFile->eFileLock == 0);
- assert(pInode->nShared > 0);
- pFile->eFileLock = SHARED_LOCK;
- pInode->nShared++;
- pInode->nLock++;
- goto end_lock;
- }
-
- /* 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.
- */
- lock.l_len = 1L;
- lock.l_whence = SEEK_SET;
- if (eFileLock == SHARED_LOCK
- || (eFileLock == EXCLUSIVE_LOCK && pFile->eFileLock < PENDING_LOCK)
- ) {
- lock.l_type = (eFileLock == SHARED_LOCK ? F_RDLCK : F_WRLCK);
- lock.l_start = PENDING_BYTE;
- if (unixFileLock(pFile, &lock)) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- if (rc != SQLITE_BUSY) {
- storeLastErrno(pFile, tErrno);
- }
- goto end_lock;
- }
- }
-
- /* If control gets to this point, then actually go ahead and make
- * operating system calls for the specified lock.
- */
- if (eFileLock == SHARED_LOCK) {
- assert(pInode->nShared == 0);
- assert(pInode->eFileLock == 0);
- assert(rc == SQLITE_OK);
-
- /* Now get the read-lock */
- lock.l_start = SHARED_FIRST;
- lock.l_len = SHARED_SIZE;
- if (unixFileLock(pFile, &lock)) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- }
-
- /* Drop the temporary PENDING lock */
- lock.l_start = PENDING_BYTE;
- lock.l_len = 1L;
- lock.l_type = F_UNLCK;
- if (unixFileLock(pFile, &lock) && rc == SQLITE_OK) {
- /* This could happen with a network mount */
- tErrno = errno;
- rc = SQLITE_IOERR_UNLOCK;
- }
-
- if (rc) {
- if (rc != SQLITE_BUSY) {
- storeLastErrno(pFile, tErrno);
- }
- goto end_lock;
- } else {
- pFile->eFileLock = SHARED_LOCK;
- pInode->nLock++;
- pInode->nShared = 1;
- }
- } else if (eFileLock == EXCLUSIVE_LOCK && pInode->nShared > 1) {
- /* We are trying for an exclusive lock but another thread in this
- * same process is still holding a shared lock.
- */
- rc = SQLITE_BUSY;
- } 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.
- */
- assert(0 != pFile->eFileLock);
- lock.l_type = F_WRLCK;
-
- assert(eFileLock == RESERVED_LOCK
- || eFileLock == EXCLUSIVE_LOCK);
- if (eFileLock == RESERVED_LOCK) {
- lock.l_start = RESERVED_BYTE;
- lock.l_len = 1L;
- } else {
- lock.l_start = SHARED_FIRST;
- lock.l_len = SHARED_SIZE;
- }
-
- if (unixFileLock(pFile, &lock)) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- if (rc != SQLITE_BUSY) {
- storeLastErrno(pFile, tErrno);
- }
- }
- }
-
-#ifdef SQLITE_DEBUG
- /* Set up the transaction-counter change checking flags when
- * transitioning from a SHARED to a RESERVED lock. The change
- * from SHARED to RESERVED marks the beginning of a normal
- * write operation.
- */
- if (rc == SQLITE_OK
- && pFile->eFileLock <= SHARED_LOCK && eFileLock == RESERVED_LOCK) {
- pFile->transCntrChng = 0;
- pFile->dbUpdate = 0;
- pFile->inNormalWrite = 1;
+ rc = fcntl(pFile->h, F_SETLK, pLock);
}
-#endif
-
- if (rc == SQLITE_OK) {
- pFile->eFileLock = eFileLock;
- pInode->eFileLock = eFileLock;
- } else if (eFileLock == EXCLUSIVE_LOCK) {
- pFile->eFileLock = PENDING_LOCK;
- pInode->eFileLock = PENDING_LOCK;
- }
-
- end_lock:
return rc;
}
@@ -1472,18 +653,6 @@ posixUnlock(sqlite3_file * id, int eFileLock, int handleNFSUnlock)
if (pFile->eFileLock > SHARED_LOCK) {
assert(pInode->eFileLock == pFile->eFileLock);
-#ifdef SQLITE_DEBUG
- /* When reducing a lock such that other processes can start
- * reading the database file again, make sure that the
- * transaction counter was updated if any part of the database
- * file changed. If the transaction counter is not updated,
- * other connections to the same file might not realize that
- * the file has changed and hence might not know to flush their
- * cache. The use of a stale cache can lead to database corruption.
- */
- pFile->inNormalWrite = 0;
-#endif
-
/* downgrading to a shared lock on NFS involves clearing the write lock
* before establishing the readlock - to avoid a race condition we downgrade
* the lock in 2 blocks, so that part of the range will be covered by a
@@ -1494,50 +663,8 @@ posixUnlock(sqlite3_file * id, int eFileLock, int handleNFSUnlock)
* 4: [RRRR.]
*/
if (eFileLock == SHARED_LOCK) {
-#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
(void)handleNFSUnlock;
assert(handleNFSUnlock == 0);
-#endif
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- if (handleNFSUnlock) {
- int tErrno; /* Error code from system call errors */
- off_t divSize = SHARED_SIZE - 1;
-
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST;
- lock.l_len = divSize;
- if (unixFileLock(pFile, &lock) == (-1)) {
- tErrno = errno;
- rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- goto end_unlock;
- }
- lock.l_type = F_RDLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST;
- lock.l_len = divSize;
- if (unixFileLock(pFile, &lock) == (-1)) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_RDLOCK);
- if (IS_LOCK_ERROR(rc)) {
- storeLastErrno(pFile, tErrno);
- }
- goto end_unlock;
- }
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SHARED_FIRST + divSize;
- lock.l_len = SHARED_SIZE - divSize;
- if (unixFileLock(pFile, &lock) == (-1)) {
- tErrno = errno;
- rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- goto end_unlock;
- }
- } else
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
{
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
@@ -1617,16 +744,12 @@ posixUnlock(sqlite3_file * id, int eFileLock, int handleNFSUnlock)
static int
unixUnlock(sqlite3_file * id, int eFileLock)
{
-#if SQLITE_MAX_MMAP_SIZE>0
assert(eFileLock == SHARED_LOCK || ((unixFile *) id)->nFetchOut == 0);
-#endif
return posixUnlock(id, eFileLock, 0);
}
-#if SQLITE_MAX_MMAP_SIZE>0
static int unixMapfile(unixFile * pFd, i64 nByte);
static void unixUnmapfile(unixFile * pFd);
-#endif
/*
* This function performs the parts of the "close file" operation
@@ -1645,13 +768,6 @@ closeUnixFile(sqlite3_file * id)
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
}
-#ifdef SQLITE_UNLINK_AFTER_CLOSE
- if (pFile->ctrlFlags & UNIXFILE_DELETE) {
- osUnlink(pFile->zPath);
- sqlite3_free(*(char **)&pFile->zPath);
- pFile->zPath = 0;
- }
-#endif
OpenCounter(-1);
sqlite3_free(pFile->pUnused);
memset(pFile, 0, sizeof(unixFile));
@@ -1689,45 +805,6 @@ unixClose(sqlite3_file * id)
/************** End of the posix advisory lock implementation *****************
*****************************************************************************/
-/******************************************************************************
- ***************************** No-op Locking **********************************
- *
- * Of the various locking implementations available, this is by far the
- * simplest: locking is ignored. No attempt is made to lock the database
- * file for reading or writing.
- *
- * This locking mode is appropriate for use on read-only databases
- * (ex: databases that are burned into CD-ROM, for example.) It can
- * also be used if the application employs some external mechanism to
- * prevent simultaneous access of the same database by two or more
- * database connections. But there is a serious risk of database
- * corruption if this locking mode is used in situations where multiple
- * database connections are accessing the same database file at the same
- * time and one or more of those connections are writing.
- */
-
-static int
-nolockCheckReservedLock(sqlite3_file * NotUsed, int *pResOut)
-{
- UNUSED_PARAMETER(NotUsed);
- *pResOut = 0;
- return SQLITE_OK;
-}
-
-static int
-nolockLock(sqlite3_file * NotUsed, int NotUsed2)
-{
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
- return SQLITE_OK;
-}
-
-static int
-nolockUnlock(sqlite3_file * NotUsed, int NotUsed2)
-{
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
- return SQLITE_OK;
-}
-
/*
* Close the file.
*/
@@ -1737,4396 +814,1330 @@ nolockClose(sqlite3_file * id)
return closeUnixFile(id);
}
-/******************* End of the no-op lock implementation *********************
+
+/******************* End of the non-op lock implementation *******************
*****************************************************************************/
/******************************************************************************
- ************************ Begin dot-file Locking ******************************
- *
- * The dotfile locking implementation uses the existence of separate lock
- * files (really a directory) to control access to the database. This works
- * on just about every filesystem imaginable. But there are serious downsides:
- *
- * (1) There is zero concurrency. A single reader blocks all other
- * connections from reading or writing the database.
- *
- * (2) An application crash or power loss can leave stale lock files
- * sitting around that need to be cleared manually.
- *
- * Nevertheless, a dotlock is an appropriate locking mode for use if no
- * other locking strategy is available.
- *
- * Dotfile locking works by creating a subdirectory in the same directory as
- * the database and with the same name but with a ".lock" extension added.
- * The existence of a lock directory implies an EXCLUSIVE lock. All other
- * lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
- */
-
-/*
- * The file suffix added to the data base filename in order to create the
- * lock directory.
- */
-#define DOTLOCK_SUFFIX ".lock"
-
-/*
- * 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.
+ *************** Non-locking sqlite3_file methods *****************************
*
- * In dotfile locking, either a lock exists or it does not. So in this
- * variation of CheckReservedLock(), *pResOut is set to true if any lock
- * is held on the file and false if the file is unlocked.
+ * The next division contains implementations for all methods of the
+ * sqlite3_file object other than the locking methods. The locking
+ * methods were defined in divisions above (one locking method per
+ * division). Those methods that are common to all locking modes
+ * are gather together into this division.
*/
-static int
-dotlockCheckReservedLock(sqlite3_file * id, int *pResOut)
-{
- int rc = SQLITE_OK;
- int reserved = 0;
- unixFile *pFile = (unixFile *) id;
-
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
-
- assert(pFile);
- reserved = osAccess((const char *)pFile->lockingContext, 0) == 0;
- *pResOut = reserved;
- return rc;
-}
/*
- * Lock the file with the lock specified by parameter eFileLock - 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
+ * Seek to the offset passed as the second argument, then read cnt
+ * bytes into pBuf. Return the number of bytes actually read.
*
- * This routine will only increase a lock. Use the sqlite3OsUnlock()
- * routine to lower a locking level.
+ * 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
+ * in any form by default, we will not attempt to define _XOPEN_SOURCE.
+ * See tickets #2741 and #2681.
*
- * With dotfile locking, we really only support state (4): EXCLUSIVE.
- * But we track the other locking levels internally.
+ * To avoid stomping the errno value on a failed read the lastErrno value
+ * is set before returning.
*/
static int
-dotlockLock(sqlite3_file * id, int eFileLock)
+seekAndRead(unixFile * id, sqlite3_int64 offset, void *pBuf, int cnt)
{
- unixFile *pFile = (unixFile *) id;
- char *zLockFile = (char *)pFile->lockingContext;
- int rc;
-
- /* If we have any lock, then the lock file already exists. All we have
- * to do is adjust our internal record of the lock level.
- */
- if (pFile->eFileLock > NO_LOCK) {
- pFile->eFileLock = eFileLock;
- /* Always update the timestamp on the old file */
-#ifdef HAVE_UTIME
- utime(zLockFile, NULL);
-#else
- utimes(zLockFile, NULL);
-#endif
- return SQLITE_OK;
- }
+ int got;
+ int prior = 0;
+ i64 newOffset;
- /* grab an exclusive lock */
- rc = osMkdir(zLockFile, 0777);
- if (rc < 0) {
- /* failed to open/create the lock directory */
- int tErrno = errno;
- if (EEXIST == tErrno) {
- rc = SQLITE_BUSY;
- } else {
- rc = sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- if (rc != SQLITE_BUSY) {
- storeLastErrno(pFile, tErrno);
+ assert(cnt == (cnt & 0x1ffff));
+ assert(id->h > 2);
+ do {
+ newOffset = lseek(id->h, offset, SEEK_SET);
+ SimulateIOError(newOffset = -1);
+ if (newOffset < 0) {
+ storeLastErrno((unixFile *) id, errno);
+ return -1;
+ }
+ got = read(id->h, pBuf, cnt);
+ if (got == cnt)
+ break;
+ if (got < 0) {
+ if (errno == EINTR) {
+ got = 1;
+ continue;
}
+ prior = 0;
+ storeLastErrno((unixFile *) id, errno);
+ break;
+ } else if (got > 0) {
+ cnt -= got;
+ offset += got;
+ prior += got;
+ pBuf = (void *)(got + (char *)pBuf);
}
- return rc;
- }
-
- /* got it, set the type and return ok */
- pFile->eFileLock = eFileLock;
- return rc;
+ } while (got > 0);
+ return got + prior;
}
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * 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.
- *
- * When the locking level reaches NO_LOCK, delete the lock file.
+ * Read data from a file into a buffer. Return SQLITE_OK if all
+ * bytes were read successfully and SQLITE_IOERR if anything goes
+ * wrong.
*/
static int
-dotlockUnlock(sqlite3_file * id, int eFileLock)
+unixRead(sqlite3_file * id, void *pBuf, int amt, sqlite3_int64 offset)
{
unixFile *pFile = (unixFile *) id;
- char *zLockFile = (char *)pFile->lockingContext;
- int rc;
-
- assert(pFile);
- assert(eFileLock <= SHARED_LOCK);
-
- /* no-op if possible */
- if (pFile->eFileLock == eFileLock) {
- return SQLITE_OK;
- }
+ int got;
+ assert(id);
+ assert(offset >= 0);
+ assert(amt > 0);
- /* To downgrade to shared, simply update our internal notion of the
- * lock state. No need to mess with the file on disk.
+#if SQLITE_MAX_MMAP_SIZE>0
+ /* Deal with as much of this read request as possible by transfering
+ * data from the memory mapping using memcpy().
*/
- if (eFileLock == SHARED_LOCK) {
- pFile->eFileLock = SHARED_LOCK;
- return SQLITE_OK;
- }
-
- /* To fully unlock the database, delete the lock file */
- assert(eFileLock == NO_LOCK);
- rc = osRmdir(zLockFile);
- if (rc < 0) {
- int tErrno = errno;
- if (tErrno == ENOENT) {
- rc = SQLITE_OK;
+ if (offset < pFile->mmapSize) {
+ if (offset + amt <= pFile->mmapSize) {
+ memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
+ amt);
+ return SQLITE_OK;
} else {
- rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
+ int nCopy = pFile->mmapSize - offset;
+ memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
+ nCopy);
+ pBuf = &((u8 *) pBuf)[nCopy];
+ amt -= nCopy;
+ offset += nCopy;
}
- return rc;
}
- pFile->eFileLock = NO_LOCK;
- return SQLITE_OK;
+#endif
+
+ got = seekAndRead(pFile, offset, pBuf, amt);
+ if (got == amt) {
+ return SQLITE_OK;
+ } else if (got < 0) {
+ /* lastErrno set by seekAndRead */
+ return SQLITE_IOERR_READ;
+ } else {
+ storeLastErrno(pFile, 0); /* not a system error */
+ /* Unread parts of the buffer must be zero-filled */
+ memset(&((char *)pBuf)[got], 0, amt - got);
+ return SQLITE_IOERR_SHORT_READ;
+ }
}
/*
- * Close a file. Make sure the lock has been released before closing.
+ * Attempt to seek the file-descriptor passed as the first argument to
+ * absolute offset iOff, then attempt to write nBuf bytes of data from
+ * pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
+ * return the actual number of bytes written (which may be less than
+ * nBuf).
*/
static int
-dotlockClose(sqlite3_file * id)
+seekAndWriteFd(int fd, /* File descriptor to write to */
+ i64 iOff, /* File offset to begin writing at */
+ const void *pBuf, /* Copy data from this buffer to the file */
+ int nBuf, /* Size of buffer pBuf in bytes */
+ int *piErrno /* OUT: Error number if error occurs */
+ )
{
- unixFile *pFile = (unixFile *) id;
- assert(id != 0);
- dotlockUnlock(id, NO_LOCK);
- sqlite3_free(pFile->lockingContext);
- return closeUnixFile(id);
-}
+ int rc = 0; /* Value returned by system call */
-/****************** End of the dot-file lock implementation *******************
- *****************************************************************************/
+ assert(nBuf == (nBuf & 0x1ffff));
+ assert(fd > 2);
+ assert(piErrno != 0);
+ nBuf &= 0x1ffff;
+ do {
+ i64 iSeek = lseek(fd, iOff, SEEK_SET);
+ SimulateIOError(iSeek = -1);
+ if (iSeek < 0) {
+ rc = -1;
+ break;
+ }
+ rc = write(fd, pBuf, nBuf);
+ } while (rc < 0 && errno == EINTR);
-/******************************************************************************
- ************************* Begin flock Locking ********************************
- *
- * 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
- */
-#if SQLITE_ENABLE_LOCKING_STYLE
+ if (rc < 0)
+ *piErrno = errno;
+ return rc;
+}
/*
- * Retry flock() calls that fail with EINTR
+ * Seek to the offset in id->offset then read cnt bytes into pBuf.
+ * Return the number of bytes actually read. Update the offset.
+ *
+ * To avoid stomping the errno value on a failed write the lastErrno value
+ * is set before returning.
*/
-#ifdef EINTR
static int
-robust_flock(int fd, int op)
+seekAndWrite(unixFile * id, i64 offset, const void *pBuf, int cnt)
{
- int rc;
- do {
- rc = flock(fd, op);
- } while (rc < 0 && errno == EINTR);
- return rc;
+ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
}
-#else
-#define robust_flock(a,b) flock(a,b)
-#endif
/*
- * 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.
+ * Write data from a buffer into a file. Return SQLITE_OK on success
+ * or some other error code on failure.
*/
static int
-flockCheckReservedLock(sqlite3_file * id, int *pResOut)
+unixWrite(sqlite3_file * id, const void *pBuf, int amt, sqlite3_int64 offset)
{
- int rc = SQLITE_OK;
- int reserved = 0;
unixFile *pFile = (unixFile *) id;
+ int wrote = 0;
+ assert(id);
+ assert(amt > 0);
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
-
- assert(pFile);
-
- /* Check if a thread in this process holds such a lock */
- if (pFile->eFileLock > SHARED_LOCK) {
- reserved = 1;
+ while ((wrote = seekAndWrite(pFile, offset, pBuf, amt)) < amt
+ && wrote > 0) {
+ amt -= wrote;
+ offset += wrote;
+ pBuf = &((char *)pBuf)[wrote];
}
+ SimulateIOError((wrote = (-1), amt = 1));
+ SimulateDiskfullError((wrote = 0, amt = 1));
- /* Otherwise see if some other process holds it. */
- if (!reserved) {
- /* attempt to get the lock */
- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
- if (!lrc) {
- /* got the lock, unlock it */
- lrc = robust_flock(pFile->h, LOCK_UN);
- if (lrc) {
- int tErrno = errno;
- /* unlock failed with an error */
- lrc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
+ if (amt > wrote) {
+ if (wrote < 0 && pFile->lastErrno != ENOSPC) {
+ /* lastErrno set by seekAndWrite */
+ return SQLITE_IOERR_WRITE;
} else {
- int tErrno = errno;
- reserved = 1;
- /* someone else might have it reserved */
- lrc =
- sqliteErrorFromPosixError(tErrno,
- SQLITE_IOERR_LOCK);
- if (IS_LOCK_ERROR(lrc)) {
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
+ storeLastErrno(pFile, 0); /* not a system error */
+ return SQLITE_FULL;
}
}
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if ((rc & SQLITE_IOERR) == SQLITE_IOERR) {
- rc = SQLITE_OK;
- reserved = 1;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- *pResOut = reserved;
- return rc;
+ return SQLITE_OK;
}
+#ifdef SQLITE_TEST
/*
- * Lock the file with the lock specified by parameter eFileLock - 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.
+ * Count the number of fullsyncs and normal syncs. This is used to test
+ * that syncs and fullsyncs are occurring at the right times.
*/
-static int
-flockLock(sqlite3_file * id, int eFileLock)
-{
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
-
- assert(pFile);
-
- /* if we already have a lock, it is exclusive.
- * Just adjust level and punt on outta here.
- */
- if (pFile->eFileLock > NO_LOCK) {
- pFile->eFileLock = eFileLock;
- return SQLITE_OK;
- }
-
- /* grab an exclusive lock */
-
- if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
- int tErrno = errno;
- /* didn't get, must be busy */
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if (IS_LOCK_ERROR(rc)) {
- storeLastErrno(pFile, tErrno);
- }
- } else {
- /* got it, set the type and return ok */
- pFile->eFileLock = eFileLock;
- }
+int sqlite3_sync_count = 0;
+int sqlite3_fullsync_count = 0;
+#endif
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if ((rc & SQLITE_IOERR) == SQLITE_IOERR) {
- rc = SQLITE_BUSY;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- return rc;
-}
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * must be either NO_LOCK or SHARED_LOCK.
+ * The fsync() system call does not work as advertised on many
+ * unix systems. The following procedure is an attempt to make
+ * it work better.
*
- * If the locking level of the file descriptor is already at or below
- * the requested locking level, this routine is a no-op.
+ * The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
+ * for testing when we want to run through the test suite quickly.
+ * You are strongly advised *not* to deploy with SQLITE_NO_SYNC
+ * enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
+ * or power failure will likely corrupt the database file.
+ *
+ * SQLite sets the dataOnly flag if the size of the file is unchanged.
+ * The idea behind dataOnly is that it should only write the file content
+ * to disk, not the inode. We only set dataOnly if the file size is
+ * unchanged since the file size is part of the inode. However,
+ * Ted Ts'o tells us that fdatasync() will also write the inode if the
+ * file size has changed. The only real difference between fdatasync()
+ * and fsync(), Ted tells us, is that fdatasync() will not flush the
+ * inode if the mtime or owner or other inode attributes have changed.
+ * We only care about the file size, not the other file attributes, so
+ * as far as SQLite is concerned, an fdatasync() is always adequate.
+ * So, we always use fdatasync() if it is available, regardless of
+ * the value of the dataOnly flag.
*/
static int
-flockUnlock(sqlite3_file * id, int eFileLock)
+full_fsync(int fd, int fullSync, int dataOnly)
{
- unixFile *pFile = (unixFile *) id;
-
- assert(pFile);
- assert(eFileLock <= SHARED_LOCK);
-
- /* no-op if possible */
- if (pFile->eFileLock == eFileLock) {
- return SQLITE_OK;
- }
+ UNUSED_PARAMETER(fd);
+ UNUSED_PARAMETER(fullSync);
+ UNUSED_PARAMETER(dataOnly);
- /* shared can just be set because we always have an exclusive */
- if (eFileLock == SHARED_LOCK) {
- pFile->eFileLock = eFileLock;
- return SQLITE_OK;
- }
+ /* Record the number of times that we do a normal fsync() and
+ * FULLSYNC. This is used during testing to verify that this procedure
+ * gets called with the correct arguments.
+ */
+#ifdef SQLITE_TEST
+ if (fullSync)
+ sqlite3_fullsync_count++;
+ sqlite3_sync_count++;
+#endif
- /* no, really, unlock. */
- if (robust_flock(pFile->h, LOCK_UN)) {
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- return SQLITE_OK;
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- return SQLITE_IOERR_UNLOCK;
- } else {
- pFile->eFileLock = NO_LOCK;
- return SQLITE_OK;
- }
+ struct stat buf;
+ return fstat(fd, &buf);
}
/*
- * Close a file.
- */
-static int
-flockClose(sqlite3_file * id)
-{
- assert(id != 0);
- flockUnlock(id, NO_LOCK);
- return closeUnixFile(id);
-}
-
-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-
-/******************* End of the flock lock implementation *********************
- *****************************************************************************/
-
-
-/******************************************************************************
- ************************** Begin AFP Locking *********************************
+ * 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.
*
- * AFP is the Apple Filing Protocol. AFP is a network filesystem found
- * on Apple Macintosh computers - both OS9 and OSX.
+ * The directory file descriptor is used for only one thing - to
+ * fsync() a directory to make sure file creation and deletion events
+ * are flushed to disk. Such fsyncs are not needed on newer
+ * journaling filesystems, but are required on older filesystems.
*
- * Third-party implementations of AFP are available. But this code here
- * only works on OSX.
- */
-
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
- * The afpLockingContext structure contains all afp lock specific state
- */
-typedef struct afpLockingContext afpLockingContext;
-struct afpLockingContext {
- int reserved;
- const char *dbPath; /* Name of the open file */
-};
-
-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)
-
-/*
- * This is a utility for setting or clearing a bit-range lock on an
- * AFP filesystem.
+ * This routine can be overridden using the xSetSysCall interface.
+ * The ability to override this routine was added in support of the
+ * chromium sandbox. Opening a directory is a security risk (we are
+ * told) so making it overrideable allows the chromium sandbox to
+ * replace this routine with a harmless no-op. To make this routine
+ * a no-op, replace it with a stub that returns SQLITE_OK but leaves
+ * *pFd set to a negative number.
*
- * Return SQLITE_OK on success, SQLITE_BUSY on failure.
+ * If SQLITE_OK is returned, the caller is responsible for closing
+ * the file descriptor *pFd using close().
*/
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 */
- )
+openDirectory(const char *zFilename, int *pFd)
{
- struct ByteRangeLockPB2 pb;
- int err;
-
- pb.unLockFlag = setLockFlag ? 0 : 1;
- pb.startEndFlag = 0;
- pb.offset = offset;
- pb.length = length;
- pb.fd = pFile->h;
+ int ii;
+ int fd;
+ char zDirname[MAX_PATHNAME + 1];
- err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
- if (err == -1) {
- int rc;
- int tErrno = errno;
-
-#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
- rc = SQLITE_BUSY;
-#else
- rc = sqliteErrorFromPosixError(tErrno,
- setLockFlag ? SQLITE_IOERR_LOCK :
- SQLITE_IOERR_UNLOCK);
-#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
- if (IS_LOCK_ERROR(rc)) {
- storeLastErrno(pFile, tErrno);
- }
- return rc;
+ sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
+ for (ii = (int)strlen(zDirname); ii > 0 && zDirname[ii] != '/'; ii--) ;
+ if (ii > 0) {
+ zDirname[ii] = '\0';
} else {
- return SQLITE_OK;
+ if (zDirname[0] != '/')
+ zDirname[0] = '.';
+ zDirname[1] = 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, 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;
- unixFile *pFile = (unixFile *) id;
- afpLockingContext *context;
-
- SimulateIOError(return SQLITE_IOERR_CHECKRESERVEDLOCK;
- );
+ fd = robust_open(zDirname, O_RDONLY | O_BINARY, 0);
- assert(pFile);
- context = (afpLockingContext *) pFile->lockingContext;
- if (context->reserved) {
- *pResOut = 1;
+ *pFd = fd;
+ if (fd >= 0)
return SQLITE_OK;
- }
-
- /* Check if a thread in this process holds such a lock */
- if (pFile->pInode->eFileLock > SHARED_LOCK) {
- reserved = 1;
- }
-
- /* Otherwise see if some other process holds it.
- */
- if (!reserved) {
- /* lock the RESERVED byte */
- 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 =
- afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,
- 0);
- } else {
- /* if we failed to get the lock then someone else must have it */
- reserved = 1;
- }
- if (IS_LOCK_ERROR(lrc)) {
- rc = lrc;
- }
- }
-
- *pResOut = reserved;
- return rc;
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
}
/*
- * Lock the file with the lock specified by parameter eFileLock - 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.
+ * This function is called to handle the SQLITE_FCNTL_SIZE_HINT
+ * file-control operation. Enlarge the database to nBytes in size
+ * (rounded up to the next chunk-size). If the database is already
+ * nBytes or larger, this routine is a no-op.
*/
static int
-afpLock(sqlite3_file * id, int eFileLock)
+fcntlSizeHint(unixFile * pFile, i64 nByte)
{
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
- unixInodeInfo *pInode = pFile->pInode;
- afpLockingContext *context =
- (afpLockingContext *) pFile->lockingContext;
-
- assert(pFile);
-
- /* If there is already a lock of this type or more restrictive on the
- * unixFile, do nothing.
- */
- if (pFile->eFileLock >= eFileLock) {
- return SQLITE_OK;
- }
-
- /* Make sure the locking sequence is correct
- * (1) We never move from unlocked to anything higher than shared lock.
- * (2) SQLite never explicitly requests a pendig lock.
- * (3) A shared lock is always held when a reserve lock is requested.
- */
- assert(pFile->eFileLock != NO_LOCK || eFileLock == SHARED_LOCK);
- assert(eFileLock != PENDING_LOCK);
- assert(eFileLock != RESERVED_LOCK || pFile->eFileLock == SHARED_LOCK);
-
- pInode = pFile->pInode;
-
- /* If some thread using this PID has a lock via a different unixFile*
- * handle that precludes the requested lock, return BUSY.
- */
- if ((pFile->eFileLock != pInode->eFileLock &&
- (pInode->eFileLock >= PENDING_LOCK || eFileLock > SHARED_LOCK))
- ) {
- rc = SQLITE_BUSY;
- goto afp_end_lock;
- }
+ if (pFile->szChunk > 0) {
+ i64 nSize; /* Required file size */
+ struct stat buf; /* Used to hold return values of fstat() */
- /* If a SHARED lock is requested, and some thread using this PID already
- * has a SHARED or RESERVED lock, then increment reference counts and
- * return SQLITE_OK.
- */
- if (eFileLock == SHARED_LOCK &&
- (pInode->eFileLock == SHARED_LOCK
- || pInode->eFileLock == RESERVED_LOCK)) {
- assert(eFileLock == SHARED_LOCK);
- assert(pFile->eFileLock == 0);
- assert(pInode->nShared > 0);
- pFile->eFileLock = SHARED_LOCK;
- pInode->nShared++;
- pInode->nLock++;
- goto afp_end_lock;
- }
+ if (fstat(pFile->h, &buf))
+ return SQLITE_IOERR_FSTAT;
- /* 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 (eFileLock == SHARED_LOCK
- || (eFileLock == EXCLUSIVE_LOCK && pFile->eFileLock < PENDING_LOCK)
- ) {
- int failed;
- failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1);
- if (failed) {
- rc = failed;
- goto afp_end_lock;
- }
- }
+ nSize =
+ ((nByte + pFile->szChunk -
+ 1) / pFile->szChunk) * pFile->szChunk;
+ if (nSize > (i64) buf.st_size) {
+ int nBlk = buf.st_blksize; /* File-system block size */
+ int nWrite = 0; /* Number of bytes written by seekAndWrite */
+ i64 iWrite; /* Next offset to write to */
- /* If control gets to this point, then actually go ahead and make
- * operating system calls for the specified lock.
- */
- if (eFileLock == SHARED_LOCK) {
- int lrc1, lrc2, lrc1Errno = 0;
- long lk, mask;
-
- assert(pInode->nShared == 0);
- assert(pInode->eFileLock == 0);
-
- mask = (sizeof(long) == 8) ? LARGEST_INT64 : 0x7fffffff;
- /* Now get the read-lock SHARED_LOCK */
- /* note that the quality of the randomness doesn't matter that much */
- lk = random();
- pInode->sharedByte = (lk & mask) % (SHARED_SIZE - 1);
- lrc1 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + pInode->sharedByte, 1, 1);
- if (IS_LOCK_ERROR(lrc1)) {
- lrc1Errno = pFile->lastErrno;
- }
- /* Drop the temporary PENDING lock */
- lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
-
- if (IS_LOCK_ERROR(lrc1)) {
- storeLastErrno(pFile, lrc1Errno);
- rc = lrc1;
- goto afp_end_lock;
- } else if (IS_LOCK_ERROR(lrc2)) {
- rc = lrc2;
- goto afp_end_lock;
- } else if (lrc1 != SQLITE_OK) {
- rc = lrc1;
- } else {
- pFile->eFileLock = SHARED_LOCK;
- pInode->nLock++;
- pInode->nShared = 1;
- }
- } else if (eFileLock == EXCLUSIVE_LOCK && pInode->nShared > 1) {
- /* We are trying for an exclusive lock but another thread in this
- * same process is still holding a shared lock.
- */
- rc = SQLITE_BUSY;
- } 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->eFileLock);
- if (eFileLock >= RESERVED_LOCK
- && pFile->eFileLock < RESERVED_LOCK) {
- /* Acquire a RESERVED lock */
- failed =
- afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,
- 1);
- if (!failed) {
- context->reserved = 1;
+ iWrite = (buf.st_size / nBlk) * nBlk + nBlk - 1;
+ assert(iWrite >= buf.st_size);
+ assert(((iWrite + 1) % nBlk) == 0);
+ for ( /*no-op */ ; iWrite < nSize + nBlk - 1;
+ iWrite += nBlk) {
+ if (iWrite >= nSize)
+ iWrite = nSize - 1;
+ nWrite = seekAndWrite(pFile, iWrite, "", 1);
+ if (nWrite != 1)
+ return SQLITE_IOERR_WRITE;
}
}
- if (!failed && eFileLock == 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 afpUnlock
- */
- if (!
- (failed =
- afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + pInode->sharedByte, 1,
- 0))) {
- int failed2 = SQLITE_OK;
- /* now attemmpt to get the exclusive lock range */
- failed =
- afpSetLock(context->dbPath, pFile,
- SHARED_FIRST, SHARED_SIZE, 1);
- if (failed
- && (failed2 =
- afpSetLock(context->dbPath, pFile,
- SHARED_FIRST +
- pInode->sharedByte, 1, 1))) {
- /* Can't reestablish the shared lock. Sqlite can't deal, this is
- * a critical I/O error
- */
- rc = ((failed & SQLITE_IOERR) ==
- SQLITE_IOERR) ? failed2 :
- SQLITE_IOERR_LOCK;
- goto afp_end_lock;
- }
- } else {
- rc = failed;
+ }
+ if (pFile->mmapSizeMax > 0 && nByte > pFile->mmapSize) {
+ int rc;
+ if (pFile->szChunk <= 0) {
+ if (robust_ftruncate(pFile->h, nByte)) {
+ storeLastErrno(pFile, errno);
+ return unixLogError(SQLITE_IOERR_TRUNCATE,
+ "ftruncate", pFile->zPath);
}
}
- if (failed) {
- rc = failed;
- }
- }
- if (rc == SQLITE_OK) {
- pFile->eFileLock = eFileLock;
- pInode->eFileLock = eFileLock;
- } else if (eFileLock == EXCLUSIVE_LOCK) {
- pFile->eFileLock = PENDING_LOCK;
- pInode->eFileLock = PENDING_LOCK;
+ rc = unixMapfile(pFile, nByte);
+ return rc;
}
- afp_end_lock:
- return rc;
+ return SQLITE_OK;
}
+/* Forward declaration */
+static int unixGetTempname(int nBuf, char *zBuf);
+
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * 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.
+ * Information and control of an open file handle.
*/
static int
-afpUnlock(sqlite3_file * id, int eFileLock)
+unixFileControl(sqlite3_file * id, int op, void *pArg)
{
- int rc = SQLITE_OK;
unixFile *pFile = (unixFile *) id;
- unixInodeInfo *pInode;
- afpLockingContext *context =
- (afpLockingContext *) pFile->lockingContext;
- int skipShared = 0;
-#ifdef SQLITE_TEST
- int h = pFile->h;
-#endif
-
- assert(pFile);
-
- assert(eFileLock <= SHARED_LOCK);
- if (pFile->eFileLock <= eFileLock) {
- return SQLITE_OK;
- }
- pInode = pFile->pInode;
- assert(pInode->nShared != 0);
- if (pFile->eFileLock > SHARED_LOCK) {
- assert(pInode->eFileLock == pFile->eFileLock);
- SimulateIOErrorBenign(1);
- SimulateIOError(h = (-1))
- SimulateIOErrorBenign(0);
-
-#ifdef SQLITE_DEBUG
- /* When reducing a lock such that other processes can start
- * reading the database file again, make sure that the
- * transaction counter was updated if any part of the database
- * file changed. If the transaction counter is not updated,
- * other connections to the same file might not realize that
- * the file has changed and hence might not know to flush their
- * cache. The use of a stale cache can lead to database corruption.
- */
- assert(pFile->inNormalWrite == 0
- || pFile->dbUpdate == 0 || pFile->transCntrChng == 1);
- pFile->inNormalWrite = 0;
-#endif
-
- if (pFile->eFileLock == EXCLUSIVE_LOCK) {
- rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
- SHARED_SIZE, 0);
- if (rc == SQLITE_OK
- && (eFileLock == SHARED_LOCK
- || pInode->nShared > 1)) {
- /* only re-establish the shared lock if necessary */
- int sharedLockByte =
- SHARED_FIRST + pInode->sharedByte;
- rc = afpSetLock(context->dbPath, pFile,
- sharedLockByte, 1, 1);
- } else {
- skipShared = 1;
- }
- }
- if (rc == SQLITE_OK && pFile->eFileLock >= PENDING_LOCK) {
- rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1,
- 0);
+ switch (op) {
+ case SQLITE_FCNTL_LOCKSTATE:{
+ *(int *)pArg = pFile->eFileLock;
+ return SQLITE_OK;
}
- if (rc == SQLITE_OK && pFile->eFileLock >= RESERVED_LOCK
- && context->reserved) {
- rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE,
- 1, 0);
- if (!rc) {
- context->reserved = 0;
- }
+ case SQLITE_FCNTL_LAST_ERRNO:{
+ *(int *)pArg = pFile->lastErrno;
+ return SQLITE_OK;
}
- if (rc == SQLITE_OK
- && (eFileLock == SHARED_LOCK || pInode->nShared > 1)) {
- pInode->eFileLock = SHARED_LOCK;
+ case SQLITE_FCNTL_CHUNK_SIZE:{
+ pFile->szChunk = *(int *)pArg;
+ return SQLITE_OK;
}
- }
- if (rc == SQLITE_OK && eFileLock == NO_LOCK) {
-
- /* Decrement the shared lock counter. Release the lock using an
- * OS call only when all threads in this same process have released
- * the lock.
- */
- unsigned long long sharedLockByte =
- SHARED_FIRST + pInode->sharedByte;
- pInode->nShared--;
- if (pInode->nShared == 0) {
+ case SQLITE_FCNTL_SIZE_HINT:{
+ int rc;
SimulateIOErrorBenign(1);
- SimulateIOError(h = (-1))
- SimulateIOErrorBenign(0);
- if (!skipShared) {
- rc = afpSetLock(context->dbPath, pFile,
- sharedLockByte, 1, 0);
- }
- if (!rc) {
- pInode->eFileLock = NO_LOCK;
- pFile->eFileLock = NO_LOCK;
+ rc = fcntlSizeHint(pFile, *(i64 *) pArg);
+ SimulateIOErrorBenign(0);
+ return rc;
+ }
+ case SQLITE_FCNTL_VFSNAME:{
+ *(char **)pArg =
+ sqlite3_mprintf("%s", pFile->pVfs->zName);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_TEMPFILENAME:{
+ char *zTFile =
+ sqlite3_malloc64(pFile->pVfs->mxPathname);
+ if (zTFile) {
+ unixGetTempname(pFile->pVfs->mxPathname,
+ zTFile);
+ *(char **)pArg = zTFile;
}
+ return SQLITE_OK;
}
- if (rc == SQLITE_OK) {
- pInode->nLock--;
- assert(pInode->nLock >= 0);
- if (pInode->nLock == 0) {
- closePendingFds(pFile);
+ case SQLITE_FCNTL_HAS_MOVED:{
+ *(int *)pArg = fileHasMoved(pFile);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_MMAP_SIZE:{
+ i64 newLimit = *(i64 *) pArg;
+ int rc = SQLITE_OK;
+ if (newLimit > sqlite3GlobalConfig.mxMmap) {
+ newLimit = sqlite3GlobalConfig.mxMmap;
+ }
+ *(i64 *) pArg = pFile->mmapSizeMax;
+ if (newLimit >= 0 && newLimit != pFile->mmapSizeMax
+ && pFile->nFetchOut == 0) {
+ pFile->mmapSizeMax = newLimit;
+ if (pFile->mmapSize > 0) {
+ unixUnmapfile(pFile);
+ rc = unixMapfile(pFile, -1);
+ }
}
+ return rc;
}
}
-
- if (rc == SQLITE_OK)
- pFile->eFileLock = eFileLock;
- return rc;
+ return SQLITE_NOTFOUND;
}
/*
- * Close a file & cleanup AFP specific locking context
+ * If it is currently memory mapped, unmap file pFd.
*/
-static int
-afpClose(sqlite3_file * id)
+static void
+unixUnmapfile(unixFile * pFd)
{
- int rc = SQLITE_OK;
- unixFile *pFile = (unixFile *) id;
- assert(id != 0);
- afpUnlock(id, NO_LOCK);
- if (pFile->pInode && pFile->pInode->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 pInode->aPending. It will be automatically closed when
- * the last lock is cleared.
- */
- setPendingFd(pFile);
+ assert(pFd->nFetchOut == 0);
+ if (pFd->pMapRegion) {
+ munmap(pFd->pMapRegion, pFd->mmapSizeActual);
+ pFd->pMapRegion = 0;
+ pFd->mmapSize = 0;
+ pFd->mmapSizeActual = 0;
}
- releaseInodeInfo(pFile);
- sqlite3_free(pFile->lockingContext);
- rc = closeUnixFile(id);
- return rc;
}
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
/*
- * The code above is the AFP lock implementation. The code is specific
- * to MacOSX and does not work on other unix platforms. No alternative
- * is available. If you don't compile for a mac, then the "unix-afp"
- * VFS is not available.
+ * Attempt to set the size of the memory mapping maintained by file
+ * descriptor pFd to nNew bytes. Any existing mapping is discarded.
*
- ******************** End of the AFP lock implementation **********************
- *****************************************************************************/
-
-/******************************************************************************
- ************************** Begin NFS Locking *******************************
- */
-
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
- ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- ** 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.
+ * If successful, this function sets the following variables:
+ *
+ * unixFile.pMapRegion
+ * unixFile.mmapSize
+ * unixFile.mmapSizeActual
+ *
+ * If unsuccessful, an error message is logged via sqlite3_log() and
+ * the three variables above are zeroed. In this case SQLite should
+ * continue accessing the database using the xRead() and xWrite()
+ * methods.
*/
-static int
-nfsUnlock(sqlite3_file * id, int eFileLock)
+static void
+unixRemapfile(unixFile * pFd, /* File descriptor object */
+ i64 nNew /* Required mapping size */
+ )
{
- return posixUnlock(id, eFileLock, 1);
+ const char *zErr = "mmap";
+ int h = pFd->h; /* File descriptor open on db file */
+ u8 *pOrig = (u8 *) pFd->pMapRegion; /* Pointer to current file mapping */
+ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
+ u8 *pNew = 0; /* Location of new mapping */
+ int flags = PROT_READ; /* Flags to pass to mmap() */
+
+ assert(pFd->nFetchOut == 0);
+ assert(nNew > pFd->mmapSize);
+ assert(nNew <= pFd->mmapSizeMax);
+ assert(nNew > 0);
+ assert(pFd->mmapSizeActual >= pFd->mmapSize);
+ assert(MAP_FAILED != 0);
+
+ if (pOrig) {
+ i64 nReuse = pFd->mmapSize;
+ u8 *pReq = &pOrig[nReuse];
+
+ /* Unmap any pages of the existing mapping that cannot be reused. */
+ if (nReuse != nOrig)
+ munmap(pReq, nOrig - nReuse);
+ #if !defined(__APPLE__) && !defined(__FreeBSD__)
+ pNew = mremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
+ zErr = "mremap";
+ #else
+ pNew = mmap(pReq, nNew - nReuse, flags, MAP_SHARED, h, nReuse);
+ if (pNew != MAP_FAILED) {
+ if (pNew != pReq) {
+ munmap(pNew, nNew - nReuse);
+ pNew = NULL;
+ } else {
+ pNew = pOrig;
+ }
+ }
+ #endif
+
+ /* The attempt to extend the existing mapping failed. Free it. */
+ if (pNew == MAP_FAILED || pNew == NULL)
+ munmap(pOrig, nReuse);
+ }
+
+ /* If pNew is still NULL, try to create an entirely new mapping. */
+ if (pNew == NULL)
+ pNew = mmap(0, nNew, flags, MAP_SHARED, h, 0);
+
+ if (pNew == MAP_FAILED) {
+ pNew = 0;
+ nNew = 0;
+ unixLogError(SQLITE_OK, zErr, pFd->zPath);
+
+ /* If the mmap() above failed, assume that all subsequent mmap() calls
+ * will probably fail too. Fall back to using xRead/xWrite exclusively
+ * in this case.
+ */
+ pFd->mmapSizeMax = 0;
+ }
+ pFd->pMapRegion = (void *)pNew;
+ pFd->mmapSize = pFd->mmapSizeActual = nNew;
}
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
/*
- * The code above is the NFS lock implementation. The code is specific
- * to MacOSX and does not work on other unix platforms. No alternative
- * is available.
+ * Memory map or remap the file opened by file-descriptor pFd (if the file
+ * is already mapped, the existing mapping is replaced by the new). Or, if
+ * there already exists a mapping for this file, and there are still
+ * outstanding xFetch() references to it, this function is a no-op.
*
- ******************** End of the NFS lock implementation **********************
- *****************************************************************************/
-
-/******************************************************************************
- *************** Non-locking sqlite3_file methods *****************************
+ * If parameter nByte is non-negative, then it is the requested size of
+ * the mapping to create. Otherwise, if nByte is less than zero, then the
+ * requested size is the size of the file on disk. The actual size of the
+ * created mapping is either the requested size or the value configured
+ * using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
*
- * The next division contains implementations for all methods of the
- * sqlite3_file object other than the locking methods. The locking
- * methods were defined in divisions above (one locking method per
- * division). Those methods that are common to all locking modes
- * are gather together into this division.
+ * SQLITE_OK is returned if no error occurs (even if the mapping is not
+ * recreated as a result of outstanding references) or an SQLite error
+ * code otherwise.
*/
+static int
+unixMapfile(unixFile * pFd, i64 nMap)
+{
+ assert(nMap >= 0 || pFd->nFetchOut == 0);
+ assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
+ if (pFd->nFetchOut > 0)
+ return SQLITE_OK;
+
+ if (nMap < 0) {
+ struct stat statbuf; /* Low-level file information */
+ if (fstat(pFd->h, &statbuf))
+ return SQLITE_IOERR_FSTAT;
+ nMap = statbuf.st_size;
+ }
+ if (nMap > pFd->mmapSizeMax) {
+ nMap = pFd->mmapSizeMax;
+ }
+
+ assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
+ if (nMap != pFd->mmapSize) {
+ unixRemapfile(pFd, nMap);
+ }
+
+ return SQLITE_OK;
+}
/*
- * Seek to the offset passed as the second argument, then read cnt
- * bytes into pBuf. Return the number of bytes actually read.
+ * If possible, return a pointer to a mapping of file fd starting at offset
+ * iOff. The mapping must be valid for at least nAmt bytes.
*
- * 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
- * in any form by default, we will not attempt to define _XOPEN_SOURCE.
- * See tickets #2741 and #2681.
+ * If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
+ * Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
+ * Finally, if an error does occur, return an SQLite error code. The final
+ * value of *pp is undefined in this case.
*
- * To avoid stomping the errno value on a failed read the lastErrno value
- * is set before returning.
+ * If this function does return a pointer, the caller must eventually
+ * release the reference by calling unixUnfetch().
*/
static int
-seekAndRead(unixFile * id, sqlite3_int64 offset, void *pBuf, int cnt)
+unixFetch(sqlite3_file * fd MAYBE_UNUSED,
+ i64 iOff MAYBE_UNUSED,
+ int nAmt MAYBE_UNUSED, void **pp)
{
- int got;
- int prior = 0;
-#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
- i64 newOffset;
-#endif
- TIMER_START;
- assert(cnt == (cnt & 0x1ffff));
- assert(id->h > 2);
- do {
-#if defined(USE_PREAD)
- got = osPread(id->h, pBuf, cnt, offset);
- SimulateIOError(got = -1);
-#elif defined(USE_PREAD64)
- got = osPread64(id->h, pBuf, cnt, offset);
- SimulateIOError(got = -1);
-#else
- newOffset = lseek(id->h, offset, SEEK_SET);
- SimulateIOError(newOffset = -1);
- if (newOffset < 0) {
- storeLastErrno((unixFile *) id, errno);
- return -1;
- }
- got = osRead(id->h, pBuf, cnt);
+#if SQLITE_MAX_MMAP_SIZE>0
+ unixFile *pFd = (unixFile *) fd; /* The underlying database file */
#endif
- if (got == cnt)
- break;
- if (got < 0) {
- if (errno == EINTR) {
- got = 1;
- continue;
- }
- prior = 0;
- storeLastErrno((unixFile *) id, errno);
- break;
- } else if (got > 0) {
- cnt -= got;
- offset += got;
- prior += got;
- pBuf = (void *)(got + (char *)pBuf);
- }
- } while (got > 0);
- TIMER_END;
- return got + prior;
-}
-
-/*
- * Read data from a file into a buffer. Return SQLITE_OK if all
- * bytes were read successfully and SQLITE_IOERR if anything goes
- * wrong.
- */
-static int
-unixRead(sqlite3_file * id, void *pBuf, int amt, sqlite3_int64 offset)
-{
- unixFile *pFile = (unixFile *) id;
- int got;
- assert(id);
- assert(offset >= 0);
- assert(amt > 0);
-
-#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
- * data from the memory mapping using memcpy().
- */
- if (offset < pFile->mmapSize) {
- if (offset + amt <= pFile->mmapSize) {
- memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
- amt);
- return SQLITE_OK;
- } else {
- int nCopy = pFile->mmapSize - offset;
- memcpy(pBuf, &((u8 *) (pFile->pMapRegion))[offset],
- nCopy);
- pBuf = &((u8 *) pBuf)[nCopy];
- amt -= nCopy;
- offset += nCopy;
- }
- }
-#endif
-
- got = seekAndRead(pFile, offset, pBuf, amt);
- if (got == amt) {
- return SQLITE_OK;
- } else if (got < 0) {
- /* lastErrno set by seekAndRead */
- return SQLITE_IOERR_READ;
- } else {
- storeLastErrno(pFile, 0); /* not a system error */
- /* Unread parts of the buffer must be zero-filled */
- memset(&((char *)pBuf)[got], 0, amt - got);
- return SQLITE_IOERR_SHORT_READ;
- }
-}
-
-/*
- * Attempt to seek the file-descriptor passed as the first argument to
- * absolute offset iOff, then attempt to write nBuf bytes of data from
- * pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
- * return the actual number of bytes written (which may be less than
- * nBuf).
- */
-static int
-seekAndWriteFd(int fd, /* File descriptor to write to */
- i64 iOff, /* File offset to begin writing at */
- const void *pBuf, /* Copy data from this buffer to the file */
- int nBuf, /* Size of buffer pBuf in bytes */
- int *piErrno /* OUT: Error number if error occurs */
- )
-{
- int rc = 0; /* Value returned by system call */
-
- assert(nBuf == (nBuf & 0x1ffff));
- assert(fd > 2);
- assert(piErrno != 0);
- nBuf &= 0x1ffff;
- TIMER_START;
-
-#if defined(USE_PREAD)
- do {
- rc = (int)osPwrite(fd, pBuf, nBuf, iOff);
- } while (rc < 0 && errno == EINTR);
-#elif defined(USE_PREAD64)
- do {
- rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);
- } while (rc < 0 && errno == EINTR);
-#else
- do {
- i64 iSeek = lseek(fd, iOff, SEEK_SET);
- SimulateIOError(iSeek = -1);
- if (iSeek < 0) {
- rc = -1;
- break;
- }
- rc = osWrite(fd, pBuf, nBuf);
- } while (rc < 0 && errno == EINTR);
-#endif
-
- TIMER_END;
-
- if (rc < 0)
- *piErrno = errno;
- return rc;
-}
-
-/*
- * Seek to the offset in id->offset then read cnt bytes into pBuf.
- * Return the number of bytes actually read. Update the offset.
- *
- * To avoid stomping the errno value on a failed write the lastErrno value
- * is set before returning.
- */
-static int
-seekAndWrite(unixFile * id, i64 offset, const void *pBuf, int cnt)
-{
- return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
-}
-
-/*
- * Write data from a buffer into a file. Return SQLITE_OK on success
- * or some other error code on failure.
- */
-static int
-unixWrite(sqlite3_file * id, const void *pBuf, int amt, sqlite3_int64 offset)
-{
- unixFile *pFile = (unixFile *) id;
- int wrote = 0;
- assert(id);
- assert(amt > 0);
-
-#ifdef SQLITE_DEBUG
- /* If we are doing a normal write to a database file,
- * then record the fact that the database
- * has changed. If the transaction counter is modified, record that
- * fact too.
- */
- if (pFile->inNormalWrite) {
- pFile->dbUpdate = 1; /* The database has been modified */
- if (offset <= 24 && offset + amt >= 27) {
- int rc;
- char oldCntr[4];
- SimulateIOErrorBenign(1);
- rc = seekAndRead(pFile, 24, oldCntr, 4);
- SimulateIOErrorBenign(0);
- if (rc != 4
- || memcmp(oldCntr, &((char *)pBuf)[24 - offset],
- 4) != 0) {
- pFile->transCntrChng = 1; /* The transaction counter has changed */
- }
- }
- }
-#endif
-
-#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
- * data from the memory mapping using memcpy().
- */
- if (offset < pFile->mmapSize) {
- if (offset + amt <= pFile->mmapSize) {
- memcpy(&((u8 *) (pFile->pMapRegion))[offset], pBuf,
- amt);
- return SQLITE_OK;
- } else {
- int nCopy = pFile->mmapSize - offset;
- memcpy(&((u8 *) (pFile->pMapRegion))[offset], pBuf,
- nCopy);
- pBuf = &((u8 *) pBuf)[nCopy];
- amt -= nCopy;
- offset += nCopy;
- }
- }
-#endif
-
- while ((wrote = seekAndWrite(pFile, offset, pBuf, amt)) < amt
- && wrote > 0) {
- amt -= wrote;
- offset += wrote;
- pBuf = &((char *)pBuf)[wrote];
- }
- SimulateIOError((wrote = (-1), amt = 1));
- SimulateDiskfullError((wrote = 0, amt = 1));
-
- if (amt > wrote) {
- if (wrote < 0 && pFile->lastErrno != ENOSPC) {
- /* lastErrno set by seekAndWrite */
- return SQLITE_IOERR_WRITE;
- } else {
- storeLastErrno(pFile, 0); /* not a system error */
- return SQLITE_FULL;
- }
- }
-
- return SQLITE_OK;
-}
-
-#ifdef SQLITE_TEST
-/*
- * Count the number of fullsyncs and normal syncs. This is used to test
- * that syncs and fullsyncs are occurring at the right times.
- */
-int sqlite3_sync_count = 0;
-int sqlite3_fullsync_count = 0;
-#endif
-
-/*
- * We do not trust systems to provide a working fdatasync(). Some do.
- * Others do no. To be safe, we will stick with the (slightly slower)
- * fsync(). If you know that your system does support fdatasync() correctly,
- * then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
- */
-#if !defined(fdatasync) && !HAVE_FDATASYNC
-#define fdatasync fsync
-#endif
-
-/*
- * The fsync() system call does not work as advertised on many
- * unix systems. The following procedure is an attempt to make
- * it work better.
- *
- * The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
- * for testing when we want to run through the test suite quickly.
- * You are strongly advised *not* to deploy with SQLITE_NO_SYNC
- * enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
- * or power failure will likely corrupt the database file.
- *
- * SQLite sets the dataOnly flag if the size of the file is unchanged.
- * The idea behind dataOnly is that it should only write the file content
- * to disk, not the inode. We only set dataOnly if the file size is
- * unchanged since the file size is part of the inode. However,
- * Ted Ts'o tells us that fdatasync() will also write the inode if the
- * file size has changed. The only real difference between fdatasync()
- * and fsync(), Ted tells us, is that fdatasync() will not flush the
- * inode if the mtime or owner or other inode attributes have changed.
- * We only care about the file size, not the other file attributes, so
- * as far as SQLite is concerned, an fdatasync() is always adequate.
- * So, we always use fdatasync() if it is available, regardless of
- * the value of the dataOnly flag.
- */
-static int
-full_fsync(int fd, int fullSync, int dataOnly)
-{
- int rc;
-
- /* The following "ifdef/elif/else/" block has the same structure as
- * the one below. It is replicated here solely to avoid cluttering
- * up the real code with the UNUSED_PARAMETER() macros.
- */
-#ifdef SQLITE_NO_SYNC
- UNUSED_PARAMETER(fd);
- UNUSED_PARAMETER(fullSync);
- UNUSED_PARAMETER(dataOnly);
-#else
- UNUSED_PARAMETER(fullSync);
- UNUSED_PARAMETER(dataOnly);
-#endif
-
- /* Record the number of times that we do a normal fsync() and
- * FULLSYNC. This is used during testing to verify that this procedure
- * gets called with the correct arguments.
- */
-#ifdef SQLITE_TEST
- if (fullSync)
- sqlite3_fullsync_count++;
- sqlite3_sync_count++;
-#endif
-
- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
- * no-op. But go ahead and call fstat() to validate the file
- * descriptor as we need a method to provoke a failure during
- * coverate testing.
- */
-#ifdef SQLITE_NO_SYNC
- {
- struct stat buf;
- rc = osFstat(fd, &buf);
- }
-#elif defined(__APPLE__)
- /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
- * so currently we default to the macro that redefines fdatasync to fsync
- */
- rc = fsync(fd);
-#else
- rc = fdatasync(fd);
-#endif /* ifdef SQLITE_NO_SYNC */
-
- return rc;
-}
-
-/*
- * 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.
- *
- * The directory file descriptor is used for only one thing - to
- * fsync() a directory to make sure file creation and deletion events
- * are flushed to disk. Such fsyncs are not needed on newer
- * journaling filesystems, but are required on older filesystems.
- *
- * This routine can be overridden using the xSetSysCall interface.
- * The ability to override this routine was added in support of the
- * chromium sandbox. Opening a directory is a security risk (we are
- * told) so making it overrideable allows the chromium sandbox to
- * replace this routine with a harmless no-op. To make this routine
- * a no-op, replace it with a stub that returns SQLITE_OK but leaves
- * *pFd set to a negative number.
- *
- * 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;
- char zDirname[MAX_PATHNAME + 1];
-
- sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
- for (ii = (int)strlen(zDirname); ii > 0 && zDirname[ii] != '/'; ii--) ;
- if (ii > 0) {
- zDirname[ii] = '\0';
- } else {
- if (zDirname[0] != '/')
- zDirname[0] = '.';
- zDirname[1] = 0;
- }
- fd = robust_open(zDirname, O_RDONLY | O_BINARY, 0);
-
- *pFd = fd;
- if (fd >= 0)
- return SQLITE_OK;
- return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
-}
-
-/*
- * Make sure all writes to a particular file are committed to disk.
- *
- * If dataOnly==0 then both the file itself and its metadata (file
- * size, access time, etc) are synced. If dataOnly!=0 then only the
- * file data is synced.
- *
- * Under Unix, also make sure that the directory entry for the file
- * has been created by fsync-ing the directory that contains the file.
- * If we do not do this and we encounter a power failure, the directory
- * entry for the journal might not exist after we reboot. The next
- * SQLite to access the file will not know that the journal exists (because
- * the directory entry for the journal was never created) and the transaction
- * will not roll back - possibly leading to database corruption.
- */
-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);
-
- /* Unix cannot, but some systems may return SQLITE_FULL from here. This
- * line is to test that doing so does not cause any problems.
- */
- SimulateDiskfullError(return SQLITE_FULL);
-
- assert(pFile);
- rc = full_fsync(pFile->h, isFullsync, isDataOnly);
- SimulateIOError(rc = 1);
- if (rc) {
- storeLastErrno(pFile, errno);
- return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync",
- pFile->zPath);
- }
-
- return rc;
-}
-
-/*
- * Truncate an open file to a specified size
- */
-static int
-unixTruncate(sqlite3_file * id, i64 nByte)
-{
- unixFile *pFile = (unixFile *) id;
- int rc;
- assert(pFile);
- SimulateIOError(return SQLITE_IOERR_TRUNCATE);
-
- /* If the user has configured a chunk-size for this file, truncate the
- * file so that it consists of an integer number of chunks (i.e. the
- * actual file size after the operation may be larger than the requested
- * size).
- */
- if (pFile->szChunk > 0) {
- nByte =
- ((nByte + pFile->szChunk -
- 1) / pFile->szChunk) * pFile->szChunk;
- }
-
- rc = robust_ftruncate(pFile->h, nByte);
- if (rc) {
- storeLastErrno(pFile, errno);
- return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate",
- pFile->zPath);
- } else {
-#ifdef SQLITE_DEBUG
- /* If we are doing a normal write to a database file (as opposed to
- * doing a hot-journal rollback or a write to some file other than a
- * normal database file) and we truncate the file to zero length,
- * that effectively updates the change counter.
- */
- if (pFile->inNormalWrite && nByte == 0) {
- pFile->transCntrChng = 1;
- }
-#endif
-
-#if SQLITE_MAX_MMAP_SIZE>0
- /* If the file was just truncated to a size smaller than the currently
- * mapped region, reduce the effective mapping size as well. SQLite will
- * use read() and write() to access data beyond this point from now on.
- */
- if (nByte < pFile->mmapSize) {
- pFile->mmapSize = nByte;
- }
-#endif
-
- return SQLITE_OK;
- }
-}
-
-/*
- * Determine the current size of a file in bytes
- */
-static int
-unixFileSize(sqlite3_file * id, i64 * pSize)
-{
- int rc;
- struct stat buf;
- assert(id);
- rc = osFstat(((unixFile *) id)->h, &buf);
- SimulateIOError(rc = 1);
- if (rc != 0) {
- storeLastErrno((unixFile *) id, errno);
- return SQLITE_IOERR_FSTAT;
- }
- *pSize = buf.st_size;
-
- /* When opening a zero-size database, the findInodeInfo() procedure
- * writes a single byte into that file in order to work around a bug
- * in the OS-X msdos filesystem. In order to avoid problems with upper
- * layers, we need to report this file size as zero even though it is
- * really 1. Ticket #3260.
- */
- if (*pSize == 1)
- *pSize = 0;
-
- return SQLITE_OK;
-}
-
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
-/*
- * Handler for proxy-locking file-control verbs. Defined below in the
- * proxying locking division.
- */
-static int proxyFileControl(sqlite3_file *, int, void *);
-#endif
-
-/*
- * This function is called to handle the SQLITE_FCNTL_SIZE_HINT
- * file-control operation. Enlarge the database to nBytes in size
- * (rounded up to the next chunk-size). If the database is already
- * nBytes or larger, this routine is a no-op.
- */
-static int
-fcntlSizeHint(unixFile * pFile, i64 nByte)
-{
- if (pFile->szChunk > 0) {
- i64 nSize; /* Required file size */
- struct stat buf; /* Used to hold return values of fstat() */
-
- if (osFstat(pFile->h, &buf)) {
- return SQLITE_IOERR_FSTAT;
- }
-
- nSize =
- ((nByte + pFile->szChunk -
- 1) / pFile->szChunk) * pFile->szChunk;
- if (nSize > (i64) buf.st_size) {
-
-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
- /* The code below is handling the return value of osFallocate()
- * correctly. posix_fallocate() is defined to "returns zero on success,
- * or an error number on failure". See the manpage for details.
- */
- int err;
- do {
- err =
- osFallocate(pFile->h, buf.st_size,
- nSize - buf.st_size);
- } while (err == EINTR);
- if (err)
- return SQLITE_IOERR_WRITE;
-#else
- /* If the OS does not have posix_fallocate(), fake it. Write a
- * single byte to the last byte in each block that falls entirely
- * within the extended region. Then, if required, a single byte
- * at offset (nSize-1), to set the size of the file correctly.
- * This is a similar technique to that used by glibc on systems
- * that do not have a real fallocate() call.
- */
- int nBlk = buf.st_blksize; /* File-system block size */
- int nWrite = 0; /* Number of bytes written by seekAndWrite */
- i64 iWrite; /* Next offset to write to */
-
- iWrite = (buf.st_size / nBlk) * nBlk + nBlk - 1;
- assert(iWrite >= buf.st_size);
- assert(((iWrite + 1) % nBlk) == 0);
- for ( /*no-op */ ; iWrite < nSize + nBlk - 1;
- iWrite += nBlk) {
- if (iWrite >= nSize)
- iWrite = nSize - 1;
- nWrite = seekAndWrite(pFile, iWrite, "", 1);
- if (nWrite != 1)
- return SQLITE_IOERR_WRITE;
- }
-#endif
- }
- }
-#if SQLITE_MAX_MMAP_SIZE>0
- if (pFile->mmapSizeMax > 0 && nByte > pFile->mmapSize) {
- int rc;
- if (pFile->szChunk <= 0) {
- if (robust_ftruncate(pFile->h, nByte)) {
- storeLastErrno(pFile, errno);
- return unixLogError(SQLITE_IOERR_TRUNCATE,
- "ftruncate", pFile->zPath);
- }
- }
-
- rc = unixMapfile(pFile, nByte);
- return rc;
- }
-#endif
-
- return SQLITE_OK;
-}
-
-/* Forward declaration */
-static int unixGetTempname(int nBuf, char *zBuf);
-
-/*
- * Information and control of an open file handle.
- */
-static int
-unixFileControl(sqlite3_file * id, int op, void *pArg)
-{
- unixFile *pFile = (unixFile *) id;
- switch (op) {
- case SQLITE_FCNTL_LOCKSTATE:{
- *(int *)pArg = pFile->eFileLock;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_LAST_ERRNO:{
- *(int *)pArg = pFile->lastErrno;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_CHUNK_SIZE:{
- pFile->szChunk = *(int *)pArg;
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_SIZE_HINT:{
- int rc;
- SimulateIOErrorBenign(1);
- rc = fcntlSizeHint(pFile, *(i64 *) pArg);
- SimulateIOErrorBenign(0);
- return rc;
- }
- case SQLITE_FCNTL_VFSNAME:{
- *(char **)pArg =
- sqlite3_mprintf("%s", pFile->pVfs->zName);
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_TEMPFILENAME:{
- char *zTFile =
- sqlite3_malloc64(pFile->pVfs->mxPathname);
- if (zTFile) {
- unixGetTempname(pFile->pVfs->mxPathname,
- zTFile);
- *(char **)pArg = zTFile;
- }
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_HAS_MOVED:{
- *(int *)pArg = fileHasMoved(pFile);
- return SQLITE_OK;
- }
-#if SQLITE_MAX_MMAP_SIZE>0
- case SQLITE_FCNTL_MMAP_SIZE:{
- i64 newLimit = *(i64 *) pArg;
- int rc = SQLITE_OK;
- if (newLimit > sqlite3GlobalConfig.mxMmap) {
- newLimit = sqlite3GlobalConfig.mxMmap;
- }
- *(i64 *) pArg = pFile->mmapSizeMax;
- if (newLimit >= 0 && newLimit != pFile->mmapSizeMax
- && pFile->nFetchOut == 0) {
- pFile->mmapSizeMax = newLimit;
- if (pFile->mmapSize > 0) {
- unixUnmapfile(pFile);
- rc = unixMapfile(pFile, -1);
- }
- }
- return rc;
- }
-#endif
-#ifdef SQLITE_DEBUG
- /* The pager calls this method to signal that it has done
- * a rollback and that the database is therefore unchanged and
- * it hence it is OK for the transaction change counter to be
- * unchanged.
- */
- case SQLITE_FCNTL_DB_UNCHANGED:{
- ((unixFile *) id)->dbUpdate = 0;
- return SQLITE_OK;
- }
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- case SQLITE_FCNTL_SET_LOCKPROXYFILE:
- case SQLITE_FCNTL_GET_LOCKPROXYFILE:{
- return proxyFileControl(id, op, pArg);
- }
-#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
- }
- return SQLITE_NOTFOUND;
-}
-
-/*
- * 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
-unixSectorSize(sqlite3_file * NotUsed)
-{
- UNUSED_PARAMETER(NotUsed);
- return SQLITE_DEFAULT_SECTOR_SIZE;
-}
-
-/*
- * Return the device characteristics for the file.
- *
- * This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
- * However, that choice is controversial since technically the underlying
- * file system does not always provide powersafe overwrites. (In other
- * words, after a power-loss event, parts of the file that were never
- * written might end up being altered.) However, non-PSOW behavior is very,
- * very rare. And asserting PSOW makes a large reduction in the amount
- * of required I/O for journaling, since a lot of padding is eliminated.
- * Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
- * available to turn it off and URI query parameter available to turn it off.
- */
-static int
-unixDeviceCharacteristics(sqlite3_file * pNotUsed)
-{
- UNUSED_PARAMETER(pNotUsed);
- return SQLITE_OK;
-}
-
-#if SQLITE_MAX_MMAP_SIZE>0
-
-/*
- * Return the system page size.
- *
- * This function should not be called directly by other code in this file.
- * Instead, it should be called via macro osGetpagesize().
- */
-static int
-unixGetpagesize(void)
-{
- return (int)sysconf(_SC_PAGESIZE);
-}
-
-#endif /* SQLITE_MAX_MMAP_SIZE>0 */
-
-#define unixShmMap 0
-#define unixShmLock 0
-#define unixShmBarrier 0
-#define unixShmUnmap 0
-
-#if SQLITE_MAX_MMAP_SIZE>0
-/*
- * If it is currently memory mapped, unmap file pFd.
- */
-static void
-unixUnmapfile(unixFile * pFd)
-{
- assert(pFd->nFetchOut == 0);
- if (pFd->pMapRegion) {
- osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
- pFd->pMapRegion = 0;
- pFd->mmapSize = 0;
- pFd->mmapSizeActual = 0;
- }
-}
-
-/*
- * Attempt to set the size of the memory mapping maintained by file
- * descriptor pFd to nNew bytes. Any existing mapping is discarded.
- *
- * If successful, this function sets the following variables:
- *
- * unixFile.pMapRegion
- * unixFile.mmapSize
- * unixFile.mmapSizeActual
- *
- * If unsuccessful, an error message is logged via sqlite3_log() and
- * the three variables above are zeroed. In this case SQLite should
- * continue accessing the database using the xRead() and xWrite()
- * methods.
- */
-static void
-unixRemapfile(unixFile * pFd, /* File descriptor object */
- i64 nNew /* Required mapping size */
- )
-{
- const char *zErr = "mmap";
- int h = pFd->h; /* File descriptor open on db file */
- u8 *pOrig = (u8 *) pFd->pMapRegion; /* Pointer to current file mapping */
- i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */
- u8 *pNew = 0; /* Location of new mapping */
- int flags = PROT_READ; /* Flags to pass to mmap() */
-
- assert(pFd->nFetchOut == 0);
- assert(nNew > pFd->mmapSize);
- assert(nNew <= pFd->mmapSizeMax);
- assert(nNew > 0);
- assert(pFd->mmapSizeActual >= pFd->mmapSize);
- assert(MAP_FAILED != 0);
-
-#ifdef SQLITE_MMAP_READWRITE
- if ((pFd->ctrlFlags & UNIXFILE_RDONLY) == 0)
- flags |= PROT_WRITE;
-#endif
-
- if (pOrig) {
-#if HAVE_MREMAP
- i64 nReuse = pFd->mmapSize;
-#else
- const int szSyspage = osGetpagesize();
- i64 nReuse = (pFd->mmapSize & ~(szSyspage - 1));
-#endif
- u8 *pReq = &pOrig[nReuse];
-
- /* Unmap any pages of the existing mapping that cannot be reused. */
- if (nReuse != nOrig) {
- osMunmap(pReq, nOrig - nReuse);
- }
-#if HAVE_MREMAP
- pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
- zErr = "mremap";
-#else
- pNew =
- osMmap(pReq, nNew - nReuse, flags, MAP_SHARED, h, nReuse);
- if (pNew != MAP_FAILED) {
- if (pNew != pReq) {
- osMunmap(pNew, nNew - nReuse);
- pNew = 0;
- } else {
- pNew = pOrig;
- }
- }
-#endif
-
- /* The attempt to extend the existing mapping failed. Free it. */
- if (pNew == MAP_FAILED || pNew == 0) {
- osMunmap(pOrig, nReuse);
- }
- }
-
- /* If pNew is still NULL, try to create an entirely new mapping. */
- if (pNew == 0) {
- pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
- }
-
- if (pNew == MAP_FAILED) {
- pNew = 0;
- nNew = 0;
- unixLogError(SQLITE_OK, zErr, pFd->zPath);
-
- /* If the mmap() above failed, assume that all subsequent mmap() calls
- * will probably fail too. Fall back to using xRead/xWrite exclusively
- * in this case.
- */
- pFd->mmapSizeMax = 0;
- }
- pFd->pMapRegion = (void *)pNew;
- pFd->mmapSize = pFd->mmapSizeActual = nNew;
-}
-
-/*
- * Memory map or remap the file opened by file-descriptor pFd (if the file
- * is already mapped, the existing mapping is replaced by the new). Or, if
- * there already exists a mapping for this file, and there are still
- * outstanding xFetch() references to it, this function is a no-op.
- *
- * If parameter nByte is non-negative, then it is the requested size of
- * the mapping to create. Otherwise, if nByte is less than zero, then the
- * requested size is the size of the file on disk. The actual size of the
- * created mapping is either the requested size or the value configured
- * using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
- *
- * SQLITE_OK is returned if no error occurs (even if the mapping is not
- * recreated as a result of outstanding references) or an SQLite error
- * code otherwise.
- */
-static int
-unixMapfile(unixFile * pFd, i64 nMap)
-{
- assert(nMap >= 0 || pFd->nFetchOut == 0);
- assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
- if (pFd->nFetchOut > 0)
- return SQLITE_OK;
-
- if (nMap < 0) {
- struct stat statbuf; /* Low-level file information */
- if (osFstat(pFd->h, &statbuf)) {
- return SQLITE_IOERR_FSTAT;
- }
- nMap = statbuf.st_size;
- }
- if (nMap > pFd->mmapSizeMax) {
- nMap = pFd->mmapSizeMax;
- }
-
- assert(nMap > 0 || (pFd->mmapSize == 0 && pFd->pMapRegion == 0));
- if (nMap != pFd->mmapSize) {
- unixRemapfile(pFd, nMap);
- }
-
- return SQLITE_OK;
-}
-#endif /* SQLITE_MAX_MMAP_SIZE>0 */
-
-/*
- * If possible, return a pointer to a mapping of file fd starting at offset
- * iOff. The mapping must be valid for at least nAmt bytes.
- *
- * If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
- * Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
- * Finally, if an error does occur, return an SQLite error code. The final
- * value of *pp is undefined in this case.
- *
- * If this function does return a pointer, the caller must eventually
- * release the reference by calling unixUnfetch().
- */
-static int
-unixFetch(sqlite3_file * fd MAYBE_UNUSED,
- i64 iOff MAYBE_UNUSED,
- int nAmt MAYBE_UNUSED, void **pp)
-{
-#if SQLITE_MAX_MMAP_SIZE>0
- unixFile *pFd = (unixFile *) fd; /* The underlying database file */
-#endif
- *pp = 0;
-
-#if SQLITE_MAX_MMAP_SIZE>0
- if (pFd->mmapSizeMax > 0) {
- if (pFd->pMapRegion == 0) {
- int rc = unixMapfile(pFd, -1);
- if (rc != SQLITE_OK)
- return rc;
- }
- if (pFd->mmapSize >= iOff + nAmt) {
- *pp = &((u8 *) pFd->pMapRegion)[iOff];
- pFd->nFetchOut++;
- }
- }
-#endif
- return SQLITE_OK;
-}
-
-/*
- * If the third argument is non-NULL, then this function releases a
- * reference obtained by an earlier call to unixFetch(). The second
- * argument passed to this function must be the same as the corresponding
- * argument that was passed to the unixFetch() invocation.
- *
- * Or, if the third argument is NULL, then this function is being called
- * to inform the VFS layer that, according to POSIX, any existing mapping
- * may now be invalid and should be unmapped.
- */
-static int
-unixUnfetch(sqlite3_file * fd, i64 iOff, void *p)
-{
-#if SQLITE_MAX_MMAP_SIZE>0
- unixFile *pFd = (unixFile *) fd; /* The underlying database file */
- UNUSED_PARAMETER(iOff);
-
- /* If p==0 (unmap the entire file) then there must be no outstanding
- * xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
- * then there must be at least one outstanding.
- */
- assert((p == 0) == (pFd->nFetchOut == 0));
-
- /* If p!=0, it must match the iOff value. */
- assert(p == 0 || p == &((u8 *) pFd->pMapRegion)[iOff]);
-
- if (p) {
- pFd->nFetchOut--;
- } else {
- unixUnmapfile(pFd);
- }
-
- assert(pFd->nFetchOut >= 0);
-#else
- UNUSED_PARAMETER(fd);
- UNUSED_PARAMETER(p);
- UNUSED_PARAMETER(iOff);
-#endif
- return SQLITE_OK;
-}
-
-/*
- * Here ends the implementation of all sqlite3_file methods.
- *
- ********************* End sqlite3_file Methods *******************************
- *****************************************************************************/
-
-/*
- * 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.
- *
- * For finder-function F, two objects are created:
- *
- * (1) The real finder-function named "FImpt()".
- *
- * (2) A constant pointer to this function named just "F".
- *
- *
- * A pointer to the F pointer is used as the pAppData value for VFS
- * objects. We have to do this instead of letting pAppData point
- * directly at the finder-function since C90 rules prevent a void*
- * from be cast into a function pointer.
- *
- *
- * Each instance of this macro generates two objects:
- *
- * * A constant sqlite3_io_methods object call METHOD that has locking
- * methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
- *
- * * An I/O method finder function called FINDER that returns a pointer
- * to the METHOD object in the previous bullet.
- */
-#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \
-static const sqlite3_io_methods METHOD = { \
- VERSION, /* iVersion */ \
- CLOSE, /* xClose */ \
- unixRead, /* xRead */ \
- unixWrite, /* xWrite */ \
- unixTruncate, /* xTruncate */ \
- unixSync, /* xSync */ \
- unixFileSize, /* xFileSize */ \
- LOCK, /* xLock */ \
- UNLOCK, /* xUnlock */ \
- CKLOCK, /* xCheckReservedLock */ \
- unixFileControl, /* xFileControl */ \
- unixSectorSize, /* xSectorSize */ \
- unixDeviceCharacteristics, /* xDeviceCapabilities */ \
- SHMMAP, /* xShmMap */ \
- unixShmLock, /* xShmLock */ \
- unixShmBarrier, /* xShmBarrier */ \
- unixShmUnmap, /* xShmUnmap */ \
- unixFetch, /* xFetch */ \
- unixUnfetch, /* xUnfetch */ \
-}; \
-static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
- UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
- return &METHOD; \
-} \
-static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
- = FINDER##Impl;
-
-/*
- * Here are all of the sqlite3_io_methods objects for each of the
- * locking strategies. Functions that return pointers to these methods
- * are also created.
- */
-IOMETHODS(posixIoFinder, /* Finder function name */
- posixIoMethods, /* sqlite3_io_methods object name */
- 3, /* shared memory and mmap are enabled */
- unixClose, /* xClose method */
- unixLock, /* xLock method */
- unixUnlock, /* xUnlock method */
- unixCheckReservedLock, /* xCheckReservedLock method */
- unixShmMap /* xShmMap method */
- )
- IOMETHODS(nolockIoFinder, /* Finder function name */
- nolockIoMethods, /* sqlite3_io_methods object name */
- 3, /* shared memory is disabled */
- nolockClose, /* xClose method */
- nolockLock, /* xLock method */
- nolockUnlock, /* xUnlock method */
- nolockCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
- IOMETHODS(dotlockIoFinder, /* Finder function name */
- dotlockIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- dotlockClose, /* xClose method */
- dotlockLock, /* xLock method */
- dotlockUnlock, /* xUnlock method */
- dotlockCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#if SQLITE_ENABLE_LOCKING_STYLE
- IOMETHODS(flockIoFinder, /* Finder function name */
- flockIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- flockClose, /* xClose method */
- flockLock, /* xLock method */
- flockUnlock, /* xUnlock method */
- flockCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- IOMETHODS(afpIoFinder, /* Finder function name */
- afpIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- afpClose, /* xClose method */
- afpLock, /* xLock method */
- afpUnlock, /* xUnlock method */
- afpCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-/*
- * The proxy locking method is a "super-method" in the sense that it
- * opens secondary file descriptors for the conch and lock files and
- * it uses proxy, dot-file, AFP, and flock() locking methods on those
- * secondary files. For this reason, the division that implements
- * proxy locking is located much further down in the file. But we need
- * to go ahead and define the sqlite3_io_methods and finder function
- * for proxy locking here. So we forward declare the I/O methods.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-static int
-proxyClose(sqlite3_file *);
-static int
-proxyLock(sqlite3_file *, int);
-static int
-proxyUnlock(sqlite3_file *, int);
-static int
-proxyCheckReservedLock(sqlite3_file *, int *);
-IOMETHODS(proxyIoFinder, /* Finder function name */
- proxyIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- proxyClose, /* xClose method */
- proxyLock, /* xLock method */
- proxyUnlock, /* xUnlock method */
- proxyCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- IOMETHODS(nfsIoFinder, /* Finder function name */
- nfsIoMethods, /* sqlite3_io_methods object name */
- 1, /* shared memory is disabled */
- unixClose, /* xClose method */
- unixLock, /* xLock method */
- nfsUnlock, /* xUnlock method */
- unixCheckReservedLock, /* xCheckReservedLock method */
- 0 /* xShmMap method */
- )
-#endif
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
- * 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.
- */
-static const sqlite3_io_methods *
-autolockIoFinderImpl(const char *filePath, /* name of the database file */
- unixFile * pNew /* open file object for the database file */
- )
-{
- static const struct Mapping {
- const char *zFilesystem; /* Filesystem type name */
- const sqlite3_io_methods *pMethods; /* Appropriate locking method */
- } aMap[] = {
- {
- "hfs", &posixIoMethods}, {
- "ufs", &posixIoMethods}, {
- "afpfs", &afpIoMethods}, {
- "smbfs", &afpIoMethods}, {
- "webdav", &nolockIoMethods}, {
- 0, 0}
- };
- int i;
- struct statfs fsInfo;
- 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) {
- if (fsInfo.f_flags & MNT_RDONLY) {
- return &nolockIoMethods;
- }
- for (i = 0; aMap[i].zFilesystem; i++) {
- if (strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem) ==
- 0) {
- return aMap[i].pMethods;
- }
- }
- }
-
- /* Default case. Handles, amongst others, "nfs".
- * Test byte-range lock using fcntl(). If the call succeeds,
- * assume that the file-system supports POSIX style locks.
- */
- lockInfo.l_len = 1;
- lockInfo.l_start = 0;
- lockInfo.l_whence = SEEK_SET;
- lockInfo.l_type = F_RDLCK;
- if (osFcntl(pNew->h, F_GETLK, &lockInfo) != -1) {
- if (strcmp(fsInfo.f_fstypename, "nfs") == 0) {
- return &nfsIoMethods;
- } else {
- return &posixIoMethods;
- }
- } else {
- return &dotlockIoMethods;
- }
-}
-
-static const sqlite3_io_methods
- * (*const autolockIoFinder)(const char *, unixFile *) =
- autolockIoFinderImpl;
-
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
-
-/*
- * An abstract type for a pointer to an IO method finder function:
- */
-typedef const sqlite3_io_methods *(*finder_type) (const char *, unixFile *);
-
-/****************************************************************************
- *************************** sqlite3_vfs methods ****************************
- *
- * This division contains the implementation of methods on the
- * sqlite3_vfs object.
- */
-
-/*
- * Initialize the contents of the unixFile structure pointed to by pId.
- */
-static int
-fillInUnixFile(sqlite3_vfs * pVfs, /* Pointer to vfs object */
- int h, /* Open file descriptor of file being opened */
- sqlite3_file * pId, /* Write to the unixFile structure here */
- const char *zFilename, /* Name of the file being opened */
- int ctrlFlags /* Zero or more UNIXFILE_* values */
- )
-{
- const sqlite3_io_methods *pLockingStyle;
- unixFile *pNew = (unixFile *) pId;
- int rc = SQLITE_OK;
-
- assert(pNew->pInode == NULL);
-
- /* Usually the path zFilename should not be a relative pathname. The
- * exception is when opening the proxy "conch" file in builds that
- * include the special Apple locking styles.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- assert(zFilename == 0 || zFilename[0] == '/'
- || pVfs->pAppData == (void *)&autolockIoFinder);
-#else
- assert(zFilename == 0 || zFilename[0] == '/');
-#endif
-
- /* No locking occurs in temporary files */
- assert(zFilename != 0 || (ctrlFlags & UNIXFILE_NOLOCK) != 0);
-
- pNew->h = h;
- pNew->pVfs = pVfs;
- pNew->zPath = zFilename;
- pNew->ctrlFlags = (u8) ctrlFlags;
-#if SQLITE_MAX_MMAP_SIZE>0
- pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
-#endif
- if (strcmp(pVfs->zName, "unix-excl") == 0) {
- pNew->ctrlFlags |= UNIXFILE_EXCL;
- }
- if (ctrlFlags & UNIXFILE_NOLOCK) {
- pLockingStyle = &nolockIoMethods;
- } else {
- pLockingStyle =
- (**(finder_type *) pVfs->pAppData) (zFilename, pNew);
-#if SQLITE_ENABLE_LOCKING_STYLE
- /* Cache zFilename in the locking context (AFP and dotlock override) for
- * proxyLock activation is possible (remote proxy is based on db name)
- * zFilename remains valid until file is closed, to support
- */
- pNew->lockingContext = (void *)zFilename;
-#endif
- }
-
- if (pLockingStyle == &posixIoMethods
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- || pLockingStyle == &nfsIoMethods
-#endif
- ) {
- rc = findInodeInfo(pNew, &pNew->pInode);
- if (rc != SQLITE_OK) {
- /* If an error occurred in findInodeInfo(), close the file descriptor
- * immediately. findInodeInfo() may fail
- * in two scenarios:
- *
- * (a) A call to fstat() failed.
- * (b) A malloc failed.
- *
- * Scenario (b) may only occur if the process is holding no other
- * file descriptors open on the same file. If there were other file
- * descriptors on this file, then no malloc would be required by
- * findInodeInfo(). If this is the case, it is quite safe to close
- * handle h - as it is guaranteed that no posix locks will be released
- * by doing so.
- *
- * If scenario (a) caused the error then things are not so safe. The
- * implicit assumption here is that if fstat() fails, things are in
- * such bad shape that dropping a lock or two doesn't matter much.
- */
- robust_close(pNew, h, __LINE__);
- h = -1;
- }
- }
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- else if (pLockingStyle == &afpIoMethods) {
- /* AFP locking uses the file path so it needs to be included in
- * the afpLockingContext.
- */
- afpLockingContext *pCtx;
- pNew->lockingContext = pCtx = sqlite3_malloc64(sizeof(*pCtx));
- if (pCtx == 0) {
- rc = SQLITE_NOMEM_BKPT;
- } else {
- /* NB: zFilename exists and remains valid until the file is closed
- * according to requirement F11141. So we do not need to make a
- * copy of the filename.
- */
- pCtx->dbPath = zFilename;
- pCtx->reserved = 0;
- srandomdev();
- rc = findInodeInfo(pNew, &pNew->pInode);
- if (rc != SQLITE_OK) {
- sqlite3_free(pNew->lockingContext);
- robust_close(pNew, h, __LINE__);
- h = -1;
- }
- }
- }
-#endif
-
- else if (pLockingStyle == &dotlockIoMethods) {
- /* Dotfile locking uses the file path so it needs to be included in
- * the dotlockLockingContext
- */
- char *zLockFile;
- int nFilename;
- assert(zFilename != 0);
- nFilename = (int)strlen(zFilename) + 6;
- zLockFile = (char *)sqlite3_malloc64(nFilename);
- if (zLockFile == 0) {
- rc = SQLITE_NOMEM_BKPT;
- } else {
- sqlite3_snprintf(nFilename, zLockFile,
- "%s" DOTLOCK_SUFFIX, zFilename);
- }
- pNew->lockingContext = zLockFile;
- }
- storeLastErrno(pNew, 0);
- if (rc != SQLITE_OK) {
- if (h >= 0)
- robust_close(pNew, h, __LINE__);
- } else {
- pNew->pMethod = pLockingStyle;
- OpenCounter(+1);
- verifyDbFile(pNew);
- }
- return rc;
-}
-
-/*
- * Return the name of a directory in which to put temporary files.
- * If no suitable temporary file directory can be found, return NULL.
- */
-static const char *
-unixTempFileDir(void)
-{
- static const char *azDirs[] = {
- 0,
- 0,
- "/var/tmp",
- "/usr/tmp",
- "/tmp",
- "."
- };
- unsigned int i = 0;
- struct stat buf;
- const char *zDir = sqlite3_temp_directory;
-
- if (!azDirs[0])
- azDirs[0] = getenv("SQLITE_TMPDIR");
- if (!azDirs[1])
- azDirs[1] = getenv("TMPDIR");
- while (1) {
- if (zDir != 0 && osStat(zDir, &buf) == 0 && S_ISDIR(buf.st_mode)
- && osAccess(zDir, 03) == 0) {
- return zDir;
- }
- if (i >= sizeof(azDirs) / sizeof(azDirs[0]))
- break;
- zDir = azDirs[i++];
- }
- return 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(int nBuf, char *zBuf)
-{
- const char *zDir;
- int iLimit = 0;
-
- /* 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.
- */
- zBuf[0] = 0;
- SimulateIOError(return SQLITE_IOERR);
-
- zDir = unixTempFileDir();
- if (zDir == 0)
- return SQLITE_IOERR_GETTEMPPATH;
- do {
- u64 r;
- sqlite3_randomness(sizeof(r), &r);
- assert(nBuf > 2);
- zBuf[nBuf - 2] = 0;
- sqlite3_snprintf(nBuf, zBuf,
- "%s/" SQLITE_TEMP_FILE_PREFIX "%llx%c", zDir,
- r, 0);
- if (zBuf[nBuf - 2] != 0 || (iLimit++) > 10)
- return SQLITE_ERROR;
- } while (osAccess(zBuf, 0) == 0);
- return SQLITE_OK;
-}
-
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
-/*
- * Routine to transform a unixFile into a proxy-locking unixFile.
- * Implementation in the proxy-lock division, but used by unixOpen()
- * if SQLITE_PREFER_PROXY_LOCKING is defined.
- */
-static int proxyTransformUnixFile(unixFile *, const char *);
-#endif
-
-/*
- * Search for an unused file descriptor that was opened on the database
- * file (not a journal or master-journal file) identified by pathname
- * zPath with SQLITE_OPEN_XXX flags matching those passed as the second
- * argument to this function.
- *
- * Such a file descriptor may exist if a database connection was closed
- * but the associated file descriptor could not be closed because some
- * other file descriptor open on the same file is holding a file-lock.
- * Refer to comments in the unixClose() function and the lengthy comment
- * describing "Posix Advisory Locking" at the start of this file for
- * further details. Also, ticket #4018.
- *
- * If a suitable file descriptor is found, then it is returned. If no
- * such file descriptor is located, -1 is returned.
- */
-static UnixUnusedFd *
-findReusableFd(const char *zPath, int flags)
-{
- UnixUnusedFd *pUnused = 0;
-
- struct stat sStat; /* Results of stat() call */
-
- /* A stat() call may fail for various reasons. If this happens, it is
- * almost certain that an open() call on the same path will also fail.
- * For this reason, if an error occurs in the stat() call here, it is
- * ignored and -1 is returned. The caller will try to open a new file
- * descriptor on the same path, fail, and return an error to SQLite.
- *
- * Even if a subsequent open() call does succeed, the consequences of
- * not searching for a reusable file descriptor are not dire.
- */
- if (0 == osStat(zPath, &sStat)) {
- unixInodeInfo *pInode;
-
- pInode = inodeList;
- while (pInode && (pInode->fileId.dev != sStat.st_dev
- || pInode->fileId.ino !=
- (u64) sStat.st_ino)) {
- pInode = pInode->pNext;
- }
- if (pInode) {
- UnixUnusedFd **pp;
- for (pp = &pInode->pUnused;
- *pp && (*pp)->flags != flags;
- pp = &((*pp)->pNext)) ;
- pUnused = *pp;
- if (pUnused) {
- *pp = pUnused->pNext;
- }
- }
- }
- return pUnused;
-}
-
-/*
- * Find the mode, uid and gid of file zFile.
- */
-static int
-getFileMode(const char *zFile, /* File name */
- mode_t * pMode, /* OUT: Permissions of zFile */
- uid_t * pUid, /* OUT: uid of zFile. */
- gid_t * pGid /* OUT: gid of zFile. */
- )
-{
- struct stat sStat; /* Output of stat() on database file */
- int rc = SQLITE_OK;
- if (0 == osStat(zFile, &sStat)) {
- *pMode = sStat.st_mode & 0777;
- *pUid = sStat.st_uid;
- *pGid = sStat.st_gid;
- } else {
- rc = SQLITE_IOERR_FSTAT;
- }
- return rc;
-}
-
-/*
- * This function is called by unixOpen() to determine the unix permissions
- * to create new files with. If no error occurs, then SQLITE_OK is returned
- * and a value suitable for passing as the third argument to open(2) is
- * written to *pMode. If an IO error occurs, an SQLite error code is
- * returned and the value of *pMode is not modified.
- *
- * In most cases, this routine sets *pMode to 0, which will become
- * an indication to robust_open() to create the file using
- * SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
- * But if the file being opened is a regular journal file, then
- * this function queries the file-system for the permissions on the
- * corresponding database file and sets *pMode to this value. Whenever
- * possible, journal files are created using the same permissions
- * as the associated database file.
- *
- * If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
- * original filename is unavailable. But 8_3_NAMES is only used for
- * FAT filesystems and permissions do not matter there, so just use
- * the default permissions.
- */
-static int
-findCreateFileMode(const char *zPath, /* Path of file (possibly) being created */
- int flags, /* Flags passed as 4th argument to xOpen() */
- mode_t * pMode, /* OUT: Permissions to open file with */
- uid_t * pUid, /* OUT: uid to set on the file */
- gid_t * pGid /* OUT: gid to set on the file */
- )
-{
- int rc = SQLITE_OK; /* Return Code */
- *pMode = 0;
- *pUid = 0;
- *pGid = 0;
- if (flags & SQLITE_OPEN_DELETEONCLOSE) {
- *pMode = 0600;
- } else if (flags & SQLITE_OPEN_URI) {
- /* If this is a main database file and the file was opened using a URI
- * filename, check for the "modeof" parameter. If present, interpret
- * its value as a filename and try to copy the mode, uid and gid from
- * that file.
- */
- const char *z = sqlite3_uri_parameter(zPath, "modeof");
- if (z) {
- rc = getFileMode(z, pMode, pUid, pGid);
- }
- }
- return rc;
-}
-
-/*
- * 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, /* 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 */
- )
-{
- unixFile *p = (unixFile *) pFile;
- int fd = -1; /* File descriptor returned by 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; /* Function Return Code */
- int ctrlFlags = 0; /* UNIXFILE_* flags */
-
- 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 SQLITE_ENABLE_LOCKING_STYLE
- int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
-#endif
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
- struct statfs fsInfo;
-#endif
-
- /* 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 syncDir = isCreate;
-
- /* If argument zPath is a NULL pointer, this function is required to open
- * a temporary file. Use this buffer to store the file name in.
- */
- char zTmpname[MAX_PATHNAME + 2];
- const char *zName = zPath;
-
- /* 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);
-
- /* Detect a pid change and reset the PRNG. There is a race condition
- * here such that two or more threads all trying to open databases at
- * the same instant might all reset the PRNG. But multiple resets
- * are harmless.
- */
- if (randomnessPid != getpid()) {
- randomnessPid = getpid();
- sqlite3_randomness(0, 0);
- }
-
- memset(p, 0, sizeof(unixFile));
-
- if (eType == SQLITE_OPEN_MAIN_DB) {
- UnixUnusedFd *pUnused;
- pUnused = findReusableFd(zName, flags);
- if (pUnused) {
- fd = pUnused->fd;
- } else {
- pUnused = sqlite3_malloc64(sizeof(*pUnused));
- if (!pUnused) {
- return SQLITE_NOMEM_BKPT;
- }
- }
- p->pUnused = pUnused;
-
- /* Database filenames are double-zero terminated if they are not
- * URIs with parameters. Hence, they can always be passed into
- * sqlite3_uri_parameter().
- */
- assert((flags & SQLITE_OPEN_URI)
- || zName[strlen(zName) + 1] == 0);
-
- } else if (!zName) {
- /* If zName is NULL, the upper layer is requesting a temp file. */
- assert(isDelete);
- rc = unixGetTempname(pVfs->mxPathname, zTmpname);
- if (rc != SQLITE_OK) {
- return rc;
- }
- zName = zTmpname;
-
- /* Generated temporary filenames are always double-zero terminated
- * for use by sqlite3_uri_parameter().
- */
- assert(zName[strlen(zName) + 1] == 0);
- }
-
- /* Determine the value of the flags parameter passed to POSIX function
- * open(). These must be calculated even if open() is not called, as
- * they may be stored as part of the file handle and used by the
- * 'conch file' locking functions later on.
- */
- if (isReadonly)
- openFlags |= O_RDONLY;
- if (isReadWrite)
- openFlags |= O_RDWR;
- if (isCreate)
- openFlags |= O_CREAT;
- if (isExclusive)
- openFlags |= (O_EXCL | O_NOFOLLOW);
- openFlags |= (O_LARGEFILE | O_BINARY);
-
- if (fd < 0) {
- mode_t openMode; /* Permissions to create file with */
- uid_t uid; /* Userid for the file */
- gid_t gid; /* Groupid for the file */
- rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
- if (rc != SQLITE_OK) {
- assert(!p->pUnused);
- return rc;
- }
- fd = robust_open(zName, openFlags, openMode);
- assert(!isExclusive || (openFlags & O_CREAT) != 0);
- if (fd < 0 && errno != EISDIR && isReadWrite) {
- /* Failed to open the file for read/write access. Try read-only. */
- flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
- openFlags &= ~(O_RDWR | O_CREAT);
- flags |= SQLITE_OPEN_READONLY;
- openFlags |= O_RDONLY;
- isReadonly = 1;
- fd = robust_open(zName, openFlags, openMode);
- }
- if (fd < 0) {
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
- goto open_finished;
- }
-
- }
- assert(fd >= 0);
- if (pOutFlags) {
- *pOutFlags = flags;
- }
-
- if (p->pUnused) {
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
- }
-
- if (isDelete) {
-
-#if defined(SQLITE_UNLINK_AFTER_CLOSE)
- zPath = sqlite3_mprintf("%s", zName);
- if (zPath == 0) {
- robust_close(p, fd, __LINE__);
- return SQLITE_NOMEM_BKPT;
- }
-#else
- osUnlink(zName);
-#endif
- }
-#if SQLITE_ENABLE_LOCKING_STYLE
- else {
- p->openFlags = openFlags;
- }
-#endif
-
-#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
- if (fstatfs(fd, &fsInfo) == -1) {
- storeLastErrno(p, errno);
- robust_close(p, fd, __LINE__);
- return SQLITE_IOERR_ACCESS;
- }
- if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
- ((unixFile *) pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
- }
- if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
- ((unixFile *) pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
- }
-#endif
-
- /* Set up appropriate ctrlFlags */
- if (isDelete)
- ctrlFlags |= UNIXFILE_DELETE;
- if (isReadonly)
- ctrlFlags |= UNIXFILE_RDONLY;
- noLock = eType != SQLITE_OPEN_MAIN_DB;
- if (noLock)
- ctrlFlags |= UNIXFILE_NOLOCK;
- if (syncDir)
- ctrlFlags |= UNIXFILE_DIRSYNC;
- if (flags & SQLITE_OPEN_URI)
- ctrlFlags |= UNIXFILE_URI;
-
-#if SQLITE_ENABLE_LOCKING_STYLE
-#if SQLITE_PREFER_PROXY_LOCKING
- isAutoProxy = 1;
-#endif
- if (isAutoProxy && (zPath != NULL) && (!noLock) && pVfs->xOpen) {
- char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
- int useProxy = 0;
-
- /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
- * never use proxy, NULL means use proxy for non-local files only.
- */
- if (envforce != NULL) {
- useProxy = atoi(envforce) > 0;
- } else {
- useProxy = !(fsInfo.f_flags & MNT_LOCAL);
- }
- if (useProxy) {
- rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
- if (rc == SQLITE_OK) {
- rc = proxyTransformUnixFile((unixFile *) pFile,
- ":auto:");
- if (rc != SQLITE_OK) {
- /* Use unixClose to clean up the resources added in fillInUnixFile
- * and clear all the structure's references. Specifically,
- * pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
- */
- unixClose(pFile);
- return rc;
- }
- }
- goto open_finished;
- }
- }
-#endif
-
- rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
-
- open_finished:
- if (rc != SQLITE_OK) {
- sqlite3_free(p->pUnused);
- }
- return rc;
-}
-
-/*
- * Delete the file at zPath. If the dirSync argument is true, fsync()
- * the directory after deleting the file.
- */
-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);
- if (osUnlink(zPath) == (-1)) {
- if (errno == ENOENT) {
- rc = SQLITE_IOERR_DELETE_NOENT;
- } else {
- rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ *pp = 0;
+
+#if SQLITE_MAX_MMAP_SIZE>0
+ if (pFd->mmapSizeMax > 0) {
+ if (pFd->pMapRegion == 0) {
+ int rc = unixMapfile(pFd, -1);
+ if (rc != SQLITE_OK)
+ return rc;
}
- return rc;
- }
-#ifndef SQLITE_DISABLE_DIRSYNC
- if ((dirSync & 1) != 0) {
- int fd;
- rc = osOpenDirectory(zPath, &fd);
- if (rc == SQLITE_OK) {
- if (full_fsync(fd, 0, 0)) {
- rc = unixLogError(SQLITE_IOERR_DIR_FSYNC,
- "fsync", zPath);
- }
- robust_close(0, fd, __LINE__);
- } else {
- assert(rc == SQLITE_CANTOPEN);
- rc = SQLITE_OK;
+ if (pFd->mmapSize >= iOff + nAmt) {
+ *pp = &((u8 *) pFd->pMapRegion)[iOff];
+ pFd->nFetchOut++;
}
}
#endif
- return rc;
-}
-
-/*
- * Test the existence 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 * 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 */
- )
-{
- UNUSED_PARAMETER(NotUsed);
- SimulateIOError(return SQLITE_IOERR_ACCESS;
- );
- assert(pResOut != 0);
-
- /* The spec says there are three possible values for flags. But only
- * two of them are actually used
- */
- assert(flags == SQLITE_ACCESS_EXISTS
- || flags == SQLITE_ACCESS_READWRITE);
-
- if (flags == SQLITE_ACCESS_EXISTS) {
- struct stat buf;
- *pResOut = (0 == osStat(zPath, &buf) && buf.st_size > 0);
- } else {
- *pResOut = osAccess(zPath, W_OK | R_OK) == 0;
- }
- return SQLITE_OK;
-}
-
-/*
- *
- */
-static int
-mkFullPathname(const char *zPath, /* Input path */
- char *zOut, /* Output buffer */
- int nOut /* Allocated size of buffer zOut */
- )
-{
- int nPath = sqlite3Strlen30(zPath);
- int iOff = 0;
- if (zPath[0] != '/') {
- if (osGetcwd(zOut, nOut - 2) == 0) {
- return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd",
- zPath);
- }
- iOff = sqlite3Strlen30(zOut);
- zOut[iOff++] = '/';
- }
- if ((iOff + nPath + 1) > nOut) {
- /* SQLite assumes that xFullPathname() nul-terminates the output buffer
- * even if it returns an error.
- */
- zOut[iOff] = '\0';
- return SQLITE_CANTOPEN_BKPT;
- }
- sqlite3_snprintf(nOut - iOff, &zOut[iOff], "%s", zPath);
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.
+ * If the third argument is non-NULL, then this function releases a
+ * reference obtained by an earlier call to unixFetch(). The second
+ * argument passed to this function must be the same as the corresponding
+ * argument that was passed to the unixFetch() invocation.
*
- * 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.
+ * Or, if the third argument is NULL, then this function is being called
+ * to inform the VFS layer that, according to POSIX, any existing mapping
+ * may now be invalid and should be unmapped.
*/
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 */
- )
+unixUnfetch(sqlite3_file * fd, i64 iOff, void *p)
{
- (void)pVfs;
-#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
- return mkFullPathname(zPath, zOut, nOut);
-#else
- int rc = SQLITE_OK;
- int nByte;
- int nLink = 1; /* Number of symbolic links followed so far */
- const char *zIn = zPath; /* Input path for each iteration of loop */
- char *zDel = 0;
-
- assert(pVfs->mxPathname == MAX_PATHNAME);
- UNUSED_PARAMETER(pVfs);
+ unixFile *pFd = (unixFile *) fd; /* The underlying database file */
+ UNUSED_PARAMETER(iOff);
- /* 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 directory has been unlinked.
+ /* If p==0 (unmap the entire file) then there must be no outstanding
+ * xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
+ * then there must be at least one outstanding.
*/
- SimulateIOError(return SQLITE_ERROR);
-
- do {
-
- /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
- * link, or false otherwise.
- */
- int bLink = 0;
- struct stat buf;
- if (osLstat(zIn, &buf) != 0) {
- if (errno != ENOENT) {
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat",
- zIn);
- }
- } else {
- bLink = S_ISLNK(buf.st_mode);
- }
-
- if (bLink) {
- if (zDel == 0) {
- zDel = sqlite3_malloc(nOut);
- if (zDel == 0)
- rc = SQLITE_NOMEM_BKPT;
- } else if (++nLink > SQLITE_MAX_SYMLINKS) {
- rc = SQLITE_CANTOPEN_BKPT;
- }
-
- if (rc == SQLITE_OK) {
- nByte = osReadlink(zIn, zDel, nOut - 1);
- if (nByte < 0) {
- rc = unixLogError(SQLITE_CANTOPEN_BKPT,
- "readlink", zIn);
- } else {
- if (zDel[0] != '/') {
- int n;
- for (n = sqlite3Strlen30(zIn);
- n > 0 && zIn[n - 1] != '/';
- n--) ;
- if (nByte + n + 1 > nOut) {
- rc = SQLITE_CANTOPEN_BKPT;
- } else {
- memmove(&zDel[n], zDel,
- nByte + 1);
- memcpy(zDel, zIn, n);
- nByte += n;
- }
- }
- zDel[nByte] = '\0';
- }
- }
-
- zIn = zDel;
- }
-
- assert(rc != SQLITE_OK || zIn != zOut || zIn[0] == '/');
- if (rc == SQLITE_OK && zIn != zOut) {
- rc = mkFullPathname(zIn, zOut, nOut);
- }
- if (bLink == 0)
- break;
- zIn = zOut;
- } while (rc == SQLITE_OK);
-
- sqlite3_free(zDel);
- return rc;
-#endif /* HAVE_READLINK && HAVE_LSTAT */
-}
+ assert((p == 0) == (pFd->nFetchOut == 0));
-/*
- * Write nBuf bytes of random data to the supplied buffer zBuf.
- */
-static int
-unixRandomness(sqlite3_vfs * NotUsed, int nBuf, char *zBuf)
-{
- UNUSED_PARAMETER(NotUsed);
- assert((size_t) nBuf >= (sizeof(time_t) + sizeof(int)));
+ /* If p!=0, it must match the iOff value. */
+ assert(p == 0 || p == &((u8 *) pFd->pMapRegion)[iOff]);
- /* 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
- * uninitialized space in zBuf - but valgrind errors tend to worry
- * some users. Rather than argue, it seems easier just to initialize
- * the whole array and silence valgrind, even if that means less randomness
- * in the random seed.
- *
- * When testing, initializing zBuf[] to zero is all we do. That means
- * that we always use the same random number sequence. This makes the
- * tests repeatable.
- */
- memset(zBuf, 0, nBuf);
- randomnessPid = getpid();
-#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
- {
- int fd, got;
- fd = robust_open("/dev/urandom", O_RDONLY, 0);
- if (fd < 0) {
- time_t t;
- time(&t);
- memcpy(zBuf, &t, sizeof(t));
- memcpy(&zBuf[sizeof(t)], &randomnessPid,
- sizeof(randomnessPid));
- assert(sizeof(t) + sizeof(randomnessPid) <=
- (size_t) nBuf);
- nBuf = sizeof(t) + sizeof(randomnessPid);
- } else {
- do {
- got = osRead(fd, zBuf, nBuf);
- } while (got < 0 && errno == EINTR);
- robust_close(0, fd, __LINE__);
- }
+ if (p) {
+ pFd->nFetchOut--;
+ } else {
+ unixUnmapfile(pFd);
}
-#endif
- return nBuf;
-}
-/*
- * Sleep for a little while. Return the amount of time slept.
- * 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.
- */
-static int
-unixSleep(sqlite3_vfs * NotUsed, int microseconds)
-{
-#if defined(HAVE_USLEEP) && HAVE_USLEEP
- usleep(microseconds);
- UNUSED_PARAMETER(NotUsed);
- return microseconds;
-#else
- int seconds = (microseconds + 999999) / 1000000;
- sleep(seconds);
- UNUSED_PARAMETER(NotUsed);
- return seconds * 1000000;
-#endif
+ assert(pFd->nFetchOut >= 0);
+ return SQLITE_OK;
}
/*
- * 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 sql_current_time = 0; /* Fake system time in seconds since 1970. */
-#endif
-
-/*
- * Find the current time (in Universal Coordinated Time). Write into *piNow
- * the current time and date as a Julian Day number times 86_400_000. In
- * other words, write into *piNow the number of milliseconds since the Julian
- * epoch of noon in Greenwich on November 24, 4714 B.C according to the
- * proleptic Gregorian calendar.
+ * Here ends the implementation of all sqlite3_file methods.
*
- * On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
- * cannot be found.
- */
-static int
-unixCurrentTimeInt64(sqlite3_vfs * NotUsed, sqlite3_int64 * piNow)
-{
- static const sqlite3_int64 unixEpoch =
- 24405875 * (sqlite3_int64) 8640000;
- int rc = SQLITE_OK;
-#if defined(NO_GETTOD)
- time_t t;
- time(&t);
- *piNow = ((sqlite3_int64) t) * 1000 + unixEpoch;
-#else
- struct timeval sNow;
- (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
- *piNow =
- unixEpoch + 1000 * (sqlite3_int64) sNow.tv_sec +
- sNow.tv_usec / 1000;
-#endif
-
-#ifdef SQLITE_TEST
- if (sql_current_time) {
- *piNow =
- 1000 * (sqlite3_int64) sql_current_time + unixEpoch;
- }
-#endif
- UNUSED_PARAMETER(NotUsed);
- return rc;
-}
-
-/*
- * The xGetLastError() method is designed to return a better
- * low-level error message when operating-system problems come up
- * during SQLite operation. Only the integer return code is currently
- * used.
- */
-static int
-unixGetLastError(sqlite3_vfs * NotUsed, int NotUsed2, char *NotUsed3)
-{
- UNUSED_PARAMETER(NotUsed);
- UNUSED_PARAMETER(NotUsed2);
- UNUSED_PARAMETER(NotUsed3);
- return errno;
-}
-
-/*
- *********************** End of sqlite3_vfs methods ***************************
+ ********************* End sqlite3_file Methods *******************************
*****************************************************************************/
-/******************************************************************************
- ************************* Begin Proxy Locking ********************************
- *
- * Proxy locking is a "uber-locking-method" in this sense: It uses the
- * other locking methods on secondary lock files. Proxy locking is a
- * meta-layer over top of the primitive locking implemented above. For
- * this reason, the division that implements of proxy locking is deferred
- * until late in the file (here) after all of the other I/O methods have
- * been defined - so that the primitive locking methods are available
- * as services to help with the implementation of proxy locking.
- *
- ***
- *
- * The default locking schemes in SQLite use byte-range locks on the
- * database file to coordinate safe, concurrent access by multiple readers
- * and writers [http://sqlite.org/lockingv3.html]. The five file locking
- * states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented
- * as POSIX read & write locks over fixed set of locations (via fsctl),
- * on AFP and SMB only exclusive byte-range locks are available via fsctl
- * with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states.
- * To simulate a F_RDLCK on the shared range, on AFP a randomly selected
- * address in the shared range is taken for a SHARED lock, the entire
- * shared range is taken for an EXCLUSIVE lock):
- *
- * PENDING_BYTE 0x40000000
- * RESERVED_BYTE 0x40000001
- * SHARED_RANGE 0x40000002 -> 0x40000200
- *
- * This works well on the local file system, but shows a nearly 100x
- * slowdown in read performance on AFP because the AFP client disables
- * the read cache when byte-range locks are present. Enabling the read
- * cache exposes a cache coherency problem that is present on all OS X
- * supported network file systems. NFS and AFP both observe the
- * close-to-open semantics for ensuring cache coherency
- * [http://nfs.sourceforge.net/#faq_a8], which does not effectively
- * address the requirements for concurrent database access by multiple
- * readers and writers
- * [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html].
- *
- * To address the performance and cache coherency issues, proxy file locking
- * changes the way database access is controlled by limiting access to a
- * single host at a time and moving file locks off of the database file
- * and onto a proxy file on the local file system.
- *
- *
- * Using proxy locks
- * -----------------
- *
- * C APIs
- *
- * sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE,
- * <proxy_path> | ":auto:");
- * sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE,
- * &<proxy_path>);
- *
- *
- * SQL pragmas
- *
- * PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto:
- * PRAGMA [database.]lock_proxy_file
- *
- * Specifying ":auto:" means that if there is a conch file with a matching
- * host ID in it, the proxy path in the conch file will be used, otherwise
- * a proxy path based on the user's temp dir
- * (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the
- * actual proxy file name is generated from the name and path of the
- * database file. For example:
- *
- * For database path "/Users/me/foo.db"
- * The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
- *
- * Once a lock proxy is configured for a database connection, it can not
- * be removed, however it may be switched to a different proxy path via
- * the above APIs (assuming the conch file is not being held by another
- * connection or process).
- *
- *
- * How proxy locking works
- * -----------------------
- *
- * Proxy file locking relies primarily on two new supporting files:
- *
- * * conch file to limit access to the database file to a single host
- * at a time
- *
- * * proxy file to act as a proxy for the advisory locks normally
- * taken on the database
- *
- * The conch file - to use a proxy file, sqlite must first "hold the conch"
- * by taking an sqlite-style shared lock on the conch file, reading the
- * contents and comparing the host's unique host ID (see below) and lock
- * proxy path against the values stored in the conch. The conch file is
- * stored in the same directory as the database file and the file name
- * is patterned after the database file name as ".<databasename>-conch".
- * If the conch file does not exist, or its contents do not match the
- * host ID and/or proxy path, then the lock is escalated to an exclusive
- * lock and the conch file contents is updated with the host ID and proxy
- * path and the lock is downgraded to a shared lock again. If the conch
- * is held by another process (with a shared lock), the exclusive lock
- * will fail and SQLITE_BUSY is returned.
- *
- * The proxy file - a single-byte file used for all advisory file locks
- * normally taken on the database file. This allows for safe sharing
- * of the database file for multiple readers and writers on the same
- * host (the conch ensures that they all use the same local lock file).
- *
- * Requesting the lock proxy does not immediately take the conch, it is
- * only taken when the first request to lock database file is made.
- * This matches the semantics of the traditional locking behavior, where
- * opening a connection to a database file does not take a lock on it.
- * The shared lock and an open file descriptor are maintained until
- * the connection to the database is closed.
- *
- * The proxy file and the lock file are never deleted so they only need
- * to be created the first time they are used.
- *
- * Configuration options
- * ---------------------
+/*
+ * 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.
*
- * SQLITE_PREFER_PROXY_LOCKING
+ * 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.
*
- * Database files accessed on non-local file systems are
- * automatically configured for proxy locking, lock files are
- * named automatically using the same logic as
- * PRAGMA lock_proxy_file=":auto:"
+ * For finder-function F, two objects are created:
*
- * SQLITE_PROXY_DEBUG
+ * (1) The real finder-function named "FImpt()".
*
- * Enables the logging of error messages during host id file
- * retrieval and creation
+ * (2) A constant pointer to this function named just "F".
*
- * LOCKPROXYDIR
*
- * Overrides the default directory used for lock proxy files that
- * are named automatically via the ":auto:" setting
+ * A pointer to the F pointer is used as the pAppData value for VFS
+ * objects. We have to do this instead of letting pAppData point
+ * directly at the finder-function since C90 rules prevent a void*
+ * from be cast into a function pointer.
*
- * SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
*
- * Permissions to use when creating a directory for storing the
- * lock proxy files, only used when LOCKPROXYDIR is not set.
+ * Each instance of this macro generates two objects:
*
+ * * A constant sqlite3_io_methods object call METHOD that has locking
+ * methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
*
- * As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
- * setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
- * force proxy locking to be used for every database file opened, and 0
- * will force automatic proxy locking to be disabled for all database
- * files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or
- * sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
+ * * An I/O method finder function called FINDER that returns a pointer
+ * to the METHOD object in the previous bullet.
*/
+#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE) \
+static const sqlite3_io_methods METHOD = { \
+ VERSION, /* iVersion */ \
+ CLOSE, /* xClose */ \
+ unixRead, /* xRead */ \
+ unixWrite, /* xWrite */ \
+ unixFileControl, /* xFileControl */ \
+ unixFetch, /* xFetch */ \
+ unixUnfetch, /* xUnfetch */ \
+}; \
+static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
+ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
+ return &METHOD; \
+} \
+static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
+ = FINDER##Impl;
/*
- * Proxy locking is only available on MacOSX
+ * Here are all of the sqlite3_io_methods objects for each of the
+ * locking strategies. Functions that return pointers to these methods
+ * are also created.
*/
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+IOMETHODS(posixIoFinder, /* Finder function name */
+ posixIoMethods, /* sqlite3_io_methods object name */
+ 3, /* shared memory and mmap are enabled */
+ unixClose /* xClose method */
+ )
+ IOMETHODS(nolockIoFinder, /* Finder function name */
+ nolockIoMethods, /* sqlite3_io_methods object name */
+ 3, /* shared memory is disabled */
+ nolockClose /* xClose method */
+ )
/*
- * The proxyLockingContext has the path and file structures for the remote
- * and local proxy files in it
+ * An abstract type for a pointer to an IO method finder function:
+ */
+typedef const sqlite3_io_methods *(*finder_type) (const char *, unixFile *);
+
+/****************************************************************************
+ *************************** sqlite3_vfs methods ****************************
+ *
+ * This division contains the implementation of methods on the
+ * sqlite3_vfs object.
*/
-typedef struct proxyLockingContext proxyLockingContext;
-struct proxyLockingContext {
- 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; /* 1 if the conch is held, -1 if lockless */
- int nFails; /* Number of conch taking failures */
- void *oldLockingContext; /* Original lockingcontext to restore on close */
- sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
-};
/*
- * The proxy lock file path for the database at dbPath is written into lPath,
- * which must point to valid, writable memory large enough for a maxLen length
- * file path.
+ * Initialize the contents of the unixFile structure pointed to by pId.
*/
static int
-proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen)
+fillInUnixFile(sqlite3_vfs * pVfs, /* Pointer to vfs object */
+ int h, /* Open file descriptor of file being opened */
+ sqlite3_file * pId, /* Write to the unixFile structure here */
+ const char *zFilename, /* Name of the file being opened */
+ int ctrlFlags /* Zero or more UNIXFILE_* values */
+ )
{
- int len;
- int dbLen;
- int i;
-
-#ifdef LOCKPROXYDIR
- len = strlcpy(lPath, LOCKPROXYDIR, maxLen);
-#else
-#ifdef _CS_DARWIN_USER_TEMP_DIR
- {
- if (!confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen)) {
- return SQLITE_IOERR_LOCK;
- }
- len = strlcat(lPath, "sqliteplocks", maxLen);
- }
-#else
- len = strlcpy(lPath, "/tmp/", maxLen);
-#endif
+ const sqlite3_io_methods *pLockingStyle;
+ unixFile *pNew = (unixFile *) pId;
+ int rc = SQLITE_OK;
+
+ assert(pNew->pInode == NULL);
+
+ /* Usually the path zFilename should not be a relative pathname. The
+ * exception is when opening the proxy "conch" file in builds that
+ * include the special Apple locking styles.
+ */
+ assert(zFilename == 0 || zFilename[0] == '/');
+
+ /* No locking occurs in temporary files */
+ assert(zFilename != 0 || (ctrlFlags & UNIXFILE_NOLOCK) != 0);
+
+ pNew->h = h;
+ pNew->pVfs = pVfs;
+ pNew->zPath = zFilename;
+ pNew->ctrlFlags = (u8) ctrlFlags;
+#if SQLITE_MAX_MMAP_SIZE>0
+ pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
#endif
+ if (strcmp(pVfs->zName, "unix-excl") == 0) {
+ pNew->ctrlFlags |= UNIXFILE_EXCL;
+ }
+ if (ctrlFlags & UNIXFILE_NOLOCK) {
+ pLockingStyle = &nolockIoMethods;
+ } else {
+ pLockingStyle =
+ (**(finder_type *) pVfs->pAppData) (zFilename, pNew);
+ assert(pLockingStyle == &posixIoMethods);
+ }
- if (lPath[len - 1] != '/') {
- len = strlcat(lPath, "/", maxLen);
+ if (pLockingStyle == &posixIoMethods) {
+ rc = findInodeInfo(pNew, &pNew->pInode);
+ if (rc != SQLITE_OK) {
+ /* If an error occurred in findInodeInfo(), close the file descriptor
+ * immediately. findInodeInfo() may fail
+ * in two scenarios:
+ *
+ * (a) A call to fstat() failed.
+ * (b) A malloc failed.
+ *
+ * Scenario (b) may only occur if the process is holding no other
+ * file descriptors open on the same file. If there were other file
+ * descriptors on this file, then no malloc would be required by
+ * findInodeInfo(). If this is the case, it is quite safe to close
+ * handle h - as it is guaranteed that no posix locks will be released
+ * by doing so.
+ *
+ * If scenario (a) caused the error then things are not so safe. The
+ * implicit assumption here is that if fstat() fails, things are in
+ * such bad shape that dropping a lock or two doesn't matter much.
+ */
+ robust_close(pNew, h, __LINE__);
+ h = -1;
+ }
+ }
+ storeLastErrno(pNew, 0);
+ if (rc != SQLITE_OK) {
+ if (h >= 0)
+ robust_close(pNew, h, __LINE__);
+ } else {
+ pNew->pMethod = pLockingStyle;
+ OpenCounter(+1);
+ verifyDbFile(pNew);
}
+ return rc;
+}
+
+/*
+ * Return the name of a directory in which to put temporary files.
+ * If no suitable temporary file directory can be found, return NULL.
+ */
+static const char *
+unixTempFileDir(void)
+{
+ static const char *azDirs[] = {
+ 0,
+ 0,
+ "/var/tmp",
+ "/usr/tmp",
+ "/tmp",
+ "."
+ };
+ unsigned int i = 0;
+ struct stat buf;
+ const char *zDir = sqlite3_temp_directory;
- /* transform the db path to a unique cache name */
- dbLen = (int)strlen(dbPath);
- for (i = 0; i < dbLen && (i + len + 7) < (int)maxLen; i++) {
- char c = dbPath[i];
- lPath[i + len] = (c == '/') ? '_' : c;
+ if (!azDirs[0])
+ azDirs[0] = getenv("SQLITE_TMPDIR");
+ if (!azDirs[1])
+ azDirs[1] = getenv("TMPDIR");
+ while (1) {
+ if (zDir != 0 && stat(zDir, &buf) == 0 &&
+ S_ISDIR(buf.st_mode) && access(zDir, 03) == 0)
+ return zDir;
+ if (i >= sizeof(azDirs) / sizeof(azDirs[0]))
+ break;
+ zDir = azDirs[i++];
}
- lPath[i + len] = '\0';
- strlcat(lPath, ":auto:", maxLen);
- return SQLITE_OK;
+ return 0;
}
/*
- ** Creates the lock file and any missing directories in lockPath
+ * 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
-proxyCreateLockPath(const char *lockPath)
+unixGetTempname(int nBuf, char *zBuf)
{
- int i, len;
- char buf[MAXPATHLEN];
- int start = 0;
-
- assert(lockPath != NULL);
- /* try to create all the intermediate directories */
- len = (int)strlen(lockPath);
- buf[0] = lockPath[0];
- for (i = 1; i < len; i++) {
- if (lockPath[i] == '/' && (i - start > 0)) {
- /* only mkdir if leaf dir != "." or "/" or ".." */
- if (i - start > 2
- || (i - start == 1 && buf[start] != '.'
- && buf[start] != '/')
- || (i - start == 2 && buf[start] != '.'
- && buf[start + 1] != '.')) {
- buf[i] = '\0';
- if (osMkdir
- (buf,
- SQLITE_DEFAULT_PROXYDIR_PERMISSIONS)) {
- int err = errno;
- if (err != EEXIST) {
- return err;
- }
- }
- }
- start = i + 1;
- }
- buf[i] = lockPath[i];
- }
+ const char *zDir;
+ int iLimit = 0;
- return 0;
+ /* 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.
+ */
+ zBuf[0] = 0;
+ SimulateIOError(return SQLITE_IOERR);
+
+ zDir = unixTempFileDir();
+ if (zDir == 0)
+ return SQLITE_IOERR_GETTEMPPATH;
+ do {
+ u64 r;
+ sqlite3_randomness(sizeof(r), &r);
+ assert(nBuf > 2);
+ zBuf[nBuf - 2] = 0;
+ sqlite3_snprintf(nBuf, zBuf,
+ "%s/" SQLITE_TEMP_FILE_PREFIX "%llx%c", zDir,
+ r, 0);
+ if (zBuf[nBuf - 2] != 0 || (iLimit++) > 10)
+ return SQLITE_ERROR;
+ } while (access(zBuf, 0) == 0);
+ 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.
+ * Search for an unused file descriptor that was opened on the database
+ * file (not a journal or master-journal file) identified by pathname
+ * zPath with SQLITE_OPEN_XXX flags matching those passed as the second
+ * argument to this function.
+ *
+ * Such a file descriptor may exist if a database connection was closed
+ * but the associated file descriptor could not be closed because some
+ * other file descriptor open on the same file is holding a file-lock.
+ * Refer to comments in the unixClose() function and the lengthy comment
+ * describing "Posix Advisory Locking" at the start of this file for
+ * further details. Also, ticket #4018.
*
- * The caller is responsible not only for closing the file descriptor
- * but also for freeing the memory associated with the file descriptor.
+ * If a suitable file descriptor is found, then it is returned. If no
+ * such file descriptor is located, -1 is returned.
*/
-static int
-proxyCreateUnixFile(const char *path, /* path for the new unixFile */
- unixFile ** ppFile, /* unixFile created and returned by ref */
- int islockfile /* if non zero missing dirs will be created */
- )
+static UnixUnusedFd *
+findReusableFd(const char *zPath, int flags)
{
- int fd = -1;
- unixFile *pNew;
- int rc = SQLITE_OK;
- int openFlags = O_RDWR | O_CREAT;
- sqlite3_vfs dummyVfs;
- int terrno = 0;
- UnixUnusedFd *pUnused = NULL;
-
- /* 1. first try to open/create the file
- * 2. if that fails, and this is a lock file (not-conch), try creating
- * the parent directories and then try again.
- * 3. if that fails, try to open the file read-only
- * otherwise return BUSY (if lock file) or CANTOPEN for the conch file
+ UnixUnusedFd *pUnused = 0;
+
+ struct stat sStat; /* Results of stat() call */
+
+ /* A stat() call may fail for various reasons. If this happens, it is
+ * almost certain that an open() call on the same path will also fail.
+ * For this reason, if an error occurs in the stat() call here, it is
+ * ignored and -1 is returned. The caller will try to open a new file
+ * descriptor on the same path, fail, and return an error to SQLite.
+ *
+ * Even if a subsequent open() call does succeed, the consequences of
+ * not searching for a reusable file descriptor are not dire.
*/
- pUnused = findReusableFd(path, openFlags);
- if (pUnused) {
- fd = pUnused->fd;
- } else {
- pUnused = sqlite3_malloc64(sizeof(*pUnused));
- if (!pUnused) {
- return SQLITE_NOMEM_BKPT;
+ if (0 == stat(zPath, &sStat)) {
+ unixInodeInfo *pInode;
+
+ pInode = inodeList;
+ while (pInode && (pInode->fileId.dev != sStat.st_dev
+ || pInode->fileId.ino !=
+ (u64) sStat.st_ino)) {
+ pInode = pInode->pNext;
}
- }
- if (fd < 0) {
- fd = robust_open(path, openFlags, 0);
- terrno = errno;
- if (fd < 0 && errno == ENOENT && islockfile) {
- if (proxyCreateLockPath(path) == SQLITE_OK) {
- fd = robust_open(path, openFlags, 0);
+ if (pInode) {
+ UnixUnusedFd **pp;
+ for (pp = &pInode->pUnused;
+ *pp && (*pp)->flags != flags;
+ pp = &((*pp)->pNext)) ;
+ pUnused = *pp;
+ if (pUnused) {
+ *pp = pUnused->pNext;
}
}
}
- if (fd < 0) {
- openFlags = O_RDONLY;
- fd = robust_open(path, openFlags, 0);
- terrno = errno;
- }
- if (fd < 0) {
- if (islockfile) {
- return SQLITE_BUSY;
- }
- switch (terrno) {
- case EACCES:
- return SQLITE_PERM;
- case EIO:
- return SQLITE_IOERR_LOCK; /* even though it is the conch */
- default:
- return SQLITE_CANTOPEN_BKPT;
- }
- }
-
- pNew = (unixFile *) sqlite3_malloc64(sizeof(*pNew));
- if (pNew == NULL) {
- rc = SQLITE_NOMEM_BKPT;
- goto end_create_proxy;
- }
- memset(pNew, 0, sizeof(unixFile));
- pNew->openFlags = openFlags;
- memset(&dummyVfs, 0, sizeof(dummyVfs));
- dummyVfs.pAppData = (void *)&autolockIoFinder;
- dummyVfs.zName = "dummy";
- pUnused->fd = fd;
- pUnused->flags = openFlags;
- pNew->pUnused = pUnused;
-
- rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file *) pNew, path, 0);
- if (rc == SQLITE_OK) {
- *ppFile = pNew;
- return SQLITE_OK;
- }
- end_create_proxy:
- robust_close(pNew, fd, __LINE__);
- sqlite3_free(pNew);
- sqlite3_free(pUnused);
- return rc;
+ return pUnused;
}
-#ifdef SQLITE_TEST
-/* simulate multiple hosts by creating unique hostid file paths */
-int sqlite3_hostid_num = 0;
-#endif
-
-#define PROXY_HOSTIDLEN 16 /* conch file host id length */
-
-#ifdef HAVE_GETHOSTUUID
-/* Not always defined in the headers as it ought to be */
-extern int gethostuuid(uuid_t id, const struct timespec *wait);
-#endif
-
-/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
- * bytes of writable memory.
+/*
+ * Find the mode, uid and gid of file zFile.
*/
static int
-proxyGetHostID(unsigned char *pHostID, int *pError)
+getFileMode(const char *zFile, /* File name */
+ mode_t * pMode, /* OUT: Permissions of zFile */
+ uid_t * pUid, /* OUT: uid of zFile. */
+ gid_t * pGid /* OUT: gid of zFile. */
+ )
{
- assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
- memset(pHostID, 0, PROXY_HOSTIDLEN);
-#ifdef HAVE_GETHOSTUUID
- {
- struct timespec timeout = { 1, 0 }; /* 1 sec timeout */
- if (gethostuuid(pHostID, &timeout)) {
- int err = errno;
- if (pError) {
- *pError = err;
- }
- return SQLITE_IOERR;
- }
- }
-#else
- UNUSED_PARAMETER(pError);
-#endif
-#ifdef SQLITE_TEST
- /* simulate multiple hosts by creating unique hostid file paths */
- if (sqlite3_hostid_num != 0) {
- pHostID[0] =
- (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
+ struct stat sStat; /* Output of stat() on database file */
+ int rc = SQLITE_OK;
+ if (0 == stat(zFile, &sStat)) {
+ *pMode = sStat.st_mode & 0777;
+ *pUid = sStat.st_uid;
+ *pGid = sStat.st_gid;
+ } else {
+ rc = SQLITE_IOERR_FSTAT;
}
-#endif
-
- return SQLITE_OK;
+ return rc;
}
-/* The conch file contains the header, host id and lock file path
- */
-#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */
-#define PROXY_HEADERLEN 1 /* conch file header length */
-#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
-#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
-
/*
- * Takes an open conch file, copies the contents to a new path and then moves
- * it back. The newly created file's file descriptor is assigned to the
- * conch file structure and finally the original conch file descriptor is
- * closed. Returns zero if successful.
+ * This function is called by unixOpen() to determine the unix permissions
+ * to create new files with. If no error occurs, then SQLITE_OK is returned
+ * and a value suitable for passing as the third argument to open(2) is
+ * written to *pMode. If an IO error occurs, an SQLite error code is
+ * returned and the value of *pMode is not modified.
+ *
+ * In most cases, this routine sets *pMode to 0, which will become
+ * an indication to robust_open() to create the file using
+ * SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
+ * But if the file being opened is a regular journal file, then
+ * this function queries the file-system for the permissions on the
+ * corresponding database file and sets *pMode to this value. Whenever
+ * possible, journal files are created using the same permissions
+ * as the associated database file.
+ *
+ * If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
+ * original filename is unavailable. But 8_3_NAMES is only used for
+ * FAT filesystems and permissions do not matter there, so just use
+ * the default permissions.
*/
static int
-proxyBreakConchLock(unixFile * pFile, uuid_t myHostID)
+findCreateFileMode(const char *zPath, /* Path of file (possibly) being created */
+ int flags, /* Flags passed as 4th argument to xOpen() */
+ mode_t * pMode, /* OUT: Permissions to open file with */
+ uid_t * pUid, /* OUT: uid to set on the file */
+ gid_t * pGid /* OUT: gid to set on the file */
+ )
{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- unixFile *conchFile = pCtx->conchFile;
- char tPath[MAXPATHLEN];
- char buf[PROXY_MAXCONCHLEN];
- char *cPath = pCtx->conchFilePath;
- size_t readLen = 0;
- size_t pathLen = 0;
- char errmsg[64] = "";
- int fd = -1;
- int rc = -1;
- UNUSED_PARAMETER(myHostID);
-
- /* create a new path by replace the trailing '-conch' with '-break' */
- pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
- if (pathLen > MAXPATHLEN || pathLen < 6 ||
- (strlcpy(&tPath[pathLen - 5], "break", 6) != 5)) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "path error (len %d)",
- (int)pathLen);
- goto end_breaklock;
- }
- /* read the conch content */
- readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
- if (readLen < PROXY_PATHINDEX) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "read error (len %d)",
- (int)readLen);
- goto end_breaklock;
- }
- /* write it out to the temporary break file */
- fd = robust_open(tPath, (O_RDWR | O_CREAT | O_EXCL), 0);
- if (fd < 0) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)",
- errno);
- goto end_breaklock;
- }
- if (osPwrite(fd, buf, readLen, 0) != (ssize_t) readLen) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)",
- errno);
- goto end_breaklock;
- }
- if (rename(tPath, cPath)) {
- sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)",
- errno);
- goto end_breaklock;
- }
- rc = 0;
- fprintf(stderr, "broke stale lock on %s\n", cPath);
- robust_close(pFile, conchFile->h, __LINE__);
- conchFile->h = fd;
- conchFile->openFlags = O_RDWR | O_CREAT;
-
- end_breaklock:
- if (rc) {
- if (fd >= 0) {
- osUnlink(tPath);
- robust_close(pFile, fd, __LINE__);
+ int rc = SQLITE_OK; /* Return Code */
+ *pMode = 0;
+ *pUid = 0;
+ *pGid = 0;
+ if (flags & SQLITE_OPEN_DELETEONCLOSE) {
+ *pMode = 0600;
+ } else if (flags & SQLITE_OPEN_URI) {
+ /* If this is a main database file and the file was opened using a URI
+ * filename, check for the "modeof" parameter. If present, interpret
+ * its value as a filename and try to copy the mode, uid and gid from
+ * that file.
+ */
+ const char *z = sqlite3_uri_parameter(zPath, "modeof");
+ if (z) {
+ rc = getFileMode(z, pMode, pUid, pGid);
}
- fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath,
- errmsg);
}
return rc;
}
-/* Take the requested lock on the conch file and break a stale lock if the
- * host id matches.
+/*
+ * 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
-proxyConchLock(unixFile * pFile, uuid_t myHostID, int lockType)
+unixOpen(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 */
+ )
{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- unixFile *conchFile = pCtx->conchFile;
- int rc = SQLITE_OK;
- int nTries = 0;
- struct timespec conchModTime;
-
- memset(&conchModTime, 0, sizeof(conchModTime));
- do {
- rc = conchFile->pMethod->xLock((sqlite3_file *) conchFile,
- lockType);
- nTries++;
- if (rc == SQLITE_BUSY) {
- /* If the lock failed (busy):
- * 1st try: get the mod time of the conch, wait 0.5s and try again.
- * 2nd try: fail if the mod time changed or host id is different, wait
- * 10 sec and try again
- * 3rd try: break the lock unless the mod time has changed.
- */
- struct stat buf;
- if (osFstat(conchFile->h, &buf)) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR_LOCK;
- }
-
- if (nTries == 1) {
- conchModTime = buf.st_mtimespec;
- usleep(500000); /* wait 0.5 sec and try the lock again */
- continue;
- }
+ unixFile *p = (unixFile *) pFile;
+ int fd = -1; /* File descriptor returned by 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; /* Function Return Code */
+ int ctrlFlags = 0; /* UNIXFILE_* flags */
- assert(nTries > 1);
- if (conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
- conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec) {
- return SQLITE_BUSY;
- }
+ 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 (nTries == 2) {
- char tBuf[PROXY_MAXCONCHLEN];
- int len =
- osPread(conchFile->h, tBuf,
- PROXY_MAXCONCHLEN, 0);
- if (len < 0) {
- storeLastErrno(pFile, errno);
- return SQLITE_IOERR_LOCK;
- }
- if (len > PROXY_PATHINDEX
- && tBuf[0] == (char)PROXY_CONCHVERSION) {
- /* don't break the lock if the host id doesn't match */
- if (0 !=
- memcmp(&tBuf[PROXY_HEADERLEN],
- myHostID, PROXY_HOSTIDLEN)) {
- return SQLITE_BUSY;
- }
- } else {
- /* don't break the lock on short read or a version mismatch */
- return SQLITE_BUSY;
- }
- usleep(10000000); /* wait 10 sec and try the lock again */
- continue;
- }
+ /* 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 syncDir = isCreate;
- assert(nTries == 3);
- if (0 == proxyBreakConchLock(pFile, myHostID)) {
- rc = SQLITE_OK;
- if (lockType == EXCLUSIVE_LOCK) {
- rc = conchFile->pMethod->
- xLock((sqlite3_file *) conchFile,
- SHARED_LOCK);
- }
- if (!rc) {
- rc = conchFile->pMethod->
- xLock((sqlite3_file *) conchFile,
- lockType);
- }
- }
- }
- } while (rc == SQLITE_BUSY && nTries < 3);
+ /* If argument zPath is a NULL pointer, this function is required to open
+ * a temporary file. Use this buffer to store the file name in.
+ */
+ char zTmpname[MAX_PATHNAME + 2];
+ const char *zName = zPath;
- return rc;
-}
+ /* 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);
-/* 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
-proxyTakeConch(unixFile * pFile)
-{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
+ /* Detect a pid change and reset the PRNG. There is a race condition
+ * here such that two or more threads all trying to open databases at
+ * the same instant might all reset the PRNG. But multiple resets
+ * are harmless.
+ */
+ if (randomnessPid != getpid()) {
+ randomnessPid = getpid();
+ sqlite3_randomness(0, 0);
+ }
- if (pCtx->conchHeld != 0) {
- return SQLITE_OK;
- } else {
- unixFile *conchFile = pCtx->conchFile;
- uuid_t myHostID;
- int pError = 0;
- char readBuf[PROXY_MAXCONCHLEN];
- char lockPath[MAXPATHLEN];
- char *tempLockPath = NULL;
- int rc = SQLITE_OK;
- int createConch = 0;
- int hostIdMatch = 0;
- int readLen = 0;
- int tryOldLockPath = 0;
- int forceNewLockPath = 0;
-
- rc = proxyGetHostID(myHostID, &pError);
- if ((rc & 0xff) == SQLITE_IOERR) {
- storeLastErrno(pFile, pError);
- goto end_takeconch;
- }
- rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
- if (rc != SQLITE_OK) {
- goto end_takeconch;
- }
- /* read the existing conch file */
- readLen =
- seekAndRead((unixFile *) conchFile, 0, readBuf,
- PROXY_MAXCONCHLEN);
- if (readLen < 0) {
- /* I/O error: lastErrno set by seekAndRead */
- storeLastErrno(pFile, conchFile->lastErrno);
- rc = SQLITE_IOERR_READ;
- goto end_takeconch;
- } else if (readLen <= (PROXY_HEADERLEN + PROXY_HOSTIDLEN) ||
- readBuf[0] != (char)PROXY_CONCHVERSION) {
- /* a short read or version format mismatch means we need to create a new
- * conch file.
- */
- createConch = 1;
- }
- /* if the host id matches and the lock path already exists in the conch
- * we'll try to use the path there, if we can't open that path, we'll
- * retry with a new auto-generated path
- */
- do { /* in case we need to try again for an :auto: named lock file */
-
- if (!createConch && !forceNewLockPath) {
- hostIdMatch =
- !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
- PROXY_HOSTIDLEN);
- /* if the conch has data compare the contents */
- if (!pCtx->lockProxyPath) {
- /* for auto-named local lock file, just check the host ID and we'll
- * use the local lock file path that's already in there
- */
- if (hostIdMatch) {
- size_t pathLen =
- (readLen - PROXY_PATHINDEX);
-
- if (pathLen >= MAXPATHLEN) {
- pathLen =
- MAXPATHLEN - 1;
- }
- memcpy(lockPath,
- &readBuf
- [PROXY_PATHINDEX],
- pathLen);
- lockPath[pathLen] = 0;
- tempLockPath = lockPath;
- tryOldLockPath = 1;
- /* create a copy of the lock path if the conch is taken */
- goto end_takeconch;
- }
- } else if (hostIdMatch
- && !strncmp(pCtx->lockProxyPath,
- &readBuf
- [PROXY_PATHINDEX],
- readLen -
- PROXY_PATHINDEX)
- ) {
- /* conch host and lock path match */
- goto end_takeconch;
- }
- }
+ memset(p, 0, sizeof(unixFile));
- /* if the conch isn't writable and doesn't match, we can't take it */
- if ((conchFile->openFlags & O_RDWR) == 0) {
- rc = SQLITE_BUSY;
- goto end_takeconch;
+ if (eType == SQLITE_OPEN_MAIN_DB) {
+ UnixUnusedFd *pUnused;
+ pUnused = findReusableFd(zName, flags);
+ if (pUnused) {
+ fd = pUnused->fd;
+ } else {
+ pUnused = sqlite3_malloc64(sizeof(*pUnused));
+ if (!pUnused) {
+ return SQLITE_NOMEM_BKPT;
}
+ }
+ p->pUnused = pUnused;
- /* either the conch didn't match or we need to create a new one */
- if (!pCtx->lockProxyPath) {
- proxyGetLockPath(pCtx->dbPath, lockPath,
- MAXPATHLEN);
- tempLockPath = lockPath;
- /* create a copy of the lock path _only_ if the conch is taken */
- }
+ /* Database filenames are double-zero terminated if they are not
+ * URIs with parameters. Hence, they can always be passed into
+ * sqlite3_uri_parameter().
+ */
+ assert((flags & SQLITE_OPEN_URI)
+ || zName[strlen(zName) + 1] == 0);
- /* update conch with host and path (this will fail if other process
- * has a shared lock already), if the host id matches, use the big
- * stick.
- */
- futimes(conchFile->h, NULL);
- if (hostIdMatch && !createConch) {
- if (conchFile->pInode
- && conchFile->pInode->nShared > 1) {
- /* We are trying for an exclusive lock but another thread in this
- * same process is still holding a shared lock.
- */
- rc = SQLITE_BUSY;
- } else {
- rc = proxyConchLock(pFile, myHostID,
- EXCLUSIVE_LOCK);
- }
- } else {
- rc = proxyConchLock(pFile, myHostID,
- EXCLUSIVE_LOCK);
- }
- if (rc == SQLITE_OK) {
- char writeBuffer[PROXY_MAXCONCHLEN];
- int writeSize = 0;
-
- writeBuffer[0] = (char)PROXY_CONCHVERSION;
- memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID,
- PROXY_HOSTIDLEN);
- if (pCtx->lockProxyPath != NULL) {
- strlcpy(&writeBuffer[PROXY_PATHINDEX],
- pCtx->lockProxyPath,
- MAXPATHLEN);
- } else {
- strlcpy(&writeBuffer[PROXY_PATHINDEX],
- tempLockPath, MAXPATHLEN);
- }
- writeSize =
- PROXY_PATHINDEX +
- strlen(&writeBuffer[PROXY_PATHINDEX]);
- robust_ftruncate(conchFile->h, writeSize);
- rc = unixWrite((sqlite3_file *) conchFile,
- writeBuffer, writeSize, 0);
- full_fsync(conchFile->h, 0, 0);
- /* If we created a new conch file (not just updated the contents of a
- * valid conch file), try to match the permissions of the database
- */
- if (rc == SQLITE_OK && createConch) {
- struct stat buf;
- int err = osFstat(pFile->h, &buf);
- if (err == 0) {
- mode_t cmode =
- buf.
- st_mode & (S_IRUSR | S_IWUSR
- | S_IRGRP |
- S_IWGRP | S_IROTH
- | S_IWOTH);
- /* try to match the database file R/W permissions, ignore failure */
-#ifndef SQLITE_PROXY_DEBUG
- osFchmod(conchFile->h, cmode);
-#else
- do {
- rc = osFchmod
- (conchFile->h,
- cmode);
- } while (rc == (-1)
- && errno == EINTR);
- if (rc != 0) {
- int code = errno;
- fprintf(stderr,
- "fchmod %o FAILED with %d %s\n",
- cmode, code,
- strerror(code));
- } else {
- fprintf(stderr,
- "fchmod %o SUCCEDED\n",
- cmode);
- }
- } else {
- int code = errno;
- fprintf(stderr,
- "STAT FAILED[%d] with %d %s\n",
- err, code,
- strerror(code));
-#endif
- }
- }
- }
- conchFile->pMethod->xUnlock((sqlite3_file *) conchFile,
- SHARED_LOCK);
-
- end_takeconch:
- if (rc == SQLITE_OK && pFile->openFlags) {
- int fd;
- if (pFile->h >= 0) {
- robust_close(pFile, pFile->h, __LINE__);
- }
- pFile->h = -1;
- fd = robust_open(pCtx->dbPath, pFile->openFlags,
- 0);
- if (fd >= 0) {
- pFile->h = fd;
- } else {
- rc = SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called
- during locking */
- }
- }
- if (rc == SQLITE_OK && !pCtx->lockProxy) {
- char *path =
- tempLockPath ? tempLockPath : pCtx->
- lockProxyPath;
- rc = proxyCreateUnixFile(path, &pCtx->lockProxy,
- 1);
- if (rc != SQLITE_OK && rc != SQLITE_NOMEM
- && tryOldLockPath) {
- /* we couldn't create the proxy lock file with the old lock file path
- * so try again via auto-naming
- */
- forceNewLockPath = 1;
- tryOldLockPath = 0;
- continue; /* go back to the do {} while start point, try again */
- }
- }
- if (rc == SQLITE_OK) {
- /* Need to make a copy of path if we extracted the value
- * from the conch file or the path was allocated on the stack
- */
- if (tempLockPath) {
- pCtx->lockProxyPath =
- sqlite3DbStrDup(0, tempLockPath);
- if (!pCtx->lockProxyPath) {
- rc = SQLITE_NOMEM_BKPT;
- }
- }
- }
- if (rc == SQLITE_OK) {
- pCtx->conchHeld = 1;
-
- if (pCtx->lockProxy->pMethod == &afpIoMethods) {
- afpLockingContext *afpCtx;
- afpCtx =
- (afpLockingContext *) pCtx->
- lockProxy->lockingContext;
- afpCtx->dbPath = pCtx->lockProxyPath;
- }
- } else {
- conchFile->pMethod->
- xUnlock((sqlite3_file *) conchFile,
- NO_LOCK);
- }
+ } else if (!zName) {
+ /* If zName is NULL, the upper layer is requesting a temp file. */
+ assert(isDelete);
+ rc = unixGetTempname(pVfs->mxPathname, zTmpname);
+ if (rc != SQLITE_OK) {
return rc;
- } while (1); /* in case we need to retry the :auto: lock file -
- * we should never get here except via the 'continue' call.
- */
- }
-}
+ }
+ zName = zTmpname;
-/*
- * If pFile holds a lock on a conch file, then release that lock.
- */
-static int
-proxyReleaseConch(unixFile * pFile)
-{
- int rc = SQLITE_OK; /* 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;
- if (pCtx->conchHeld > 0) {
- rc = conchFile->pMethod->xUnlock((sqlite3_file *) conchFile,
- NO_LOCK);
+ /* Generated temporary filenames are always double-zero terminated
+ * for use by sqlite3_uri_parameter().
+ */
+ assert(zName[strlen(zName) + 1] == 0);
}
- pCtx->conchHeld = 0;
- return rc;
-}
-
-/*
- * Given the name of a database file, compute the name of its conch file.
- * Store the conch filename in memory obtained from sqlite3_malloc64().
- * 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 = (int)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.
+ /* Determine the value of the flags parameter passed to POSIX function
+ * open(). These must be calculated even if open() is not called, as
+ * they may be stored as part of the file handle and used by the
+ * 'conch file' locking functions later on.
*/
- *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
- if (conchPath == 0) {
- return SQLITE_NOMEM_BKPT;
- }
- memcpy(conchPath, dbPath, len + 1);
+ if (isReadonly)
+ openFlags |= O_RDONLY;
+ if (isReadWrite)
+ openFlags |= O_RDWR;
+ if (isCreate)
+ openFlags |= O_CREAT;
+ if (isExclusive)
+ openFlags |= (O_EXCL | O_NOFOLLOW);
+ openFlags |= O_BINARY;
+ #ifndef __APPLE__
+ openFlags |= O_LARGEFILE;
+ #endif
- /* now insert a "." before the last / character */
- for (i = (len - 1); i >= 0; i--) {
- if (conchPath[i] == '/') {
- i++;
- break;
+ if (fd < 0) {
+ mode_t openMode; /* Permissions to create file with */
+ uid_t uid; /* Userid for the file */
+ gid_t gid; /* Groupid for the file */
+ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
+ if (rc != SQLITE_OK) {
+ assert(!p->pUnused);
+ return rc;
+ }
+ fd = robust_open(zName, openFlags, openMode);
+ assert(!isExclusive || (openFlags & O_CREAT) != 0);
+ if (fd < 0 && errno != EISDIR && isReadWrite) {
+ /* Failed to open the file for read/write access. Try read-only. */
+ flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+ openFlags &= ~(O_RDWR | O_CREAT);
+ flags |= SQLITE_OPEN_READONLY;
+ openFlags |= O_RDONLY;
+ isReadonly = 1;
+ fd = robust_open(zName, openFlags, openMode);
+ }
+ if (fd < 0) {
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
+ goto open_finished;
}
+
}
- conchPath[i] = '.';
- while (i < len) {
- conchPath[i + 1] = dbPath[i];
- i++;
+ assert(fd >= 0);
+ if (pOutFlags) {
+ *pOutFlags = flags;
}
- /* append the "-conch" suffix to the file */
- memcpy(&conchPath[i + 1], "-conch", 7);
- assert((int)strlen(conchPath) == len + 7);
+ if (p->pUnused) {
+ p->pUnused->fd = fd;
+ p->pUnused->flags = flags;
+ }
- return SQLITE_OK;
-}
+ if (isDelete)
+ unlink(zName);
-/* Takes a fully configured proxy locking-style unix file and switches
- * the local lock file path
- */
-static int
-switchLockProxyPath(unixFile * pFile, const char *path)
-{
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- char *oldPath = pCtx->lockProxyPath;
- int rc = SQLITE_OK;
+ /* Set up appropriate ctrlFlags */
+ if (isDelete)
+ ctrlFlags |= UNIXFILE_DELETE;
+ if (isReadonly)
+ ctrlFlags |= UNIXFILE_RDONLY;
+ noLock = eType != SQLITE_OPEN_MAIN_DB;
+ if (noLock)
+ ctrlFlags |= UNIXFILE_NOLOCK;
+ if (syncDir)
+ ctrlFlags |= UNIXFILE_DIRSYNC;
+ if (flags & SQLITE_OPEN_URI)
+ ctrlFlags |= UNIXFILE_URI;
- if (pFile->eFileLock != NO_LOCK) {
- return SQLITE_BUSY;
- }
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
- /* nothing to do if the path is NULL, :auto: or matches the existing path */
- if (!path || path[0] == '\0' || !strcmp(path, ":auto:") ||
- (oldPath && !strncmp(oldPath, path, MAXPATHLEN))) {
- return SQLITE_OK;
- } else {
- unixFile *lockProxy = pCtx->lockProxy;
- pCtx->lockProxy = NULL;
- pCtx->conchHeld = 0;
- if (lockProxy != NULL) {
- rc = lockProxy->pMethod->
- xClose((sqlite3_file *) lockProxy);
- if (rc)
- return rc;
- sqlite3_free(lockProxy);
- }
- sqlite3_free(oldPath);
- pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
+ open_finished:
+ if (rc != SQLITE_OK) {
+ sqlite3_free(p->pUnused);
}
-
return rc;
}
/*
- * 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(__APPLE__)
- if (pFile->pMethod == &afpIoMethods) {
- /* afp style keeps a reference to the db path in the filePath field
- * of the struct
- */
- assert((int)strlen((char *)pFile->lockingContext) <=
- MAXPATHLEN);
- strlcpy(dbPath,
- ((afpLockingContext *) pFile->lockingContext)->dbPath,
- MAXPATHLEN);
- } 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);
- strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN);
- }
- 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
- * the unix structure properly cleaned up at close time:
- * ->lockingContext
- * ->pMethod
+ * Delete the file at zPath. If the dirSync argument is true, fsync()
+ * the directory after deleting the file.
*/
static int
-proxyTransformUnixFile(unixFile * pFile, const char *path)
+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 */
+ )
{
- proxyLockingContext *pCtx;
- char dbPath[MAXPATHLEN + 1]; /* Name of the database file */
- char *lockPath = NULL;
int rc = SQLITE_OK;
-
- if (pFile->eFileLock != NO_LOCK) {
- return SQLITE_BUSY;
- }
- proxyGetDbPathForUnixFile(pFile, dbPath);
- if (!path || path[0] == '\0' || !strcmp(path, ":auto:")) {
- lockPath = NULL;
- } else {
- lockPath = (char *)path;
- }
-
- pCtx = sqlite3_malloc64(sizeof(*pCtx));
- if (pCtx == 0) {
- return SQLITE_NOMEM_BKPT;
- }
- memset(pCtx, 0, sizeof(*pCtx));
-
- rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath);
- if (rc == SQLITE_OK) {
- rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile,
- 0);
- if (rc == SQLITE_CANTOPEN && ((pFile->openFlags & O_RDWR) == 0)) {
- /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and
- * (c) the file system is read-only, then enable no-locking access.
- * Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts
- * that openFlags will have only one of O_RDONLY or O_RDWR.
- */
- struct statfs fsInfo;
- struct stat conchInfo;
- int goLockless = 0;
-
- if (osStat(pCtx->conchFilePath, &conchInfo) == -1) {
- int err = errno;
- if ((err == ENOENT)
- && (statfs(dbPath, &fsInfo) != -1)) {
- goLockless =
- (fsInfo.f_flags & MNT_RDONLY) ==
- MNT_RDONLY;
- }
- }
- if (goLockless) {
- pCtx->conchHeld = -1; /* read only FS/ lockless */
- rc = SQLITE_OK;
- }
- }
- }
- if (rc == SQLITE_OK && lockPath) {
- pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
- }
-
- if (rc == SQLITE_OK) {
- pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
- if (pCtx->dbPath == NULL) {
- rc = SQLITE_NOMEM_BKPT;
+ UNUSED_PARAMETER(NotUsed);
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ if (unlink(zPath) == (-1)) {
+ if (errno == ENOENT) {
+ rc = SQLITE_IOERR_DELETE_NOENT;
+ } else {
+ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
+ return rc;
}
- if (rc == SQLITE_OK) {
- /* all memory is allocated, proxys are created and assigned,
- * switch the locking context and pMethod then return.
- */
- pCtx->oldLockingContext = pFile->lockingContext;
- pFile->lockingContext = pCtx;
- pCtx->pOldMethod = pFile->pMethod;
- pFile->pMethod = &proxyIoMethods;
- } else {
- if (pCtx->conchFile) {
- pCtx->conchFile->pMethod->xClose((sqlite3_file *) pCtx->
- conchFile);
- sqlite3_free(pCtx->conchFile);
+#ifndef SQLITE_DISABLE_DIRSYNC
+ if ((dirSync & 1) != 0) {
+ int fd;
+ rc = openDirectory(zPath, &fd);
+ if (rc == SQLITE_OK) {
+ if (full_fsync(fd, 0, 0)) {
+ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC,
+ "fsync", zPath);
+ }
+ robust_close(0, fd, __LINE__);
+ } else {
+ assert(rc == SQLITE_CANTOPEN);
+ rc = SQLITE_OK;
}
- sqlite3DbFree(0, pCtx->lockProxyPath);
- sqlite3_free(pCtx->conchFilePath);
- sqlite3_free(pCtx);
}
+#endif
return rc;
}
/*
- * This routine handles sqlite3_file_control() calls that are specific
- * to proxy locking.
+ * Write nBuf bytes of random data to the supplied buffer zBuf.
*/
static int
-proxyFileControl(sqlite3_file * id, int op, void *pArg)
+unixRandomness(sqlite3_vfs * NotUsed, int nBuf, char *zBuf)
{
- switch (op) {
- case SQLITE_FCNTL_GET_LOCKPROXYFILE:{
- unixFile *pFile = (unixFile *) id;
- if (pFile->pMethod == &proxyIoMethods) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->
- lockingContext;
- proxyTakeConch(pFile);
- if (pCtx->lockProxyPath) {
- *(const char **)pArg =
- pCtx->lockProxyPath;
- } else {
- *(const char **)pArg =
- ":auto: (not held)";
- }
- } else {
- *(const char **)pArg = NULL;
- }
- return SQLITE_OK;
- }
- case SQLITE_FCNTL_SET_LOCKPROXYFILE:{
- unixFile *pFile = (unixFile *) id;
- int rc = SQLITE_OK;
- int isProxyStyle = (pFile->pMethod == &proxyIoMethods);
- if (pArg == NULL || (const char *)pArg == 0) {
- if (isProxyStyle) {
- rc = SQLITE_ERROR;
- } else {
- /* turn off proxy locking - already off - NOOP */
- rc = SQLITE_OK;
- }
- } else {
- const char *proxyPath = (const char *)pArg;
- if (isProxyStyle) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->
- lockingContext;
- if (!strcmp(pArg, ":auto:")
- || (pCtx->lockProxyPath &&
- !strncmp(pCtx->lockProxyPath,
- proxyPath, MAXPATHLEN))
- ) {
- rc = SQLITE_OK;
- } else {
- rc = switchLockProxyPath(pFile,
- proxyPath);
- }
- } else {
- /* turn on proxy file locking */
- rc = proxyTransformUnixFile(pFile,
- proxyPath);
- }
- }
- return rc;
- }
- default:{
- assert(0); /* The call assures that only valid opcodes are sent */
- }
- }
- /*NOTREACHED*/ return SQLITE_ERROR;
-}
+ UNUSED_PARAMETER(NotUsed);
+ assert((size_t) nBuf >= (sizeof(time_t) + sizeof(int)));
-/*
- * 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.
- */
+ /* 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
+ * uninitialized space in zBuf - but valgrind errors tend to worry
+ * some users. Rather than argue, it seems easier just to initialize
+ * the whole array and silence valgrind, even if that means less randomness
+ * in the random seed.
+ *
+ * When testing, initializing zBuf[] to zero is all we do. That means
+ * that we always use the same random number sequence. This makes the
+ * tests repeatable.
+ */
+ memset(zBuf, 0, nBuf);
+ randomnessPid = getpid();
+ return nBuf;
+}
/*
- * 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.
+ * Sleep for a little while. Return the amount of time slept.
+ * 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.
*/
static int
-proxyCheckReservedLock(sqlite3_file * id, int *pResOut)
+unixSleep(sqlite3_vfs * NotUsed, int microseconds)
{
- unixFile *pFile = (unixFile *) id;
- int rc = proxyTakeConch(pFile);
- if (rc == SQLITE_OK) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- if (pCtx->conchHeld > 0) {
- unixFile *proxy = pCtx->lockProxy;
- return proxy->pMethod->
- xCheckReservedLock((sqlite3_file *) proxy, pResOut);
- } else { /* conchHeld < 0 is lockless */
- pResOut = 0;
- }
- }
- return rc;
+ int seconds = (microseconds + 999999) / 1000000;
+ sleep(seconds);
+ UNUSED_PARAMETER(NotUsed);
+ return seconds * 1000000;
}
+/* Fake system time in seconds since 1970. */
+int sqlite3_current_time = 0;
+
/*
- * Lock the file with the lock specified by parameter eFileLock - 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
+ * Find the current time (in Universal Coordinated Time). Write into *piNow
+ * the current time and date as a Julian Day number times 86_400_000. In
+ * other words, write into *piNow the number of milliseconds since the Julian
+ * epoch of noon in Greenwich on November 24, 4714 B.C according to the
+ * proleptic Gregorian calendar.
*
- * This routine will only increase a lock. Use the sqlite3OsUnlock()
- * routine to lower a locking level.
+ * On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
+ * cannot be found.
*/
static int
-proxyLock(sqlite3_file * id, int eFileLock)
+unixCurrentTimeInt64(sqlite3_vfs * NotUsed, sqlite3_int64 * piNow)
{
- unixFile *pFile = (unixFile *) id;
- int rc = proxyTakeConch(pFile);
- if (rc == SQLITE_OK) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- if (pCtx->conchHeld > 0) {
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xLock((sqlite3_file *) proxy,
- eFileLock);
- pFile->eFileLock = proxy->eFileLock;
- } else {
- /* conchHeld < 0 is lockless */
- }
+ static const sqlite3_int64 unixEpoch =
+ 24405875 * (sqlite3_int64) 8640000;
+ int rc = SQLITE_OK;
+ struct timeval sNow;
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
+ *piNow =
+ unixEpoch + 1000 * (sqlite3_int64) sNow.tv_sec +
+ sNow.tv_usec / 1000;
+
+#ifdef SQLITE_TEST
+ if (sqlite3_current_time) {
+ *piNow =
+ 1000 * (sqlite3_int64) sqlite3_current_time + unixEpoch;
}
+#endif
+ UNUSED_PARAMETER(NotUsed);
return rc;
}
/*
- * Lower the locking level on file descriptor pFile to eFileLock. eFileLock
- * 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.
+ * The xGetLastError() method is designed to return a better
+ * low-level error message when operating-system problems come up
+ * during SQLite operation. Only the integer return code is currently
+ * used.
*/
static int
-proxyUnlock(sqlite3_file * id, int eFileLock)
+unixGetLastError(sqlite3_vfs * NotUsed, int NotUsed2, char *NotUsed3)
{
- unixFile *pFile = (unixFile *) id;
- int rc = proxyTakeConch(pFile);
- if (rc == SQLITE_OK) {
- proxyLockingContext *pCtx =
- (proxyLockingContext *) pFile->lockingContext;
- if (pCtx->conchHeld > 0) {
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xUnlock((sqlite3_file *) proxy,
- eFileLock);
- pFile->eFileLock = proxy->eFileLock;
- } else {
- /* conchHeld < 0 is lockless */
- }
- }
- return rc;
+ UNUSED_PARAMETER(NotUsed);
+ UNUSED_PARAMETER(NotUsed2);
+ UNUSED_PARAMETER(NotUsed3);
+ return errno;
}
/*
- * Close a file that uses proxy locks.
- */
-static int
-proxyClose(sqlite3_file * id)
-{
- if (ALWAYS(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);
- }
- sqlite3DbFree(0, pCtx->lockProxyPath);
- sqlite3_free(pCtx->conchFilePath);
- sqlite3DbFree(0, 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;
-}
+ *********************** End of sqlite3_vfs methods ***************************
+ *****************************************************************************/
-#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
/*
* The proxy locking style is intended for use with AFP filesystems.
* And since AFP is only supported on MacOSX, the proxy locking is also
@@ -6136,6 +2147,22 @@ proxyClose(sqlite3_file * id)
****************** End of the proxy lock implementation **********************
*****************************************************************************/
+#define UNIXVFS(VFSNAME, FINDER) { \
+ 3, /* iVersion */ \
+ sizeof(unixFile), /* szOsFile */ \
+ MAX_PATHNAME, /* mxPathname */ \
+ NULL, /* pNext */ \
+ VFSNAME, /* zName */ \
+ (void*)&FINDER, /* pAppData */ \
+ unixOpen, /* xOpen */ \
+ unixDelete, /* xDelete */ \
+ unixRandomness, /* xRandomness */ \
+ unixSleep, /* xSleep */ \
+ NULL, /* xCurrentTime */ \
+ unixGetLastError, /* xGetLastError */ \
+ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
+ }
+
/*
* Initialize the operating system interface.
*
@@ -6153,47 +2180,6 @@ int
sqlite3_os_init(void)
{
/*
- * 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 pointer
- * to the "finder" function. (pAppData is a pointer to a pointer because
- * silly C90 rules prohibit a void* from being cast to a function pointer
- * and so we have to go through the intermediate pointer to avoid problems
- * when compiling with -pedantic-errors on GCC.)
- *
- * The FINDER parameter to this macro is the name of the pointer to 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) { \
- 3, /* iVersion */ \
- sizeof(unixFile), /* szOsFile */ \
- MAX_PATHNAME, /* mxPathname */ \
- 0, /* pNext */ \
- VFSNAME, /* zName */ \
- (void*)&FINDER, /* pAppData */ \
- unixOpen, /* xOpen */ \
- unixDelete, /* xDelete */ \
- unixAccess, /* xAccess */ \
- unixFullPathname, /* xFullPathname */ \
- unixRandomness, /* xRandomness */ \
- unixSleep, /* xSleep */ \
- 0, /* xCurrentTime */ \
- unixGetLastError, /* xGetLastError */ \
- unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
- unixSetSystemCall, /* xSetSystemCall */ \
- unixGetSystemCall, /* xGetSystemCall */ \
- unixNextSystemCall, /* xNextSystemCall */ \
- }
-
- /*
* All default VFSes for unix are contained in the following array.
*
* Note that the sqlite3_vfs.pNext field of the VFS object is modified
@@ -6201,36 +2187,13 @@ sqlite3_os_init(void)
* array cannot be const.
*/
static sqlite3_vfs aVfs[] = {
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- UNIXVFS("unix", autolockIoFinder),
-#endif
UNIXVFS("unix-none", nolockIoFinder),
- UNIXVFS("unix-dotfile", dotlockIoFinder),
- UNIXVFS("unix-excl", posixIoFinder),
-
-#if SQLITE_ENABLE_LOCKING_STYLE
- UNIXVFS("unix-posix", posixIoFinder),
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
- UNIXVFS("unix-flock", flockIoFinder),
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
- UNIXVFS("unix-afp", afpIoFinder),
- UNIXVFS("unix-nfs", nfsIoFinder),
- UNIXVFS("unix-proxy", proxyIoFinder),
-#endif
+ UNIXVFS("unix-excl", posixIoFinder)
};
- unsigned int i; /* Loop counter */
-
- /* Double-check that the aSyscall[] array has been constructed
- * correctly. See ticket [bb3a86e890c8e96ab]
- */
- assert(ArraySize(aSyscall) == 28);
- /* Register all VFSes defined in the aVfs[] array */
- for (i = 0; i < (sizeof(aVfs) / sizeof(sqlite3_vfs)); i++) {
+ /* Register all VFSes defined in the aVfs[] array. */
+ for (unsigned int i = 0; i < (sizeof(aVfs) / sizeof(sqlite3_vfs)); i++)
sqlite3_vfs_register(&aVfs[i], i == 0);
- }
return SQLITE_OK;
}
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 31581b1..146b446 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -43,14 +43,6 @@
#include "box/schema.h"
#include "box/session.h"
-#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
-#if defined(__APPLE__)
-#define SQLITE_ENABLE_LOCKING_STYLE 1
-#else
-#define SQLITE_ENABLE_LOCKING_STYLE 0
-#endif
-#endif
-
/*
************************************************************************
* pragma.h contains several pragmas, including utf's pragmas.
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 9f6f83b..12fa109 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -342,7 +342,6 @@ struct sqlite3_file {
typedef int (*sqlite3_callback) (void *, int, char **, char **);
typedef struct sqlite3_vfs sqlite3_vfs;
-typedef void (*sqlite3_syscall_ptr) (void);
struct sqlite3_vfs {
int iVersion; /* Structure version number (currently 3) */
int szOsFile; /* Size of subclassed sqlite3_file */
@@ -353,10 +352,6 @@ struct sqlite3_vfs {
int (*xOpen) (sqlite3_vfs *, const char *zName, sqlite3_file *,
int flags, int *pOutFlags);
int (*xDelete) (sqlite3_vfs *, const char *zName, int syncDir);
- int (*xAccess) (sqlite3_vfs *, const char *zName, int flags,
- int *pResOut);
- int (*xFullPathname) (sqlite3_vfs *, const char *zName,
- int nOut, char *zOut);
int (*xRandomness) (sqlite3_vfs *, int nByte, char *zOut);
int (*xSleep) (sqlite3_vfs *, int microseconds);
int (*xCurrentTime) (sqlite3_vfs *, double *);
@@ -367,16 +362,6 @@ struct sqlite3_vfs {
*/
int (*xCurrentTimeInt64) (sqlite3_vfs *, sqlite3_int64 *);
/*
- ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
- ** Those below are for version 3 and greater.
- */
- int (*xSetSystemCall) (sqlite3_vfs *, const char *zName,
- sqlite3_syscall_ptr);
- sqlite3_syscall_ptr(*xGetSystemCall) (sqlite3_vfs *,
- const char *zName);
- const char *(*xNextSystemCall) (sqlite3_vfs *,
- const char *zName);
- /*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
** New fields may be appended in future versions. The iVersion
** value will increment whenever this happens.
@@ -846,21 +831,7 @@ struct sqlite3_io_methods {
sqlite3_int64 iOfst);
int (*xWrite) (sqlite3_file *, const void *, int iAmt,
sqlite3_int64 iOfst);
- int (*xTruncate) (sqlite3_file *, sqlite3_int64 size);
- int (*xSync) (sqlite3_file *, int flags);
- int (*xFileSize) (sqlite3_file *, sqlite3_int64 * pSize);
- int (*xLock) (sqlite3_file *, int);
- int (*xUnlock) (sqlite3_file *, int);
- int (*xCheckReservedLock) (sqlite3_file *, int *pResOut);
int (*xFileControl) (sqlite3_file *, int op, void *pArg);
- int (*xSectorSize) (sqlite3_file *);
- int (*xDeviceCharacteristics) (sqlite3_file *);
- /* Methods above are valid for version 1 */
- int (*xShmMap) (sqlite3_file *, int iPg, int pgsz, int,
- void volatile **);
- int (*xShmLock) (sqlite3_file *, int offset, int n, int flags);
- void (*xShmBarrier) (sqlite3_file *);
- int (*xShmUnmap) (sqlite3_file *, int deleteFlag);
/* Methods above are valid for version 2 */
int (*xFetch) (sqlite3_file *, sqlite3_int64 iOfst, int iAmt,
void **pp);
@@ -887,11 +858,6 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_TRACE 17
#define SQLITE_FCNTL_HAS_MOVED 18
#define SQLITE_FCNTL_SYNC 19
-#define SQLITE_FCNTL_COMMIT_PHASETWO 20
-#define SQLITE_FCNTL_ZIPVFS 22
-#define SQLITE_FCNTL_RBU 23
-#define SQLITE_FCNTL_VFS_POINTER 24
-#define SQLITE_FCNTL_PDB 26
int
sqlite3_os_init(void);
--
2.7.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-07-03 11:27 ` Kirill Shcherbatov
@ 2018-07-04 13:28 ` n.pettik
2018-08-08 16:00 ` Kirill Shcherbatov
0 siblings, 1 reply; 9+ messages in thread
From: n.pettik @ 2018-07-04 13:28 UTC (permalink / raw)
To: tarantool-patches; +Cc: Kirill Shcherbatov
I deleted more code and fixed compile failure on MacOS.
Look at changes and if you are OK with them - squash.
Then LGTM.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-07-04 13:28 ` n.pettik
@ 2018-08-08 16:00 ` Kirill Shcherbatov
2018-08-09 9:39 ` n.pettik
0 siblings, 1 reply; 9+ messages in thread
From: Kirill Shcherbatov @ 2018-08-08 16:00 UTC (permalink / raw)
To: tarantool-patches, Nikita Pettik
> I deleted more code and fixed compile failure on MacOS.
> Look at changes and if you are OK with them - squash.
> Then LGTM.
Hi) I've finally returned to this branch and fixed OS X build.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-08-08 16:00 ` Kirill Shcherbatov
@ 2018-08-09 9:39 ` n.pettik
0 siblings, 0 replies; 9+ messages in thread
From: n.pettik @ 2018-08-09 9:39 UTC (permalink / raw)
To: tarantool-patches; +Cc: Kirill Shcherbatov
> Hi) I've finally returned to this branch and fixed OS X build.
Thanks, now LGTM.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [tarantool-patches] Re: [PATCH v1 1/1] sql: drop useless code from os_unix.c
2018-06-28 15:21 [tarantool-patches] [PATCH v1 1/1] sql: drop useless code from os_unix.c Kirill Shcherbatov
2018-07-02 11:22 ` [tarantool-patches] " Vladislav Shpilevoy
@ 2018-08-14 7:45 ` Kirill Yukhin
1 sibling, 0 replies; 9+ messages in thread
From: Kirill Yukhin @ 2018-08-14 7:45 UTC (permalink / raw)
To: tarantool-patches; +Cc: v.shpilevoy, Kirill Shcherbatov
Hello,
On 28 июн 18:21, Kirill Shcherbatov wrote:
> Resolves #3284.
> ---
> https://github.com/tarantool/tarantool/tree/kshch/gh-3284-no-os-unix
> https://github.com/tarantool/tarantool/issues/3284
I've checked the patch into 2.9 branch.
--
Regards, Kirill Yukhin
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2018-08-14 7:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-28 15:21 [tarantool-patches] [PATCH v1 1/1] sql: drop useless code from os_unix.c Kirill Shcherbatov
2018-07-02 11:22 ` [tarantool-patches] " Vladislav Shpilevoy
2018-07-02 14:55 ` Kirill Shcherbatov
2018-07-02 18:29 ` Vladislav Shpilevoy
2018-07-03 11:27 ` Kirill Shcherbatov
2018-07-04 13:28 ` n.pettik
2018-08-08 16:00 ` Kirill Shcherbatov
2018-08-09 9:39 ` n.pettik
2018-08-14 7:45 ` Kirill Yukhin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox