aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/os_win.c1
-rw-r--r--src/pager.c25
-rw-r--r--src/sqlite.h.in6
-rw-r--r--src/test_vfstrace.c5
4 files changed, 36 insertions, 1 deletions
diff --git a/src/os_win.c b/src/os_win.c
index 22052a3fe..56b546fb4 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -3192,6 +3192,7 @@ static int winSectorSize(sqlite3_file *id){
static int winDeviceCharacteristics(sqlite3_file *id){
winFile *p = (winFile*)id;
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
+ SQLITE_IOCAP_UNMOVABLE_WHEN_OPEN |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
diff --git a/src/pager.c b/src/pager.c
index d675b8582..78cb78ab2 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -4797,6 +4797,27 @@ int sqlite3PagerOpen(
}
+/* Verify that the database file has not be deleted or renamed out from
+** under the pager. Return SQLITE_OK if the database is still were it ought
+** to be on disk. Return non-zero (SQLITE_IOERR_NODB or some other error
+** code from sqlite3OsAccess()) if the database has gone missing.
+*/
+static int databaseIsUnmoved(Pager *pPager){
+ const int fixedFlags = SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
+ SQLITE_IOCAP_UNMOVABLE_WHEN_OPEN;
+ int dc;
+ int x = 0, rc;
+
+ if( pPager->tempFile ) return SQLITE_OK;
+ if( pPager->dbSize==0 ) return SQLITE_OK;
+ assert( pPager->zFilename && pPager->zFilename[0] );
+ dc = sqlite3OsDeviceCharacteristics(pPager->fd);
+ if( (dc&fixedFlags)==fixedFlags ) return SQLITE_OK;
+ rc = sqlite3OsAccess(pPager->pVfs, pPager->zFilename, SQLITE_ACCESS_EXISTS, &x);
+ if( rc==SQLITE_OK && !x ) rc = SQLITE_IOERR_NODB;
+ return rc;
+}
+
/*
** This function is called after transitioning from PAGER_UNLOCK to
@@ -4970,6 +4991,10 @@ int sqlite3PagerSharedLock(Pager *pPager){
goto failed;
}
+ /* Verify that the database is unmoved and undeleted */
+ rc = databaseIsUnmoved(pPager);
+ if( rc ) goto failed;
+
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
*/
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 98c89da32..de6b59b0b 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -475,6 +475,7 @@ int sqlite3_exec(
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
+#define SQLITE_IOERR_NODB (SQLITE_IOERR | (27<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@@ -553,7 +554,9 @@ int sqlite3_exec(
** after reboot following a crash or power loss, the only bytes in a
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
-** guaranteed to be unchanged.
+** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+** and SQLITE_IOCAP_UNMOVABLE_WHEN_OPEN flags indicate that a file
+** cannot be deleted or renamed when open, respectively.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -568,6 +571,7 @@ int sqlite3_exec(
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
+#define SQLITE_IOCAP_UNMOVABLE_WHEN_OPEN 0x00002000
/*
** CAPI3REF: File Locking Levels
diff --git a/src/test_vfstrace.c b/src/test_vfstrace.c
index 0aacc01fe..8d56cf894 100644
--- a/src/test_vfstrace.c
+++ b/src/test_vfstrace.c
@@ -258,6 +258,11 @@ static void vfstrace_print_errcode(
case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
+ case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
+ case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
+ case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
+ case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
+ case SQLITE_IOERR_NODB: zVal = "SQLITE_IOERR_NODB"; break;
case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;