Index: third_party/sqlite/src/src/os_unix.c |
diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c |
index 77ffd8ac0d9a50c0328d03aff3dca52ccd5bb52f..1624f6a2ce220925271aab83826f0ed73219fa39 100644 |
--- a/third_party/sqlite/src/src/os_unix.c |
+++ b/third_party/sqlite/src/src/os_unix.c |
@@ -84,32 +84,6 @@ |
#endif |
/* |
-** These #defines should enable >2GB file support on Posix if the |
-** underlying operating system supports it. If the OS lacks |
-** large file support, these should be no-ops. |
-** |
-** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch |
-** on the compiler command line. This is necessary if you are compiling |
-** on a recent machine (ex: RedHat 7.2) but you want your code to work |
-** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 |
-** without this option, LFS is enable. But LFS does not exist in the kernel |
-** in RedHat 6.0, so the code won't work. Hence, for maximum binary |
-** portability you should omit LFS. |
-** |
-** The previous paragraph was written in 2005. (This paragraph is written |
-** on 2008-11-28.) These days, all Linux kernels support large files, so |
-** you should probably leave LFS enabled. But some embedded platforms might |
-** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful. |
-*/ |
-#ifndef SQLITE_DISABLE_LFS |
-# define _LARGE_FILE 1 |
-# ifndef _FILE_OFFSET_BITS |
-# define _FILE_OFFSET_BITS 64 |
-# endif |
-# define _LARGEFILE_SOURCE 1 |
-#endif |
- |
-/* |
** standard include files. |
*/ |
#include <sys/types.h> |
@@ -119,11 +93,11 @@ |
#include <time.h> |
#include <sys/time.h> |
#include <errno.h> |
-#ifndef SQLITE_OMIT_WAL |
-#include <sys/mman.h> |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+# include <sys/mman.h> |
#endif |
-#if SQLITE_ENABLE_LOCKING_STYLE |
+#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS |
# include <sys/ioctl.h> |
# if OS_VXWORKS |
# include <semaphore.h> |
@@ -138,6 +112,10 @@ |
# include <sys/mount.h> |
#endif |
+#ifdef HAVE_UTIME |
+# include <utime.h> |
+#endif |
+ |
/* |
** Allowed values of unixFile.fsFlags |
*/ |
@@ -160,8 +138,8 @@ |
#endif |
/* |
- ** Default permissions when creating auto proxy dir |
- */ |
+** Default permissions when creating auto proxy dir |
+*/ |
#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS |
# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 |
#endif |
@@ -202,16 +180,28 @@ struct UnixUnusedFd { |
typedef struct unixFile unixFile; |
struct unixFile { |
sqlite3_io_methods const *pMethod; /* Always the first entry */ |
+ sqlite3_vfs *pVfs; /* The VFS that created this unixFile */ |
unixInodeInfo *pInode; /* Info about locks on this inode */ |
int h; /* The file descriptor */ |
unsigned char eFileLock; /* The type of lock held on this fd */ |
- unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ |
+ 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 |
+#ifdef __QNXNTO__ |
+ int sectorSize; /* Device sector size */ |
+ int deviceCharacteristics; /* Precomputed device characteristics */ |
+#endif |
#if SQLITE_ENABLE_LOCKING_STYLE |
int openFlags; /* The flags specified at open() */ |
#endif |
@@ -219,10 +209,9 @@ struct unixFile { |
unsigned fsFlags; /* cached details from statfs() */ |
#endif |
#if OS_VXWORKS |
- int isDelete; /* Delete on close if true */ |
struct vxworksFileId *pId; /* Unique file ID */ |
#endif |
-#ifndef NDEBUG |
+#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 |
@@ -233,7 +222,9 @@ struct unixFile { |
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. |
@@ -242,12 +233,28 @@ struct unixFile { |
#endif |
}; |
+/* This variable holds the process id (pid) from when the xRandomness() |
+** method was called. If xOpen() is called from a different process id, |
+** indicating that a fork() has occurred, the PRNG will be reset. |
+*/ |
+static int randomnessPid = 0; |
+ |
/* |
** Allowed values for the unixFile.ctrlFlags bitmask: |
*/ |
-#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
-#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ |
-#define UNIXFILE_DIRSYNC 0x04 /* Directory sync needed */ |
+#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
+#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ |
+#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ |
+#ifndef SQLITE_DISABLE_DIRSYNC |
+# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ |
+#else |
+# define UNIXFILE_DIRSYNC 0x00 |
+#endif |
+#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ |
+#define UNIXFILE_DELETE 0x20 /* Delete on close */ |
+#define UNIXFILE_URI 0x40 /* Filename might have query parameters */ |
+#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ |
+#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */ |
/* |
** Include code that is common to all os_*.c files |
@@ -281,8 +288,53 @@ struct unixFile { |
#define threadid 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 |
+ |
+/* |
+** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek() |
+** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. |
+*/ |
+#ifdef __ANDROID__ |
+# define lseek lseek64 |
+#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); |
+} |
+ |
+/* |
+** On some systems, calls to fchown() will trigger a message in a security |
+** log if they come from non-root processes. So avoid calling fchown() if |
+** we are not running as root. |
+*/ |
+static int posixFchown(int fd, uid_t uid, gid_t gid){ |
+#if OS_VXWORKS |
+ return 0; |
+#else |
+ return geteuid() ? 0 : fchown(fd,uid,gid); |
+#endif |
+} |
+ |
/* Forward reference */ |
static int openDirectory(const char*, int*); |
+static int unixGetpagesize(void); |
/* |
** Many system calls are accessed through pointer-to-functions so that |
@@ -291,12 +343,12 @@ static int openDirectory(const char*, int*); |
** to all overrideable system calls. |
*/ |
static struct unix_syscall { |
- const char *zName; /* Name of the sytem call */ |
+ 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)open, 0 }, |
-#define osOpen ((int(*)(const char*,int,...))aSyscall[0].pCurrent) |
+ { "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) |
@@ -333,7 +385,7 @@ static struct unix_syscall { |
{ "read", (sqlite3_syscall_ptr)read, 0 }, |
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
-#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE) |
+#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) |
{ "pread", (sqlite3_syscall_ptr)pread, 0 }, |
#else |
{ "pread", (sqlite3_syscall_ptr)0, 0 }, |
@@ -350,7 +402,7 @@ static struct unix_syscall { |
{ "write", (sqlite3_syscall_ptr)write, 0 }, |
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
-#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE) |
+#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) |
{ "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
#else |
{ "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
@@ -366,11 +418,7 @@ static struct unix_syscall { |
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
aSyscall[13].pCurrent) |
-#if SQLITE_ENABLE_LOCKING_STYLE |
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
-#else |
- { "fchmod", (sqlite3_syscall_ptr)0, 0 }, |
-#endif |
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
@@ -386,6 +434,33 @@ static struct unix_syscall { |
{ "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) |
+ |
+ { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 }, |
+#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) |
+ |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+ { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, |
+#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent) |
+ |
+ { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, |
+#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent) |
+ |
+#if HAVE_MREMAP |
+ { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, |
+#else |
+ { "mremap", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent) |
+ { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, |
+#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent) |
+ |
+#endif |
+ |
}; /* End of the overrideable system calls */ |
/* |
@@ -472,12 +547,66 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){ |
} |
/* |
-** Retry open() calls that fail due to EINTR |
+** 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. |
*/ |
-static int robust_open(const char *z, int f, int m){ |
- int rc; |
- do{ rc = osOpen(z,f,m); }while( rc<0 && errno==EINTR ); |
- return rc; |
+#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR |
+# define SQLITE_MINIMUM_FILE_DESCRIPTOR 3 |
+#endif |
+ |
+/* |
+** Invoke open(). Do so multiple times, until it either succeeds or |
+** fails for some reason other than EINTR. |
+** |
+** If the file creation mode "m" is 0 then set it to the default for |
+** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally |
+** 0644) as modified by the system umask. If m is not 0, then |
+** make the file creation mode be exactly m ignoring the umask. |
+** |
+** The m parameter will be non-zero only when creating -wal, -journal, |
+** and -shm files. We want those files to have *exactly* the same |
+** permissions as their original database, unadulterated by the umask. |
+** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a |
+** transaction crashes and leaves behind hot journals, then any |
+** process that is able to write to the database will also be able to |
+** recover the hot journals. |
+*/ |
+static int 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 |
+ if( fd<0 ){ |
+ if( errno==EINTR ) continue; |
+ break; |
+ } |
+ if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; |
+ osClose(fd); |
+ sqlite3_log(SQLITE_WARNING, |
+ "attempt to open \"%s\" as file descriptor %d", z, fd); |
+ fd = -1; |
+ if( osOpen("/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 defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) |
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); |
+#endif |
+ } |
+ return fd; |
} |
/* |
@@ -507,10 +636,10 @@ static int unixMutexHeld(void) { |
#endif |
-#ifdef SQLITE_DEBUG |
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) |
/* |
** Helper function for printing out trace information from debugging |
-** binaries. This returns the string represetation of the supplied |
+** binaries. This returns the string representation of the supplied |
** integer lock-type. |
*/ |
static const char *azFileLock(int eFileLock){ |
@@ -587,9 +716,22 @@ static int lockTrace(int fd, int op, struct flock *p){ |
/* |
** Retry ftruncate() calls that fail due to EINTR |
+** |
+** All calls to ftruncate() within this file should be made through this wrapper. |
+** On the Android platform, bypassing the logic below could lead to a corrupt |
+** database. |
*/ |
static int robust_ftruncate(int h, sqlite3_int64 sz){ |
int rc; |
+#ifdef __ANDROID__ |
+ /* On Android, ftruncate() always uses 32-bit offsets, even if |
+ ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to |
+ ** truncate a file to any size larger than 2GiB. Silently ignore any |
+ ** such attempts. */ |
+ if( sz>(sqlite3_int64)0x7FFFFFFF ){ |
+ rc = SQLITE_OK; |
+ }else |
+#endif |
do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); |
return rc; |
} |
@@ -634,25 +776,15 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { |
case EACCES: |
/* EACCES is like EAGAIN during locking operations, but not any other time*/ |
if( (sqliteIOErr == SQLITE_IOERR_LOCK) || |
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) || |
- (sqliteIOErr == SQLITE_IOERR_RDLOCK) || |
- (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){ |
+ (sqliteIOErr == SQLITE_IOERR_UNLOCK) || |
+ (sqliteIOErr == SQLITE_IOERR_RDLOCK) || |
+ (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){ |
return SQLITE_BUSY; |
} |
/* else fall through */ |
case EPERM: |
return SQLITE_PERM; |
- /* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And |
- ** this module never makes such a call. And the code in SQLite itself |
- ** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons |
- ** this case is also commented out. If the system does set errno to EDEADLK, |
- ** the default SQLITE_IOERR_XXX code will be returned. */ |
-#if 0 |
- case EDEADLK: |
- return SQLITE_IOERR_BLOCKED; |
-#endif |
- |
#if EOPNOTSUPP!=ENOTSUP |
case EOPNOTSUPP: |
/* something went terribly awry, unless during file system support |
@@ -670,7 +802,9 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { |
case ENODEV: |
case ENXIO: |
case ENOENT: |
+#ifdef ESTALE /* ESTALE is not defined on Interix systems */ |
case ESTALE: |
+#endif |
case ENOSYS: |
/* these should force the client to close the file and reconnect */ |
@@ -680,7 +814,6 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { |
} |
- |
/****************************************************************************** |
****************** Begin Unique File ID Utility Used By VxWorks *************** |
** |
@@ -942,7 +1075,7 @@ struct unixInodeInfo { |
UnixUnusedFd *pUnused; /* Unused file descriptors to close */ |
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ |
unixInodeInfo *pPrev; /* .... doubly linked */ |
-#if defined(SQLITE_ENABLE_LOCKING_STYLE) |
+#if SQLITE_ENABLE_LOCKING_STYLE |
unsigned long long sharedByte; /* for AFP simulated shared lock */ |
#endif |
#if OS_VXWORKS |
@@ -969,7 +1102,7 @@ static unixInodeInfo *inodeList = 0; |
** The first argument passed to the macro should be the error code that |
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). |
** The two subsequent arguments should be the name of the OS function that |
-** failed (e.g. "unlink", "open") and the the associated file-system path, |
+** failed (e.g. "unlink", "open") and the associated file-system path, |
** if any. |
*/ |
#define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__) |
@@ -992,7 +1125,7 @@ static int unixLogErrorAtLine( |
zErr = aErr; |
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, |
- ** assume that the system provides the the GNU version of strerror_r() that |
+ ** assume that the system provides the GNU version of strerror_r() that |
** returns a pointer to a buffer containing the error message. That pointer |
** may point to aErr[], or it may point to some static storage somewhere. |
** Otherwise, assume that the system provides the POSIX version of |
@@ -1016,7 +1149,6 @@ static int unixLogErrorAtLine( |
zErr = strerror(iErrno); |
#endif |
- assert( errcode!=SQLITE_OK ); |
if( zPath==0 ) zPath = ""; |
sqlite3_log(errcode, |
"os_unix.c:%d: (%d) %s(%s) - %s", |
@@ -1181,6 +1313,66 @@ static int findInodeInfo( |
return SQLITE_OK; |
} |
+/* |
+** Return TRUE if pFile has been renamed or unlinked since it was first opened. |
+*/ |
+static int fileHasMoved(unixFile *pFile){ |
+#if OS_VXWORKS |
+ return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId; |
+#else |
+ struct stat buf; |
+ |
+ /* TODO(shess): This check doesn't work when the Chromium's WebDB code is |
+ ** running in the sandbox. |
+ */ |
+ return 0; |
+ |
+ return pFile->pInode!=0 && |
+ (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino); |
+#endif |
+} |
+ |
+ |
+/* |
+** Check a unixFile that is a database. Verify the following: |
+** |
+** (1) There is exactly one hard link on the file |
+** (2) The file is not a symbolic link |
+** (3) The file has not been renamed or unlinked |
+** |
+** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right. |
+*/ |
+static void verifyDbFile(unixFile *pFile){ |
+ struct stat buf; |
+ int rc; |
+ if( pFile->ctrlFlags & UNIXFILE_WARNED ){ |
+ /* One or more of the following warnings have already been issued. Do not |
+ ** repeat them so as not to clutter the error log */ |
+ return; |
+ } |
+ rc = osFstat(pFile->h, &buf); |
+ if( rc!=0 ){ |
+ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath); |
+ pFile->ctrlFlags |= UNIXFILE_WARNED; |
+ return; |
+ } |
+ if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){ |
+ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath); |
+ pFile->ctrlFlags |= UNIXFILE_WARNED; |
+ return; |
+ } |
+ if( buf.st_nlink>1 ){ |
+ sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath); |
+ pFile->ctrlFlags |= UNIXFILE_WARNED; |
+ return; |
+ } |
+ if( fileHasMoved(pFile) ){ |
+ sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath); |
+ pFile->ctrlFlags |= UNIXFILE_WARNED; |
+ return; |
+ } |
+} |
+ |
/* |
** This routine checks if there is a RESERVED lock held on the specified |
@@ -1340,14 +1532,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){ |
*/ |
int rc = SQLITE_OK; |
unixFile *pFile = (unixFile*)id; |
- unixInodeInfo *pInode = pFile->pInode; |
+ unixInodeInfo *pInode; |
struct flock lock; |
int tErrno = 0; |
assert( pFile ); |
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, |
azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
- azFileLock(pInode->eFileLock), pInode->nShared , getpid())); |
+ azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid())); |
/* If there is already a lock of this type or more restrictive on the |
** unixFile, do nothing. Don't use the end_lock: exit path, as |
@@ -1488,7 +1680,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ |
} |
-#ifndef NDEBUG |
+#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 |
@@ -1551,7 +1743,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ |
unixInodeInfo *pInode; |
struct flock lock; |
int rc = SQLITE_OK; |
- int h; |
assert( pFile ); |
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, |
@@ -1563,16 +1754,12 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ |
return SQLITE_OK; |
} |
unixEnterMutex(); |
- h = pFile->h; |
pInode = pFile->pInode; |
assert( pInode->nShared!=0 ); |
if( pFile->eFileLock>SHARED_LOCK ){ |
assert( pInode->eFileLock==pFile->eFileLock ); |
- SimulateIOErrorBenign(1); |
- SimulateIOError( h=(-1) ) |
- SimulateIOErrorBenign(0); |
-#ifndef NDEBUG |
+#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 |
@@ -1581,11 +1768,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ |
** the file has changed and hence might not know to flush their |
** cache. The use of a stale cache can lead to database corruption. |
*/ |
-#if 0 |
- assert( pFile->inNormalWrite==0 |
- || pFile->dbUpdate==0 |
- || pFile->transCntrChng==1 ); |
-#endif |
pFile->inNormalWrite = 0; |
#endif |
@@ -1687,14 +1869,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ |
lock.l_type = F_UNLCK; |
lock.l_whence = SEEK_SET; |
lock.l_start = lock.l_len = 0L; |
- SimulateIOErrorBenign(1); |
- SimulateIOError( h=(-1) ) |
- SimulateIOErrorBenign(0); |
if( unixFileLock(pFile, &lock)==0 ){ |
pInode->eFileLock = NO_LOCK; |
}else{ |
rc = SQLITE_IOERR_UNLOCK; |
- pFile->lastErrno = errno; |
+ pFile->lastErrno = errno; |
pInode->eFileLock = NO_LOCK; |
pFile->eFileLock = NO_LOCK; |
} |
@@ -1710,7 +1889,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ |
closePendingFds(pFile); |
} |
} |
- |
+ |
end_unlock: |
unixLeaveMutex(); |
if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; |
@@ -1725,9 +1904,17 @@ end_unlock: |
** the requested locking level, this routine is a no-op. |
*/ |
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 |
** common to all locking schemes. It closes the directory and file |
@@ -1740,19 +1927,29 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){ |
*/ |
static int closeUnixFile(sqlite3_file *id){ |
unixFile *pFile = (unixFile*)id; |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ unixUnmapfile(pFile); |
+#endif |
if( pFile->h>=0 ){ |
robust_close(pFile, pFile->h, __LINE__); |
pFile->h = -1; |
} |
#if OS_VXWORKS |
if( pFile->pId ){ |
- if( pFile->isDelete ){ |
+ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ |
osUnlink(pFile->pId->zCanonicalName); |
} |
vxworksReleaseFileId(pFile->pId); |
pFile->pId = 0; |
} |
#endif |
+#ifdef SQLITE_UNLINK_AFTER_CLOSE |
+ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ |
+ osUnlink(pFile->zPath); |
+ sqlite3_free(*(char**)&pFile->zPath); |
+ pFile->zPath = 0; |
+ } |
+#endif |
OSTRACE(("CLOSE %-3d\n", pFile->h)); |
OpenCounter(-1); |
sqlite3_free(pFile->pUnused); |
@@ -1766,6 +1963,7 @@ static int closeUnixFile(sqlite3_file *id){ |
static int unixClose(sqlite3_file *id){ |
int rc = SQLITE_OK; |
unixFile *pFile = (unixFile *)id; |
+ verifyDbFile(pFile); |
unixUnlock(id, NO_LOCK); |
unixEnterMutex(); |
@@ -1834,9 +2032,9 @@ static int nolockClose(sqlite3_file *id) { |
/****************************************************************************** |
************************* Begin dot-file Locking ****************************** |
** |
-** The dotfile locking implementation uses the existance of separate lock |
-** files in order to control access to the database. This works on just |
-** about every filesystem imaginable. But there are serious downsides: |
+** 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. |
@@ -1847,15 +2045,15 @@ static int nolockClose(sqlite3_file *id) { |
** Nevertheless, a dotlock is an appropriate locking mode for use if no |
** other locking strategy is available. |
** |
-** Dotfile locking works by creating a file in the same directory as the |
-** database and with the same name but with a ".lock" extension added. |
-** The existance of a lock file implies an EXCLUSIVE lock. All other lock |
-** types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE. |
+** 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 file. |
+** lock directory. |
*/ |
#define DOTLOCK_SUFFIX ".lock" |
@@ -1922,7 +2120,6 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { |
*/ |
static int dotlockLock(sqlite3_file *id, int eFileLock) { |
unixFile *pFile = (unixFile*)id; |
- int fd; |
char *zLockFile = (char *)pFile->lockingContext; |
int rc = SQLITE_OK; |
@@ -1932,17 +2129,19 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) { |
*/ |
if( pFile->eFileLock > NO_LOCK ){ |
pFile->eFileLock = eFileLock; |
-#if !OS_VXWORKS |
/* 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 */ |
- fd = robust_open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600); |
- if( fd<0 ){ |
- /* failed to open/create the file, someone else may have stolen the lock */ |
+ rc = osMkdir(zLockFile, 0777); |
+ if( rc<0 ){ |
+ /* failed to open/create the lock directory */ |
int tErrno = errno; |
if( EEXIST == tErrno ){ |
rc = SQLITE_BUSY; |
@@ -1954,7 +2153,6 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) { |
} |
return rc; |
} |
- robust_close(pFile, fd, __LINE__); |
/* got it, set the type and return ok */ |
pFile->eFileLock = eFileLock; |
@@ -1973,10 +2171,11 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) { |
static int dotlockUnlock(sqlite3_file *id, int eFileLock) { |
unixFile *pFile = (unixFile*)id; |
char *zLockFile = (char *)pFile->lockingContext; |
+ int rc; |
assert( pFile ); |
OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, |
- pFile->eFileLock, getpid())); |
+ pFile->eFileLock, getpid())); |
assert( eFileLock<=SHARED_LOCK ); |
/* no-op if possible */ |
@@ -1994,9 +2193,11 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { |
/* To fully unlock the database, delete the lock file */ |
assert( eFileLock==NO_LOCK ); |
- if( osUnlink(zLockFile) ){ |
- int rc = 0; |
+ rc = osRmdir(zLockFile); |
+ if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile); |
+ if( rc<0 ){ |
int tErrno = errno; |
+ rc = 0; |
if( ENOENT != tErrno ){ |
rc = SQLITE_IOERR_UNLOCK; |
} |
@@ -2013,13 +2214,13 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { |
** Close a file. Make sure the lock has been released before closing. |
*/ |
static int dotlockClose(sqlite3_file *id) { |
- int rc; |
+ int rc = SQLITE_OK; |
if( id ){ |
unixFile *pFile = (unixFile*)id; |
dotlockUnlock(id, NO_LOCK); |
sqlite3_free(pFile->lockingContext); |
+ rc = closeUnixFile(id); |
} |
- rc = closeUnixFile(id); |
return rc; |
} |
/****************** End of the dot-file lock implementation ******************* |
@@ -2223,10 +2424,12 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { |
** Close a file. |
*/ |
static int flockClose(sqlite3_file *id) { |
+ int rc = SQLITE_OK; |
if( id ){ |
flockUnlock(id, NO_LOCK); |
+ rc = closeUnixFile(id); |
} |
- return closeUnixFile(id); |
+ return rc; |
} |
#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */ |
@@ -2269,7 +2472,6 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { |
/* Otherwise see if some other process holds it. */ |
if( !reserved ){ |
sem_t *pSem = pFile->pInode->pSem; |
- struct stat statBuf; |
if( sem_trywait(pSem)==-1 ){ |
int tErrno = errno; |
@@ -2322,7 +2524,6 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { |
*/ |
static int semLock(sqlite3_file *id, int eFileLock) { |
unixFile *pFile = (unixFile*)id; |
- int fd; |
sem_t *pSem = pFile->pInode->pSem; |
int rc = SQLITE_OK; |
@@ -2361,7 +2562,7 @@ static int semUnlock(sqlite3_file *id, int eFileLock) { |
assert( pFile ); |
assert( pSem ); |
OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, |
- pFile->eFileLock, getpid())); |
+ pFile->eFileLock, getpid())); |
assert( eFileLock<=SHARED_LOCK ); |
/* no-op if possible */ |
@@ -2500,11 +2701,12 @@ 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; ); |
assert( pFile ); |
- afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; |
+ context = (afpLockingContext *) pFile->lockingContext; |
if( context->reserved ){ |
*pResOut = 1; |
return SQLITE_OK; |
@@ -2644,7 +2846,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ |
** operating system calls for the specified lock. |
*/ |
if( eFileLock==SHARED_LOCK ){ |
- int lrc1, lrc2, lrc1Errno; |
+ int lrc1, lrc2, lrc1Errno = 0; |
long lk, mask; |
assert( pInode->nShared==0 ); |
@@ -2775,7 +2977,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { |
SimulateIOError( h=(-1) ) |
SimulateIOErrorBenign(0); |
-#ifndef NDEBUG |
+#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 |
@@ -2923,7 +3125,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ |
** NB: If you define USE_PREAD or USE_PREAD64, then it might also |
** be necessary to define _XOPEN_SOURCE to be 500. This varies from |
** one system to another. Since SQLite does not define USE_PREAD |
-** any any form by default, we will not attempt to define _XOPEN_SOURCE. |
+** 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 |
@@ -2931,35 +3133,51 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ |
*/ |
static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ |
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 ); |
+ cnt &= 0x1ffff; |
+ do{ |
#if defined(USE_PREAD) |
- do{ got = osPread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); |
- SimulateIOError( got = -1 ); |
+ got = osPread(id->h, pBuf, cnt, offset); |
+ SimulateIOError( got = -1 ); |
#elif defined(USE_PREAD64) |
- do{ got = osPread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR); |
- SimulateIOError( got = -1 ); |
+ got = osPread64(id->h, pBuf, cnt, offset); |
+ SimulateIOError( got = -1 ); |
#else |
- newOffset = lseek(id->h, offset, SEEK_SET); |
- SimulateIOError( newOffset-- ); |
- if( newOffset!=offset ){ |
- if( newOffset == -1 ){ |
- ((unixFile*)id)->lastErrno = errno; |
- }else{ |
- ((unixFile*)id)->lastErrno = 0; |
+ newOffset = lseek(id->h, offset, SEEK_SET); |
+ SimulateIOError( newOffset-- ); |
+ if( newOffset!=offset ){ |
+ if( newOffset == -1 ){ |
+ ((unixFile*)id)->lastErrno = errno; |
+ }else{ |
+ ((unixFile*)id)->lastErrno = 0; |
+ } |
+ return -1; |
} |
- return -1; |
- } |
- do{ got = osRead(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); |
+ got = osRead(id->h, pBuf, cnt); |
#endif |
+ if( got==cnt ) break; |
+ if( got<0 ){ |
+ if( errno==EINTR ){ got = 1; continue; } |
+ prior = 0; |
+ ((unixFile*)id)->lastErrno = errno; |
+ break; |
+ }else if( got>0 ){ |
+ cnt -= got; |
+ offset += got; |
+ prior += got; |
+ pBuf = (void*)(got + (char*)pBuf); |
+ } |
+ }while( got>0 ); |
TIMER_END; |
- if( got<0 ){ |
- ((unixFile*)id)->lastErrno = errno; |
- } |
- OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED)); |
- return got; |
+ OSTRACE(("READ %-3d %5d %7lld %llu\n", |
+ id->h, got+prior, offset-prior, TIMER_ELAPSED)); |
+ return got+prior; |
} |
/* |
@@ -2976,6 +3194,8 @@ static int unixRead( |
unixFile *pFile = (unixFile *)id; |
int got; |
assert( id ); |
+ assert( offset>=0 ); |
+ assert( amt>0 ); |
/* If this is a database file (not a journal, master-journal or temp |
** file), the bytes in the locking range should never be read or written. */ |
@@ -2986,6 +3206,23 @@ static int unixRead( |
); |
#endif |
+#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; |
@@ -3001,42 +3238,60 @@ static int unixRead( |
} |
/* |
-** 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. |
+** 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 seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ |
- int got; |
-#if (!defined(USE_PREAD) && !defined(USE_PREAD64)) |
- i64 newOffset; |
-#endif |
+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 ); |
+ nBuf &= 0x1ffff; |
TIMER_START; |
+ |
#if defined(USE_PREAD) |
- do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); |
+ do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); |
#elif defined(USE_PREAD64) |
- do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); |
+ do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); |
#else |
- newOffset = lseek(id->h, offset, SEEK_SET); |
- SimulateIOError( newOffset-- ); |
- if( newOffset!=offset ){ |
- if( newOffset == -1 ){ |
- ((unixFile*)id)->lastErrno = errno; |
- }else{ |
- ((unixFile*)id)->lastErrno = 0; |
+ do{ |
+ i64 iSeek = lseek(fd, iOff, SEEK_SET); |
+ SimulateIOError( iSeek-- ); |
+ |
+ if( iSeek!=iOff ){ |
+ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0); |
+ return -1; |
} |
- return -1; |
- } |
- do{ got = osWrite(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); |
+ rc = osWrite(fd, pBuf, nBuf); |
+ }while( rc<0 && errno==EINTR ); |
#endif |
+ |
TIMER_END; |
- if( got<0 ){ |
- ((unixFile*)id)->lastErrno = errno; |
- } |
+ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED)); |
- OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED)); |
- return got; |
+ if( rc<0 && piErrno ) *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); |
} |
@@ -3064,7 +3319,7 @@ static int unixWrite( |
); |
#endif |
-#ifndef NDEBUG |
+#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) then record the fact that the database |
@@ -3086,6 +3341,23 @@ static int unixWrite( |
} |
#endif |
+#if 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( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ |
amt -= wrote; |
offset += wrote; |
@@ -3095,7 +3367,7 @@ static int unixWrite( |
SimulateDiskfullError(( wrote=0, amt=1 )); |
if( amt>0 ){ |
- if( wrote<0 ){ |
+ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ |
/* lastErrno set by seekAndWrite */ |
return SQLITE_IOERR_WRITE; |
}else{ |
@@ -3118,11 +3390,11 @@ int sqlite3_fullsync_count = 0; |
/* |
** We do not trust systems to provide a working fdatasync(). Some do. |
-** Others do no. To be safe, we will stick with the (slower) fsync(). |
-** If you know that your system does support fdatasync() correctly, |
+** 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 |
*/ |
-#if !defined(fdatasync) && !defined(__linux__) |
+#if !defined(fdatasync) |
# define fdatasync fsync |
#endif |
@@ -3264,9 +3536,6 @@ static int openDirectory(const char *zFilename, int *pFd){ |
zDirname[ii] = '\0'; |
fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); |
if( fd>=0 ){ |
-#ifdef FD_CLOEXEC |
- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); |
-#endif |
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); |
} |
} |
@@ -3316,7 +3585,7 @@ static int unixSync(sqlite3_file *id, int flags){ |
} |
/* Also fsync the directory containing the file if the DIRSYNC flag |
- ** is set. This is a one-time occurrance. Many systems (examples: AIX) |
+ ** is set. This is a one-time occurrence. Many systems (examples: AIX) |
** are unable to fsync a directory, so ignore errors on the fsync. |
*/ |
if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ |
@@ -3349,16 +3618,16 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ |
** actual file size after the operation may be larger than the requested |
** size). |
*/ |
- if( pFile->szChunk ){ |
+ if( pFile->szChunk>0 ){ |
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
} |
- rc = robust_ftruncate(pFile->h, (off_t)nByte); |
+ rc = robust_ftruncate(pFile->h, nByte); |
if( rc ){ |
pFile->lastErrno = errno; |
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); |
}else{ |
-#ifndef NDEBUG |
+#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, |
@@ -3371,6 +3640,16 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ |
} |
#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; |
} |
} |
@@ -3412,14 +3691,12 @@ static int proxyFileControl(sqlite3_file*,int,void*); |
/* |
** This function is called to handle the SQLITE_FCNTL_SIZE_HINT |
-** file-control operation. |
-** |
-** If the user has configured a chunk-size for this file, it could be |
-** that the file needs to be extended at this point. Otherwise, the |
-** SQLITE_FCNTL_SIZE_HINT operation is a no-op for Unix. |
+** 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 ){ |
+ if( pFile->szChunk>0 ){ |
i64 nSize; /* Required file size */ |
struct stat buf; /* Used to hold return values of fstat() */ |
@@ -3461,30 +3738,111 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ |
} |
} |
+#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) ){ |
+ pFile->lastErrno = errno; |
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); |
+ } |
+ } |
+ |
+ rc = unixMapfile(pFile, nByte); |
+ return rc; |
+ } |
+#endif |
+ |
return SQLITE_OK; |
} |
/* |
+** If *pArg is initially negative then this is a query. Set *pArg to |
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. |
+** |
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. |
+*/ |
+static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ |
+ if( *pArg<0 ){ |
+ *pArg = (pFile->ctrlFlags & mask)!=0; |
+ }else if( (*pArg)==0 ){ |
+ pFile->ctrlFlags &= ~mask; |
+ }else{ |
+ pFile->ctrlFlags |= mask; |
+ } |
+} |
+ |
+/* 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 = ((unixFile*)id)->eFileLock; |
+ *(int*)pArg = pFile->eFileLock; |
return SQLITE_OK; |
} |
case SQLITE_LAST_ERRNO: { |
- *(int*)pArg = ((unixFile*)id)->lastErrno; |
+ *(int*)pArg = pFile->lastErrno; |
return SQLITE_OK; |
} |
case SQLITE_FCNTL_CHUNK_SIZE: { |
- ((unixFile*)id)->szChunk = *(int *)pArg; |
+ pFile->szChunk = *(int *)pArg; |
return SQLITE_OK; |
} |
case SQLITE_FCNTL_SIZE_HINT: { |
- return fcntlSizeHint((unixFile *)id, *(i64 *)pArg); |
+ int rc; |
+ SimulateIOErrorBenign(1); |
+ rc = fcntlSizeHint(pFile, *(i64 *)pArg); |
+ SimulateIOErrorBenign(0); |
+ return rc; |
+ } |
+ case SQLITE_FCNTL_PERSIST_WAL: { |
+ unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { |
+ unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_VFSNAME: { |
+ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); |
+ return SQLITE_OK; |
} |
-#ifndef NDEBUG |
+ case SQLITE_FCNTL_TEMPFILENAME: { |
+ char *zTFile = sqlite3_malloc( 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 |
@@ -3501,9 +3859,6 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ |
return proxyFileControl(id,op,pArg); |
} |
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ |
- case SQLITE_FCNTL_SYNC_OMITTED: { |
- return SQLITE_OK; /* A no-op */ |
- } |
} |
return SQLITE_NOTFOUND; |
} |
@@ -3518,21 +3873,138 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ |
** a database and its journal file) that the sector size will be the |
** same for both. |
*/ |
+#ifndef __QNXNTO__ |
static int unixSectorSize(sqlite3_file *NotUsed){ |
UNUSED_PARAMETER(NotUsed); |
return SQLITE_DEFAULT_SECTOR_SIZE; |
} |
+#endif |
/* |
-** Return the device characteristics for the file. This is always 0 for unix. |
+** The following version of unixSectorSize() is optimized for QNX. |
*/ |
-static int unixDeviceCharacteristics(sqlite3_file *NotUsed){ |
- UNUSED_PARAMETER(NotUsed); |
- return 0; |
+#ifdef __QNXNTO__ |
+#include <sys/dcmd_blk.h> |
+#include <sys/statvfs.h> |
+static int unixSectorSize(sqlite3_file *id){ |
+ unixFile *pFile = (unixFile*)id; |
+ if( pFile->sectorSize == 0 ){ |
+ struct statvfs fsInfo; |
+ |
+ /* Set defaults for non-supported filesystems */ |
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; |
+ pFile->deviceCharacteristics = 0; |
+ if( fstatvfs(pFile->h, &fsInfo) == -1 ) { |
+ return pFile->sectorSize; |
+ } |
+ |
+ if( !strcmp(fsInfo.f_basetype, "tmp") ) { |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */ |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( strstr(fsInfo.f_basetype, "etfs") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ /* etfs cluster size writes are atomic */ |
+ (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) | |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */ |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ /* full bitset of atomics from max sector size and smaller */ |
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( strstr(fsInfo.f_basetype, "dos") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ /* full bitset of atomics from max sector size and smaller */ |
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else{ |
+ pFile->deviceCharacteristics = |
+ SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */ |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ 0; |
+ } |
+ } |
+ /* Last chance verification. If the sector size isn't a multiple of 512 |
+ ** then it isn't valid.*/ |
+ if( pFile->sectorSize % 512 != 0 ){ |
+ pFile->deviceCharacteristics = 0; |
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; |
+ } |
+ return pFile->sectorSize; |
+} |
+#endif /* __QNXNTO__ */ |
+ |
+/* |
+** 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 *id){ |
+ unixFile *p = (unixFile*)id; |
+ int rc = 0; |
+#ifdef __QNXNTO__ |
+ if( p->sectorSize==0 ) unixSectorSize(id); |
+ rc = p->deviceCharacteristics; |
+#endif |
+ if( p->ctrlFlags & UNIXFILE_PSOW ){ |
+ rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; |
+ } |
+ return rc; |
} |
-#ifndef SQLITE_OMIT_WAL |
+#if !defined(SQLITE_OMIT_WAL) || 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){ |
+#if defined(_BSD_SOURCE) |
+ return getpagesize(); |
+#else |
+ return (int)sysconf(_SC_PAGESIZE); |
+#endif |
+} |
+ |
+#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */ |
+#ifndef SQLITE_OMIT_WAL |
/* |
** Object used to represent an shared memory buffer. |
@@ -3569,7 +4041,8 @@ struct unixShmNode { |
char *zFilename; /* Name of the mmapped file */ |
int h; /* Open file descriptor */ |
int szRegion; /* Size of shared-memory regions */ |
- int nRegion; /* Size of array apRegion */ |
+ u16 nRegion; /* Size of array apRegion */ |
+ u8 isReadonly; /* True if read-only */ |
char **apRegion; /* Array of mapped shared-memory regions */ |
int nRef; /* Number of unixShm objects pointing to this */ |
unixShm *pFirst; /* All unixShm objects pointing to this */ |
@@ -3597,11 +4070,9 @@ struct unixShm { |
unixShmNode *pShmNode; /* The underlying unixShmNode object */ |
unixShm *pNext; /* Next unixShm with the same unixShmNode */ |
u8 hasMutex; /* True if holding the unixShmNode mutex */ |
+ u8 id; /* Id of this connection within its unixShmNode */ |
u16 sharedMask; /* Mask of shared locks held */ |
u16 exclMask; /* Mask of exclusive locks held */ |
-#ifdef SQLITE_DEBUG |
- u8 id; /* Id of this connection within its unixShmNode */ |
-#endif |
}; |
/* |
@@ -3650,7 +4121,7 @@ static int unixShmSystemLock( |
#ifdef SQLITE_DEBUG |
{ u16 mask; |
OSTRACE(("SHM-LOCK ")); |
- mask = (1<<(ofst+n)) - (1<<ofst); |
+ mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst); |
if( rc==SQLITE_OK ){ |
if( lockType==F_UNLCK ){ |
OSTRACE(("unlock %d ok", ofst)); |
@@ -3684,6 +4155,22 @@ static int unixShmSystemLock( |
return rc; |
} |
+/* |
+** Return the minimum number of 32KB shm regions that should be mapped at |
+** a time, assuming that each mapping must be an integer multiple of the |
+** current system page-size. |
+** |
+** Usually, this is 1. The exception seems to be systems that are configured |
+** to use 64KB pages - in this case each mapping must cover at least two |
+** shm regions. |
+*/ |
+static int unixShmRegionPerMap(void){ |
+ int shmsz = 32*1024; /* SHM region size */ |
+ int pgsz = osGetpagesize(); /* System page size */ |
+ assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ |
+ if( pgsz<shmsz ) return 1; |
+ return pgsz/shmsz; |
+} |
/* |
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0. |
@@ -3695,12 +4182,13 @@ static void unixShmPurge(unixFile *pFd){ |
unixShmNode *p = pFd->pInode->pShmNode; |
assert( unixMutexHeld() ); |
if( p && p->nRef==0 ){ |
+ int nShmPerMap = unixShmRegionPerMap(); |
int i; |
assert( p->pInode==pFd->pInode ); |
- if( p->mutex ) sqlite3_mutex_free(p->mutex); |
- for(i=0; i<p->nRegion; i++){ |
+ sqlite3_mutex_free(p->mutex); |
+ for(i=0; i<p->nRegion; i+=nShmPerMap){ |
if( p->h>=0 ){ |
- munmap(p->apRegion[i], p->szRegion); |
+ osMunmap(p->apRegion[i], p->szRegion); |
}else{ |
sqlite3_free(p->apRegion[i]); |
} |
@@ -3775,8 +4263,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ |
/* Call fstat() to figure out the permissions on the database file. If |
** a new *-shm file is created, an attempt will be made to create it |
- ** with the same permissions. The actual permissions the file is created |
- ** with are subject to the current umask setting. |
+ ** with the same permissions. |
*/ |
if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){ |
rc = SQLITE_IOERR_FSTAT; |
@@ -3784,16 +4271,16 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ |
} |
#ifdef SQLITE_SHM_DIRECTORY |
- nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 30; |
+ nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31; |
#else |
- nShmFilename = 5 + (int)strlen(pDbFd->zPath); |
+ nShmFilename = 6 + (int)strlen(pDbFd->zPath); |
#endif |
pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename ); |
if( pShmNode==0 ){ |
rc = SQLITE_NOMEM; |
goto shm_open_err; |
} |
- memset(pShmNode, 0, sizeof(*pShmNode)); |
+ memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); |
zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1]; |
#ifdef SQLITE_SHM_DIRECTORY |
sqlite3_snprintf(nShmFilename, zShmFilename, |
@@ -3801,6 +4288,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ |
(u32)sStat.st_ino, (u32)sStat.st_dev); |
#else |
sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath); |
+ sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); |
#endif |
pShmNode->h = -1; |
pDbFd->pInode->pShmNode = pShmNode; |
@@ -3812,12 +4300,22 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ |
} |
if( pInode->bProcessLock==0 ){ |
- pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT, |
- (sStat.st_mode & 0777)); |
+ int openFlags = O_RDWR | O_CREAT; |
+ if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ |
+ openFlags = O_RDONLY; |
+ pShmNode->isReadonly = 1; |
+ } |
+ pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777)); |
if( pShmNode->h<0 ){ |
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); |
goto shm_open_err; |
} |
+ |
+ /* If this process is running as root, make sure that the SHM file |
+ ** is owned by the same user that owns the original database. Otherwise, |
+ ** the original owner will not be able to connect. |
+ */ |
+ osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); |
/* Check to see if another process is holding the dead-man switch. |
** If not, truncate the file to zero length. |
@@ -3895,6 +4393,8 @@ static int unixShmMap( |
unixShm *p; |
unixShmNode *pShmNode; |
int rc = SQLITE_OK; |
+ int nShmPerMap = unixShmRegionPerMap(); |
+ int nReqRegion; |
/* If the shared-memory file has not yet been opened, open it now. */ |
if( pDbFd->pShm==0 ){ |
@@ -3910,9 +4410,12 @@ static int unixShmMap( |
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); |
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); |
- if( pShmNode->nRegion<=iRegion ){ |
+ /* Minimum number of regions required to be mapped. */ |
+ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; |
+ |
+ if( pShmNode->nRegion<nReqRegion ){ |
char **apNew; /* New apRegion[] array */ |
- int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ |
+ int nByte = nReqRegion*szRegion; /* Minimum required file size */ |
struct stat sStat; /* Used by fstat() */ |
pShmNode->szRegion = szRegion; |
@@ -3930,36 +4433,55 @@ static int unixShmMap( |
if( sStat.st_size<nByte ){ |
/* The requested memory region does not exist. If bExtend is set to |
** false, exit early. *pp will be set to NULL and SQLITE_OK returned. |
- ** |
- ** Alternatively, if bExtend is true, use ftruncate() to allocate |
- ** the requested memory region. |
*/ |
- if( !bExtend ) goto shmpage_out; |
- if( robust_ftruncate(pShmNode->h, nByte) ){ |
- rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate", |
- pShmNode->zFilename); |
+ if( !bExtend ){ |
goto shmpage_out; |
} |
+ |
+ /* Alternatively, if bExtend is true, extend the file. Do this by |
+ ** writing a single byte to the end of each (OS) page being |
+ ** allocated or extended. Technically, we need only write to the |
+ ** last page in order to extend the file. But writing to all new |
+ ** pages forces the OS to allocate them immediately, which reduces |
+ ** the chances of SIGBUS while accessing the mapped region later on. |
+ */ |
+ else{ |
+ static const int pgsz = 4096; |
+ int iPg; |
+ |
+ /* Write to the last byte of each newly allocated or extended page */ |
+ assert( (nByte % pgsz)==0 ); |
+ for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ |
+ if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){ |
+ const char *zFile = pShmNode->zFilename; |
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); |
+ goto shmpage_out; |
+ } |
+ } |
+ } |
} |
} |
/* Map the requested memory region into this processes address space. */ |
apNew = (char **)sqlite3_realloc( |
- pShmNode->apRegion, (iRegion+1)*sizeof(char *) |
+ pShmNode->apRegion, nReqRegion*sizeof(char *) |
); |
if( !apNew ){ |
rc = SQLITE_IOERR_NOMEM; |
goto shmpage_out; |
} |
pShmNode->apRegion = apNew; |
- while(pShmNode->nRegion<=iRegion){ |
+ while( pShmNode->nRegion<nReqRegion ){ |
+ int nMap = szRegion*nShmPerMap; |
+ int i; |
void *pMem; |
if( pShmNode->h>=0 ){ |
- pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, |
- MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion |
+ pMem = osMmap(0, nMap, |
+ pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, |
+ MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion |
); |
if( pMem==MAP_FAILED ){ |
- rc = SQLITE_IOERR; |
+ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); |
goto shmpage_out; |
} |
}else{ |
@@ -3970,8 +4492,11 @@ static int unixShmMap( |
} |
memset(pMem, 0, szRegion); |
} |
- pShmNode->apRegion[pShmNode->nRegion] = pMem; |
- pShmNode->nRegion++; |
+ |
+ for(i=0; i<nShmPerMap; i++){ |
+ pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; |
+ } |
+ pShmNode->nRegion += nShmPerMap; |
} |
} |
@@ -3981,6 +4506,7 @@ shmpage_out: |
}else{ |
*pp = 0; |
} |
+ if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; |
sqlite3_mutex_leave(pShmNode->mutex); |
return rc; |
} |
@@ -4170,6 +4696,227 @@ static int unixShmUnmap( |
# define unixShmUnmap 0 |
#endif /* #ifndef SQLITE_OMIT_WAL */ |
+#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 ); |
+ |
+ if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; |
+ |
+ 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 nByte){ |
+ i64 nMap = nByte; |
+ int rc; |
+ |
+ assert( nMap>=0 || pFd->nFetchOut==0 ); |
+ if( pFd->nFetchOut>0 ) return SQLITE_OK; |
+ |
+ if( nMap<0 ){ |
+ struct stat statbuf; /* Low-level file information */ |
+ rc = osFstat(pFd->h, &statbuf); |
+ if( rc!=SQLITE_OK ){ |
+ return SQLITE_IOERR_FSTAT; |
+ } |
+ nMap = statbuf.st_size; |
+ } |
+ if( nMap>pFd->mmapSizeMax ){ |
+ nMap = pFd->mmapSizeMax; |
+ } |
+ |
+ if( nMap!=pFd->mmapSize ){ |
+ if( nMap>0 ){ |
+ unixRemapfile(pFd, nMap); |
+ }else{ |
+ unixUnmapfile(pFd); |
+ } |
+ } |
+ |
+ 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, i64 iOff, int nAmt, 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. |
** |
@@ -4189,7 +4936,7 @@ static int unixShmUnmap( |
** looks at the filesystem type and tries to guess the best locking |
** strategy from that. |
** |
-** For finder-funtion F, two objects are created: |
+** For finder-function F, two objects are created: |
** |
** (1) The real finder-function named "FImpt()". |
** |
@@ -4210,7 +4957,7 @@ static int unixShmUnmap( |
** * 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) \ |
+#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK, SHMMAP) \ |
static const sqlite3_io_methods METHOD = { \ |
VERSION, /* iVersion */ \ |
CLOSE, /* xClose */ \ |
@@ -4225,10 +4972,12 @@ static const sqlite3_io_methods METHOD = { \ |
unixFileControl, /* xFileControl */ \ |
unixSectorSize, /* xSectorSize */ \ |
unixDeviceCharacteristics, /* xDeviceCapabilities */ \ |
- unixShmMap, /* xShmMap */ \ |
+ SHMMAP, /* xShmMap */ \ |
unixShmLock, /* xShmLock */ \ |
unixShmBarrier, /* xShmBarrier */ \ |
- unixShmUnmap /* xShmUnmap */ \ |
+ unixShmUnmap, /* xShmUnmap */ \ |
+ unixFetch, /* xFetch */ \ |
+ unixUnfetch, /* xUnfetch */ \ |
}; \ |
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ |
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ |
@@ -4245,20 +4994,22 @@ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ |
IOMETHODS( |
posixIoFinder, /* Finder function name */ |
posixIoMethods, /* sqlite3_io_methods object name */ |
- 2, /* shared memory is enabled */ |
+ 3, /* shared memory and mmap are enabled */ |
unixClose, /* xClose method */ |
unixLock, /* xLock method */ |
unixUnlock, /* xUnlock method */ |
- unixCheckReservedLock /* xCheckReservedLock method */ |
+ unixCheckReservedLock, /* xCheckReservedLock method */ |
+ unixShmMap /* xShmMap method */ |
) |
IOMETHODS( |
nolockIoFinder, /* Finder function name */ |
nolockIoMethods, /* sqlite3_io_methods object name */ |
- 1, /* shared memory is disabled */ |
+ 3, /* shared memory is disabled */ |
nolockClose, /* xClose method */ |
nolockLock, /* xLock method */ |
nolockUnlock, /* xUnlock method */ |
- nolockCheckReservedLock /* xCheckReservedLock method */ |
+ nolockCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
IOMETHODS( |
dotlockIoFinder, /* Finder function name */ |
@@ -4267,7 +5018,8 @@ IOMETHODS( |
dotlockClose, /* xClose method */ |
dotlockLock, /* xLock method */ |
dotlockUnlock, /* xUnlock method */ |
- dotlockCheckReservedLock /* xCheckReservedLock method */ |
+ dotlockCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS |
@@ -4278,7 +5030,8 @@ IOMETHODS( |
flockClose, /* xClose method */ |
flockLock, /* xLock method */ |
flockUnlock, /* xUnlock method */ |
- flockCheckReservedLock /* xCheckReservedLock method */ |
+ flockCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
#endif |
@@ -4290,7 +5043,8 @@ IOMETHODS( |
semClose, /* xClose method */ |
semLock, /* xLock method */ |
semUnlock, /* xUnlock method */ |
- semCheckReservedLock /* xCheckReservedLock method */ |
+ semCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
#endif |
@@ -4302,7 +5056,8 @@ IOMETHODS( |
afpClose, /* xClose method */ |
afpLock, /* xLock method */ |
afpUnlock, /* xUnlock method */ |
- afpCheckReservedLock /* xCheckReservedLock method */ |
+ afpCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
#endif |
@@ -4327,7 +5082,8 @@ IOMETHODS( |
proxyClose, /* xClose method */ |
proxyLock, /* xLock method */ |
proxyUnlock, /* xUnlock method */ |
- proxyCheckReservedLock /* xCheckReservedLock method */ |
+ proxyCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
#endif |
@@ -4340,7 +5096,8 @@ IOMETHODS( |
unixClose, /* xClose method */ |
unixLock, /* xLock method */ |
nfsUnlock, /* xUnlock method */ |
- unixCheckReservedLock /* xCheckReservedLock method */ |
+ unixCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
) |
#endif |
@@ -4449,7 +5206,7 @@ static const sqlite3_io_methods |
#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ |
/* |
-** An abstract type for a pointer to a IO method finder function: |
+** An abstract type for a pointer to an IO method finder function: |
*/ |
typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); |
@@ -4462,24 +5219,14 @@ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); |
*/ |
/* |
-** Initializes a unixFile structure with zeros. |
-*/ |
-void initUnixFile(sqlite3_file* file) { |
- memset(file, 0, sizeof(unixFile)); |
-} |
- |
-/* |
** Initialize the contents of the unixFile structure pointed to by pId. |
*/ |
-int fillInUnixFile( |
+static int fillInUnixFile( |
sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
int h, /* Open file descriptor of file being opened */ |
- int syncDir, /* True to sync directory on first sync */ |
sqlite3_file *pId, /* Write to the unixFile structure here */ |
const char *zFilename, /* Name of the file being opened */ |
- int noLock, /* Omit locking if true */ |
- int isDelete, /* Delete on close if true */ |
- int isReadOnly /* True if the file is opened read-only */ |
+ int ctrlFlags /* Zero or more UNIXFILE_* values */ |
){ |
const sqlite3_io_methods *pLockingStyle; |
unixFile *pNew = (unixFile *)pId; |
@@ -4487,11 +5234,6 @@ int fillInUnixFile( |
assert( pNew->pInode==NULL ); |
- /* Parameter isDelete is only used on vxworks. Express this explicitly |
- ** here to prevent compiler warnings about unused parameters. |
- */ |
- UNUSED_PARAMETER(isDelete); |
- |
/* 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. |
@@ -4503,30 +5245,34 @@ int fillInUnixFile( |
assert( zFilename==0 || zFilename[0]=='/' ); |
#endif |
+ /* No locking occurs in temporary files */ |
+ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); |
+ |
OSTRACE(("OPEN %-3d %s\n", h, zFilename)); |
pNew->h = h; |
+ pNew->pVfs = pVfs; |
pNew->zPath = zFilename; |
- if( strcmp(pVfs->zName,"unix-excl")==0 ){ |
- pNew->ctrlFlags = UNIXFILE_EXCL; |
- }else{ |
- pNew->ctrlFlags = 0; |
- } |
- if( isReadOnly ){ |
- pNew->ctrlFlags |= UNIXFILE_RDONLY; |
+ pNew->ctrlFlags = (u8)ctrlFlags; |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap; |
+#endif |
+ if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), |
+ "psow", SQLITE_POWERSAFE_OVERWRITE) ){ |
+ pNew->ctrlFlags |= UNIXFILE_PSOW; |
} |
- if( syncDir ){ |
- pNew->ctrlFlags |= UNIXFILE_DIRSYNC; |
+ if( strcmp(pVfs->zName,"unix-excl")==0 ){ |
+ pNew->ctrlFlags |= UNIXFILE_EXCL; |
} |
#if OS_VXWORKS |
pNew->pId = vxworksFindFileId(zFilename); |
if( pNew->pId==0 ){ |
- noLock = 1; |
+ ctrlFlags |= UNIXFILE_NOLOCK; |
rc = SQLITE_NOMEM; |
} |
#endif |
- if( noLock ){ |
+ if( ctrlFlags & UNIXFILE_NOLOCK ){ |
pLockingStyle = &nolockIoMethods; |
}else{ |
pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew); |
@@ -4546,7 +5292,7 @@ int fillInUnixFile( |
unixEnterMutex(); |
rc = findInodeInfo(pNew, &pNew->pInode); |
if( rc!=SQLITE_OK ){ |
- /* If an error occured in findInodeInfo(), close the file descriptor |
+ /* If an error occurred in findInodeInfo(), close the file descriptor |
** immediately, before releasing the mutex. findInodeInfo() may fail |
** in two scenarios: |
** |
@@ -4604,6 +5350,7 @@ int fillInUnixFile( |
*/ |
char *zLockFile; |
int nFilename; |
+ assert( zFilename!=0 ); |
nFilename = (int)strlen(zFilename) + 6; |
zLockFile = (char *)sqlite3_malloc(nFilename); |
if( zLockFile==0 ){ |
@@ -4644,15 +5391,15 @@ int fillInUnixFile( |
if( h>=0 ) robust_close(pNew, h, __LINE__); |
h = -1; |
osUnlink(zFilename); |
- isDelete = 0; |
+ pNew->ctrlFlags |= UNIXFILE_DELETE; |
} |
- pNew->isDelete = isDelete; |
#endif |
if( rc!=SQLITE_OK ){ |
if( h>=0 ) robust_close(pNew, h, __LINE__); |
}else{ |
pNew->pMethod = pLockingStyle; |
OpenCounter(+1); |
+ verifyDbFile(pNew); |
} |
return rc; |
} |
@@ -4665,6 +5412,7 @@ static const char *unixTempFileDir(void){ |
static const char *azDirs[] = { |
0, |
0, |
+ 0, |
"/var/tmp", |
"/usr/tmp", |
"/tmp", |
@@ -4675,7 +5423,8 @@ static const char *unixTempFileDir(void){ |
const char *zDir = 0; |
azDirs[0] = sqlite3_temp_directory; |
- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); |
+ if( !azDirs[1] ) azDirs[1] = getenv("SQLITE_TMPDIR"); |
+ if( !azDirs[2] ) azDirs[2] = getenv("TMPDIR"); |
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){ |
if( zDir==0 ) continue; |
if( osStat(zDir, &buf) ) continue; |
@@ -4711,18 +5460,19 @@ static int unixGetTempname(int nBuf, char *zBuf){ |
/* Check that the output buffer is large enough for the temporary file |
** name. If it is not, return SQLITE_ERROR. |
*/ |
- if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 17) >= (size_t)nBuf ){ |
+ if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){ |
return SQLITE_ERROR; |
} |
do{ |
- sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); |
+ sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir); |
j = (int)strlen(zBuf); |
sqlite3_randomness(15, &zBuf[j]); |
for(i=0; i<15; i++, j++){ |
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
} |
zBuf[j] = 0; |
+ zBuf[j+1] = 0; |
}while( osAccess(zBuf,0)==0 ); |
return SQLITE_OK; |
} |
@@ -4770,7 +5520,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ |
** 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 resusable file descriptor are not dire. */ |
+ ** not searching for a reusable file descriptor are not dire. */ |
if( 0==osStat(zPath, &sStat) ){ |
unixInodeInfo *pInode; |
@@ -4801,23 +5551,31 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ |
** written to *pMode. If an IO error occurs, an SQLite error code is |
** returned and the value of *pMode is not modified. |
** |
-** If the file being opened is a temporary file, it is always created with |
-** the octal permissions 0600 (read/writable by owner only). If the file |
-** is a database or master journal file, it is created with the permissions |
-** mask SQLITE_DEFAULT_FILE_PERMISSIONS. |
-** |
-** Finally, if the file being opened is a WAL or regular journal file, then |
+** 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 WAL or 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, WAL and 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 */ |
+ 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_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
char zDb[MAX_PATHNAME+1]; /* Database file path */ |
int nDb; /* Number of valid bytes in zDb */ |
@@ -4829,27 +5587,35 @@ static int findCreateFileMode( |
** |
** "<path to db>-journal" |
** "<path to db>-wal" |
- ** "<path to db>-journal-NNNN" |
- ** "<path to db>-wal-NNNN" |
+ ** "<path to db>-journalNN" |
+ ** "<path to db>-walNN" |
** |
- ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are |
+ ** where NN is a decimal number. The NN naming schemes are |
** used by the test_multiplex.c module. |
*/ |
nDb = sqlite3Strlen30(zPath) - 1; |
- while( nDb>0 && zPath[nDb]!='l' ) nDb--; |
- nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7); |
+#ifdef SQLITE_ENABLE_8_3_NAMES |
+ while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--; |
+ if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK; |
+#else |
+ while( zPath[nDb]!='-' ){ |
+ assert( nDb>0 ); |
+ assert( zPath[nDb]!='\n' ); |
+ nDb--; |
+ } |
+#endif |
memcpy(zDb, zPath, nDb); |
zDb[nDb] = '\0'; |
if( 0==osStat(zDb, &sStat) ){ |
*pMode = sStat.st_mode & 0777; |
+ *pUid = sStat.st_uid; |
+ *pGid = sStat.st_gid; |
}else{ |
rc = SQLITE_IOERR_FSTAT; |
} |
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ |
*pMode = 0600; |
- }else{ |
- *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; |
} |
return rc; |
} |
@@ -4866,9 +5632,9 @@ int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs, |
int dirfd, |
sqlite3_file* file, |
const char* fileName, |
- int noLock, |
- int isDelete) { |
- return fillInUnixFile(vfs, fd, dirfd, file, fileName, noLock, isDelete, 0); |
+ int noLock) { |
+ int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0); |
+ return fillInUnixFile(vfs, fd, file, fileName, ctrlFlags); |
} |
/* |
@@ -4956,6 +5722,7 @@ static int unixOpen( |
int eType = flags&0xFFFFFF00; /* Type of file to open */ |
int noLock; /* True to omit locking primitives */ |
int rc = SQLITE_OK; /* Function Return Code */ |
+ int ctrlFlags = 0; /* UNIXFILE_* flags */ |
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); |
@@ -4965,6 +5732,9 @@ static int unixOpen( |
#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() |
@@ -4979,7 +5749,7 @@ static int unixOpen( |
/* 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+1]; |
+ char zTmpname[MAX_PATHNAME+2]; |
const char *zName = zPath; |
/* Check the following statements are true: |
@@ -5008,6 +5778,16 @@ static int unixOpen( |
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
); |
+ /* 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); |
+ } |
+ |
chromium_sqlite3_initialize_unix_sqlite3_file(pFile); |
if( eType==SQLITE_OPEN_MAIN_DB ){ |
@@ -5015,14 +5795,24 @@ static int unixOpen( |
if( rc!=SQLITE_OK ){ |
return rc; |
} |
+ |
+ /* 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 && !syncDir); |
- rc = unixGetTempname(MAX_PATHNAME+1, zTmpname); |
+ rc = unixGetTempname(MAX_PATHNAME+2, 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 |
@@ -5037,7 +5827,9 @@ static int unixOpen( |
if( fd<0 ){ |
mode_t openMode; /* Permissions to create file with */ |
- rc = findCreateFileMode(zName, flags, &openMode); |
+ 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 ); |
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); |
@@ -5058,6 +5850,14 @@ static int unixOpen( |
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); |
goto open_finished; |
} |
+ |
+ /* If this process is running as root and if creating a new rollback |
+ ** journal or WAL file, set the ownership of the journal or WAL to be |
+ ** the same as the original database. |
+ */ |
+ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
+ osFchown(fd, uid, gid); |
+ } |
} |
assert( fd>=0 ); |
if( pOutFlags ){ |
@@ -5069,6 +5869,12 @@ static int unixOpen( |
if( isDelete ){ |
#if OS_VXWORKS |
zPath = zName; |
+#elif defined(SQLITE_UNLINK_AFTER_CLOSE) |
+ zPath = sqlite3_mprintf("%s", zName); |
+ if( zPath==0 ){ |
+ robust_close(p, fd, __LINE__); |
+ return SQLITE_NOMEM; |
+ } |
#else |
osUnlink(zName); |
#endif |
@@ -5079,15 +5885,10 @@ static int unixOpen( |
} |
#endif |
-#ifdef FD_CLOEXEC |
- osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); |
-#endif |
- |
noLock = eType!=SQLITE_OPEN_MAIN_DB; |
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE |
- struct statfs fsInfo; |
if( fstatfs(fd, &fsInfo) == -1 ){ |
((unixFile*)pFile)->lastErrno = errno; |
robust_close(p, fd, __LINE__); |
@@ -5097,7 +5898,14 @@ static int unixOpen( |
((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; |
} |
#endif |
- |
+ |
+ /* Set up appropriate ctrlFlags */ |
+ if( isDelete ) ctrlFlags |= UNIXFILE_DELETE; |
+ if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; |
+ 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; |
@@ -5111,7 +5919,6 @@ static int unixOpen( |
if( envforce!=NULL ){ |
useProxy = atoi(envforce)>0; |
}else{ |
- struct statfs fsInfo; |
if( statfs(zPath, &fsInfo) == -1 ){ |
/* In theory, the close(fd) call is sub-optimal. If the file opened |
** with fd is a database file, and there are other connections open |
@@ -5128,8 +5935,7 @@ static int unixOpen( |
useProxy = !(fsInfo.f_flags&MNT_LOCAL); |
} |
if( useProxy ){ |
- rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, |
- isDelete, isReadonly); |
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); |
if( rc==SQLITE_OK ){ |
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); |
if( rc!=SQLITE_OK ){ |
@@ -5146,8 +5952,8 @@ static int unixOpen( |
} |
#endif |
- rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock, |
- isDelete, isReadonly); |
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); |
+ |
open_finished: |
if( rc!=SQLITE_OK ){ |
chromium_sqlite3_destroy_reusable_file_handle(pFile); |
@@ -5168,11 +5974,20 @@ static int unixDelete( |
int rc = SQLITE_OK; |
UNUSED_PARAMETER(NotUsed); |
SimulateIOError(return SQLITE_IOERR_DELETE); |
- if( osUnlink(zPath)==(-1) && errno!=ENOENT ){ |
- return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); |
+ if( osUnlink(zPath)==(-1) ){ |
+ if( errno==ENOENT |
+#if OS_VXWORKS |
+ || osAccess(zPath,0)!=0 |
+#endif |
+ ){ |
+ rc = SQLITE_IOERR_DELETE_NOENT; |
+ }else{ |
+ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); |
+ } |
+ return rc; |
} |
#ifndef SQLITE_DISABLE_DIRSYNC |
- if( dirSync ){ |
+ if( (dirSync & 1)!=0 ){ |
int fd; |
rc = osOpenDirectory(zPath, &fd); |
if( rc==SQLITE_OK ){ |
@@ -5194,7 +6009,7 @@ static int unixDelete( |
} |
/* |
-** Test the existance of or access permissions of file zPath. The |
+** 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 |
@@ -5360,20 +6175,20 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ |
** tests repeatable. |
*/ |
memset(zBuf, 0, nBuf); |
+ randomnessPid = getpid(); |
#if !defined(SQLITE_TEST) |
{ |
- int pid, fd; |
+ int fd, got; |
fd = robust_open("/dev/urandom", O_RDONLY, 0); |
if( fd<0 ){ |
time_t t; |
time(&t); |
memcpy(zBuf, &t, sizeof(t)); |
- pid = getpid(); |
- memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); |
- assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf ); |
- nBuf = sizeof(t) + sizeof(pid); |
+ memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); |
+ assert( sizeof(t)+sizeof(randomnessPid)<=(size_t)nBuf ); |
+ nBuf = sizeof(t) + sizeof(randomnessPid); |
}else{ |
- do{ nBuf = osRead(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR ); |
+ do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); |
robust_close(0, fd, __LINE__); |
} |
} |
@@ -5427,10 +6242,12 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ |
** epoch of noon in Greenwich on November 24, 4714 B.C according to the |
** proleptic Gregorian calendar. |
** |
-** On success, return 0. Return 1 if the time and date cannot be found. |
+** 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); |
@@ -5441,8 +6258,11 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ |
*piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000; |
#else |
struct timeval sNow; |
- gettimeofday(&sNow, 0); |
- *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; |
+ if( gettimeofday(&sNow, 0)==0 ){ |
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; |
+ }else{ |
+ rc = SQLITE_ERROR; |
+ } |
#endif |
#ifdef SQLITE_TEST |
@@ -5451,7 +6271,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ |
} |
#endif |
UNUSED_PARAMETER(NotUsed); |
- return 0; |
+ return rc; |
} |
/* |
@@ -5460,11 +6280,12 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ |
** return 0. Return 1 if the time and date cannot be found. |
*/ |
static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ |
- sqlite3_int64 i; |
+ sqlite3_int64 i = 0; |
+ int rc; |
UNUSED_PARAMETER(NotUsed); |
- unixCurrentTimeInt64(0, &i); |
+ rc = unixCurrentTimeInt64(0, &i); |
*prNow = i/86400000.0; |
- return 0; |
+ return rc; |
} |
/* |
@@ -5510,7 +6331,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ |
** address in the shared range is taken for a SHARED lock, the entire |
** shared range is taken for an EXCLUSIVE lock): |
** |
-** PENDING_BYTE 0x40000000 |
+** PENDING_BYTE 0x40000000 |
** RESERVED_BYTE 0x40000001 |
** SHARED_RANGE 0x40000002 -> 0x40000200 |
** |
@@ -5579,7 +6400,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ |
** 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 it's contents do not match the |
+** 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 |
@@ -5631,7 +6452,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ |
** 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 (explicity calling the SQLITE_SET_LOCKPROXYFILE pragma or |
+** files (explicitly calling the SQLITE_SET_LOCKPROXYFILE pragma or |
** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). |
*/ |
@@ -5717,7 +6538,7 @@ static int proxyCreateLockPath(const char *lockPath){ |
if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/') |
|| (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){ |
buf[i]='\0'; |
- if( mkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ |
+ if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ |
int err=errno; |
if( err!=EEXIST ) { |
OSTRACE(("CREATELOCKPATH FAILED creating %s, " |
@@ -5771,17 +6592,17 @@ static int proxyCreateUnixFile( |
} |
} |
if( fd<0 ){ |
- fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS); |
+ fd = robust_open(path, openFlags, 0); |
terrno = errno; |
if( fd<0 && errno==ENOENT && islockfile ){ |
if( proxyCreateLockPath(path) == SQLITE_OK ){ |
- fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS); |
+ fd = robust_open(path, openFlags, 0); |
} |
} |
} |
if( fd<0 ){ |
openFlags = O_RDONLY; |
- fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS); |
+ fd = robust_open(path, openFlags, 0); |
terrno = errno; |
} |
if( fd<0 ){ |
@@ -5812,7 +6633,7 @@ static int proxyCreateUnixFile( |
pUnused->flags = openFlags; |
pNew->pUnused = pUnused; |
- rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0); |
+ rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); |
if( rc==SQLITE_OK ){ |
*ppFile = pNew; |
return SQLITE_OK; |
@@ -5852,6 +6673,8 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){ |
return SQLITE_IOERR; |
} |
} |
+#else |
+ UNUSED_PARAMETER(pError); |
#endif |
#ifdef SQLITE_TEST |
/* simulate multiple hosts by creating unique hostid file paths */ |
@@ -5903,8 +6726,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ |
goto end_breaklock; |
} |
/* write it out to the temporary break file */ |
- fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), |
- SQLITE_DEFAULT_FILE_PERMISSIONS); |
+ 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; |
@@ -5944,6 +6766,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ |
int nTries = 0; |
struct timespec conchModTime; |
+ memset(&conchModTime, 0, sizeof(conchModTime)); |
do { |
rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); |
nTries ++; |
@@ -6175,12 +6998,12 @@ static int proxyTakeConch(unixFile *pFile){ |
end_takeconch: |
OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); |
if( rc==SQLITE_OK && pFile->openFlags ){ |
+ int fd; |
if( pFile->h>=0 ){ |
robust_close(pFile, pFile->h, __LINE__); |
} |
pFile->h = -1; |
- int fd = robust_open(pCtx->dbPath, pFile->openFlags, |
- SQLITE_DEFAULT_FILE_PERMISSIONS); |
+ fd = robust_open(pCtx->dbPath, pFile->openFlags, 0); |
OSTRACE(("TRANSPROXY: OPEN %d\n", fd)); |
if( fd>=0 ){ |
pFile->h = fd; |
@@ -6749,7 +7572,7 @@ int sqlite3_os_init(void){ |
/* Double-check that the aSyscall[] array has been constructed |
** correctly. See ticket [bb3a86e890c8e96ab] */ |
- assert( ArraySize(aSyscall)==18 ); |
+ assert( ArraySize(aSyscall)==25 ); |
/* Register all VFSes defined in the aVfs[] array */ |
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ |