From 17221813282f7b88a6eafc94ed21f7468cb1041b Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Tue, 15 Feb 2005 03:38:05 +0000 Subject: [PATCH] Ensure a database file is not truncated without an exclusive lock. Fix for ticket #1114. (CVS 2332) FossilOrigin-Name: dcbc983355d3207615b52b0724405a024a1a5955 --- manifest | 12 +++---- manifest.uuid | 2 +- src/pager.c | 86 ++++++++++++++++++++++++++++----------------------- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/manifest b/manifest index 7aa1fa9809..37e083d78c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Check\sthat\sread-only\spages\sare\snot\sbeing\smodified\s(disabled\sby\sdefault).\s(CVS\s2331) -D 2005-02-15T02:54:15 +C Ensure\sa\sdatabase\sfile\sis\snot\struncated\swithout\san\sexclusive\slock.\r\nFix\sfor\sticket\s#1114.\s(CVS\s2332) +D 2005-02-15T03:38:06 F Makefile.in d928187101fa3d78426cf48ca30e39d0fb714e57 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -51,7 +51,7 @@ F src/os_unix.c 68d3d32937eee90fe1f50d500d1a4ee826cbe790 F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13 F src/os_win.c bddeae1c3299be0fbe47077dd4e98b786a067f71 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 69efe972d6034d8d5603f5b2a768e43e25dad0c0 +F src/pager.c 835028769569971c7dbd63d11d3517392f1cdae0 F src/pager.h 70d496f372163abb6340f474288c4bb9ea962cf7 F src/parse.y 450fc9c4d5a737be6fdba6e4b2e3de5800d4d750 F src/pragma.c 7e65c5545d83909238adf231e2a6eee6eb43e0d5 @@ -271,7 +271,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd -P cbed92f397ec13b57771ab8b5be74c0cacf35dfd -R f5e0bf334bc8ca4771ae6f5140466932 +P 8514a4feb2a86e93c4251c491d394e861bb65edb +R 68447a9e1a1587fdc5cb563c6b34ab1f U danielk1977 -Z 79138fc5bf3ab18977a8db63dd8b495b +Z 2caaa7f8c9b8fb759f5bcfb478549a3f diff --git a/manifest.uuid b/manifest.uuid index d68eba3a8c..3ef30be8bc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8514a4feb2a86e93c4251c491d394e861bb65edb \ No newline at end of file +dcbc983355d3207615b52b0724405a024a1a5955 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index ab6490fb9d..4a65af72c1 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.189 2005/02/15 02:54:15 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.190 2005/02/15 03:38:06 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1137,6 +1137,7 @@ static int pager_reload_cache(Pager *pPager){ ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ + assert( pPager->state>=PAGER_EXCLUSIVE ); return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage); } @@ -1256,7 +1257,8 @@ static int pager_playback(Pager *pPager){ /* If this is the first header read from the journal, truncate the ** database file back to it's original size. */ - if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ + if( pPager->state>=PAGER_EXCLUSIVE && + pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg ); rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ @@ -1354,10 +1356,11 @@ static int pager_stmt_playback(Pager *pPager){ hdrOff = szJ; } - /* Truncate the database back to its original size. */ - rc = pager_truncate(pPager, pPager->stmtSize); + if( pPager->state>=PAGER_EXCLUSIVE ){ + rc = pager_truncate(pPager, pPager->stmtSize); + } pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. @@ -1804,6 +1807,37 @@ static void memoryTruncate(Pager *pPager){ #define memoryTruncate(p) #endif +/* +** Try to obtain a lock on a file. Invoke the busy callback if the lock +** is currently not available. Repeate until the busy callback returns +** false or until the lock succeeds. +** +** Return SQLITE_OK on success and an error code if we cannot obtain +** the lock. +*/ +static int pager_wait_on_lock(Pager *pPager, int locktype){ + int rc; + assert( PAGER_SHARED==SHARED_LOCK ); + assert( PAGER_RESERVED==RESERVED_LOCK ); + assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); + if( pPager->state>=locktype ){ + rc = SQLITE_OK; + }else{ + int busy = 1; + do { + rc = sqlite3OsLock(&pPager->fd, locktype); + }while( rc==SQLITE_BUSY && + pPager->pBusyHandler && + pPager->pBusyHandler->xFunc && + pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) + ); + if( rc==SQLITE_OK ){ + pPager->state = locktype; + } + } + return rc; +} + /* ** Truncate the file to the number of pages specified. */ @@ -1826,6 +1860,13 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ if( rc!=SQLITE_OK ){ return rc; } + + /* Get an exclusive lock on the database before truncating. */ + rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + return rc; + } + rc = pager_truncate(pPager, nPage); if( rc==SQLITE_OK ){ pPager->dbSize = nPage; @@ -2057,37 +2098,6 @@ static int syncJournal(Pager *pPager){ return rc; } -/* -** Try to obtain a lock on a file. Invoke the busy callback if the lock -** is currently not available. Repeate until the busy callback returns -** false or until the lock succeeds. -** -** Return SQLITE_OK on success and an error code if we cannot obtain -** the lock. -*/ -static int pager_wait_on_lock(Pager *pPager, int locktype){ - int rc; - assert( PAGER_SHARED==SHARED_LOCK ); - assert( PAGER_RESERVED==RESERVED_LOCK ); - assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); - if( pPager->state>=locktype ){ - rc = SQLITE_OK; - }else{ - int busy = 1; - do { - rc = sqlite3OsLock(&pPager->fd, locktype); - }while( rc==SQLITE_BUSY && - pPager->pBusyHandler && - pPager->pBusyHandler->xFunc && - pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) - ); - if( rc==SQLITE_OK ){ - pPager->state = locktype; - } - } - return rc; -} - /* ** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** every one of those pages out to the database file and mark them all @@ -3072,13 +3082,11 @@ int sqlite3pager_rollback(Pager *pPager){ return pager_errcode(pPager); } if( pPager->state==PAGER_RESERVED ){ - int rc2, rc3; + int rc2; rc = pager_reload_cache(pPager); - rc2 = pager_truncate(pPager, pPager->origDbSize); - rc3 = pager_unwritelock(pPager); + rc2 = pager_unwritelock(pPager); if( rc==SQLITE_OK ){ rc = rc2; - if( rc3 ) rc = rc3; } }else{ rc = pager_playback(pPager);