From: drh Date: Mon, 27 Jan 2020 14:40:44 +0000 (+0000) Subject: Revise the layout of filenames in the Pager object so that it is unchanged X-Git-Tag: version-3.31.1~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=532b0d23fd80082a8706ec683b1c7afed26ee6c4;p=thirdparty%2Fsqlite.git Revise the layout of filenames in the Pager object so that it is unchanged from prior versions. It turns out that some important 3rd-party software does questionable pointer manipulations on those filenames that depend on that legacy layout. Technical this is a misuse of SQLite by the 3rd-party software, but we want to avoid unnecessary breakage. FossilOrigin-Name: 34ab760689fd493eda482e856047708d74e769a01cc90b69da456d79ffe39aea --- diff --git a/manifest b/manifest index b3af23952d..37b823b7ec 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypos\sin\sthe\ssqlite3ext.h\sheader\sfile\sthat\sprevent\ssome\snewer\sAPIs\sfrom\nbeing\saccessed\sfrom\sloadable\sextensions. -D 2020-01-23T15:00:18.610 +C Revise\sthe\slayout\sof\sfilenames\sin\sthe\sPager\sobject\sso\sthat\sit\sis\sunchanged\nfrom\sprior\sversions.\s\sIt\sturns\sout\sthat\ssome\simportant\s3rd-party\ssoftware\ndoes\squestionable\spointer\smanipulations\son\sthose\sfilenames\sthat\sdepend\son\nthat\slegacy\slayout.\s\sTechnical\sthis\sis\sa\smisuse\sof\sSQLite\sby\sthe\s3rd-party\nsoftware,\sbut\swe\swant\sto\savoid\sunnecessary\sbreakage. +D 2020-01-27T14:40:44.978 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 2fe4d7f67078a68650f16e4efe73207899e21702e6b9d2e8ad1894c76dcad352 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8cd803f1747c03a50b32fe87ebfb5851998d0cdafefe02737daa95e0616b42bb -F src/main.c 430db07f140a2455784b504af1a56fe49134a79dd479a203370490031708d48f +F src/main.c ffaa1308ee8ad7cf70bddc9a9fe2d2d66799e534b12ec876562d26a33a30d745 F src/malloc.c eaa4dc9602ce28b077f7de2eb275db2be270c5cc56d7fec5466301bd9b80e2f5 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -518,7 +518,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 F src/os_unix.c ad7640c04eed946052a3b12856362a773d0a717696707313037186df0e2b59f2 F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c 302a18da8b247881808cd65009e1ac7c8b6e5cefb22ed9a1c330ed47b73e94ab +F src/pager.c c0bca72aa3f7b1cf521a9f350fcf8e5975ebf98da7dbb03492be876b0f053781 F src/pager.h 71fe1d5016ec54d0cc5d344cd474e563450b438c59f535e8c1ec8a13b1373f14 F src/parse.y c8d2de64db469fd56e0fa24da46cd8ec8523eb98626567d2708df371b47fdc3f F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 @@ -1857,7 +1857,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8a6fe3066cf0599fcf2960e8fb3ae39e4e7a61ec81e8ec71d0b5910aee2c16f6 -R adbf99f7d511d2f7862e65bcc9604066 +P 14331989fcaf6591336290ed1548e9c90f0f153e27f456f4c30c966f9c23aa6e +R 883ff2472492f888f089aeac00d37048 U drh -Z 72d824d23352153c482aa4a2ca7c7d22 +Z 470802efe5cd145ed0af48cfd87c7792 diff --git a/manifest.uuid b/manifest.uuid index d36bb65850..837e4d4b16 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -14331989fcaf6591336290ed1548e9c90f0f153e27f456f4c30c966f9c23aa6e \ No newline at end of file +34ab760689fd493eda482e856047708d74e769a01cc90b69da456d79ffe39aea \ No newline at end of file diff --git a/src/main.c b/src/main.c index 903f187a9f..3983f083b2 100644 --- a/src/main.c +++ b/src/main.c @@ -4243,6 +4243,21 @@ int sqlite3_test_control(int op, ...){ return rc; } +/* +** The Pager stores the Database filename, Journal filename, and WAL filename +** consecutively in memory, in that order. The database filename is prefixed +** by four zero bytes. Locate the start of the database filename by searching +** backwards for the first byte following four consecutive zero bytes. +** +** This only works if the filename passed in was obtained from the Pager. +*/ +static const char *databaseName(const char *zName){ + while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ + zName--; + } + return zName; +} + /* ** This is a utility routine, useful to VFS implementations, that checks ** to see if a database file was a URI that contained a specific query @@ -4256,6 +4271,7 @@ int sqlite3_test_control(int op, ...){ */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ if( zFilename==0 || zParam==0 ) return 0; + zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] ){ int x = strcmp(zFilename, zParam); @@ -4271,6 +4287,7 @@ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ */ const char *sqlite3_uri_key(const char *zFilename, int N){ if( zFilename==0 || N<0 ) return 0; + zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] && (N--)>0 ){ zFilename += sqlite3Strlen30(zFilename) + 1; @@ -4304,25 +4321,6 @@ sqlite3_int64 sqlite3_uri_int64( return bDflt; } -/* -** The Pager stores the Journal filename, WAL filename, and Database filename -** consecutively in memory, in that order, with prefixes \000\001\000, -** \002\000, and \003\000, in that order. Thus the three names look like query -** parameters if you start at the first prefix. -** -** This routine backs up a filename to the start of the first prefix. -** -** This only works if the filenamed passed in was obtained from the Pager. -*/ -static const char *startOfNameList(const char *zName){ - while( zName[0]!='\001' || zName[1]!=0 ){ - zName -= 3; - while( zName[0]!='\000' ){ zName--; } - zName++; - } - return zName-1; -} - /* ** Translate a filename that was handed to a VFS routine into the corresponding ** database, journal, or WAL file. @@ -4334,14 +4332,26 @@ static const char *startOfNameList(const char *zName){ ** corruption. */ const char *sqlite3_filename_database(const char *zFilename){ + return databaseName(zFilename); return sqlite3_uri_parameter(zFilename - 3, "\003"); } const char *sqlite3_filename_journal(const char *zFilename){ - const char *z = sqlite3_uri_parameter(startOfNameList(zFilename), "\001"); - return ALWAYS(z) && z[0] ? z : 0; + zFilename = databaseName(zFilename); + zFilename += sqlite3Strlen30(zFilename) + 1; + while( zFilename[0] ){ + zFilename += sqlite3Strlen30(zFilename) + 1; + zFilename += sqlite3Strlen30(zFilename) + 1; + } + return zFilename + 1; } const char *sqlite3_filename_wal(const char *zFilename){ - return sqlite3_uri_parameter(startOfNameList(zFilename), "\002"); +#ifdef SQLITE_OMIT_WAL + return 0; +#else + zFilename = sqlite3_filename_journal(zFilename); + zFilename += sqlite3Strlen30(zFilename) + 1; + return zFilename; +#endif } /* diff --git a/src/pager.c b/src/pager.c index ae75aeb7cf..66cee1f186 100644 --- a/src/pager.c +++ b/src/pager.c @@ -4838,30 +4838,48 @@ int sqlite3PagerOpen( ** Database file handle (pVfs->szOsFile bytes) ** Sub-journal file handle (journalFileSize bytes) ** Main journal file handle (journalFileSize bytes) - ** \0\1\0 journal prefix (3 bytes) - ** Journal filename (nPathname+8+1 bytes) - ** \2\0 WAL prefix (2 bytes) - ** WAL filename (nPathname+4+1 bytes) - ** \3\0 database prefix (2 bytes) + ** \0\0\0\0 database prefix (4 bytes) ** Database file name (nPathname+1 bytes) ** URI query parameters (nUriByte bytes) - ** \0\0 terminator (2 bytes) + ** Journal filename (nPathname+8+1 bytes) + ** WAL filename (nPathname+4+1 bytes) + ** \0\0\0 terminator (3 bytes) + ** + ** Some 3rd-party software, over which we have no control, depends on + ** the specific order of the filenames and the \0 separators between them + ** so that it can (for example) find the database filename given the WAL + ** filename without using the sqlite3_filename_database() API. This is a + ** misuse of SQLite and a bug in the 3rd-party software, but the 3rd-party + ** software is in widespread use, so we try to avoid changing the filename + ** order and formatting if possible. In particular, the details of the + ** filename format expected by 3rd-party software should be as follows: + ** + ** - Main Database Path + ** - \0 + ** - Multiple URI components consisting of: + ** - Key + ** - \0 + ** - Value + ** - \0 + ** - \0 + ** - Journal Path + ** - \0 + ** - WAL Path (zWALName) + ** - \0 */ pPtr = (u8 *)sqlite3MallocZero( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ journalFileSize * 2 + /* The two journal files */ - 3 + /* Journal prefix */ + 4 + /* Database prefix */ + nPathname + 1 + /* database filename */ + nUriByte + /* query parameters */ nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL - 2 + /* WAL prefix */ nPathname + 4 + 1 + /* WAL filename */ #endif - 2 + /* Database prefix */ - nPathname + 1 + /* database filename */ - nUriByte + /* query parameters */ - 2 /* Terminator */ + 3 /* Terminator */ ); assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); if( !pPtr ){ @@ -4875,9 +4893,20 @@ int sqlite3PagerOpen( pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); + /* Fill in the Pager.zFilename and pPager.zQueryParam fields */ + pPtr += 4; /* Skip zero prefix */ + pPager->zFilename = (char*)pPtr; + if( nPathname>0 ){ + memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1; + if( zUri ){ + memcpy(pPtr, zUri, nUriByte); pPtr += nUriByte; + }else{ + pPtr++; + } + } + /* Fill in Pager.zJournal */ - pPtr[1] = '\001'; pPtr += 3; if( nPathname>0 ){ pPager->zJournal = (char*)pPtr; memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; @@ -4888,12 +4917,10 @@ int sqlite3PagerOpen( #endif }else{ pPager->zJournal = 0; - pPtr++; } #ifndef SQLITE_OMIT_WAL /* Fill in Pager.zWal */ - pPtr[0] = '\002'; pPtr[1] = 0; pPtr += 2; if( nPathname>0 ){ pPager->zWal = (char*)pPtr; memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; @@ -4904,21 +4931,9 @@ int sqlite3PagerOpen( #endif }else{ pPager->zWal = 0; - pPtr++; } #endif - /* Fill in the Pager.zFilename and pPager.zQueryParam fields */ - pPtr[0] = '\003'; pPtr[1] = 0; pPtr += 2; - pPager->zFilename = (char*)pPtr; - if( nPathname>0 ){ - memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1; - if( zUri ){ - memcpy(pPtr, zUri, nUriByte); /* pPtr += nUriByte; // not needed */ - } - /* Double-zero terminator implied by the sqlite3MallocZero */ - } - if( nPathname ) sqlite3DbFree(0, zPathname); pPager->pVfs = pVfs; pPager->vfsFlags = vfsFlags; @@ -7038,8 +7053,8 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ ** sqlite3_uri_parameter() and sqlite3_filename_database() and friends. */ const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){ - static const char zFake[] = { 0x00, 0x01, 0x00, 0x00, 0x00 }; - return (nullIfMemDb && pPager->memDb) ? &zFake[3] : pPager->zFilename; + static const char zFake[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename; } /*