1 /* 2 ** 2016 September 10 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** This file contains test code to delete an SQLite database and all 13 ** of its associated files. Associated files include: 14 ** 15 ** * The journal file. 16 ** * The wal file. 17 ** * The SQLITE_ENABLE_8_3_NAMES version of the db, journal or wal files. 18 ** * Files created by the test_multiplex.c module to extend any of the 19 ** above. 20 */ 21 22 #ifndef SQLITE_OS_WIN 23 # include <unistd.h> 24 # include <errno.h> 25 #endif 26 #include <string.h> 27 #include <assert.h> 28 #include "sqlite3.h" 29 30 /* The following #defines are copied from test_multiplex.c */ 31 #ifndef MX_CHUNK_NUMBER 32 # define MX_CHUNK_NUMBER 299 33 #endif 34 #ifndef SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 35 # define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400 36 #endif 37 #ifndef SQLITE_MULTIPLEX_WAL_8_3_OFFSET 38 # define SQLITE_MULTIPLEX_WAL_8_3_OFFSET 700 39 #endif 40 41 /* 42 ** This routine is a copy of (most of) the code from SQLite function 43 ** sqlite3FileSuffix3(). It modifies the filename in buffer z in the 44 ** same way as SQLite does when in 8.3 filenames mode. 45 */ 46 static void sqlite3Delete83Name(char *z){ 47 int i, sz; 48 sz = (int)strlen(z); 49 for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} 50 if( z[i]=='.' && (sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); 51 } 52 53 /* 54 ** zFile is a filename. Assuming no error occurs, if this file exists, 55 ** set *pbExists to true and unlink it. Or, if the file does not exist, 56 ** set *pbExists to false before returning. 57 ** 58 ** If an error occurs, non-zero is returned. Or, if no error occurs, zero. 59 */ 60 static int sqlite3DeleteUnlinkIfExists( 61 sqlite3_vfs *pVfs, 62 const char *zFile, 63 int *pbExists 64 ){ 65 int rc = SQLITE_ERROR; 66 #if SQLITE_OS_WIN 67 if( pVfs ){ 68 if( pbExists ) *pbExists = 1; 69 rc = pVfs->xDelete(pVfs, zFile, 0); 70 if( rc==SQLITE_IOERR_DELETE_NOENT ){ 71 if( pbExists ) *pbExists = 0; 72 rc = SQLITE_OK; 73 } 74 } 75 #else 76 assert( pVfs==0 ); 77 rc = access(zFile, F_OK); 78 if( rc ){ 79 if( errno==ENOENT ){ 80 if( pbExists ) *pbExists = 0; 81 rc = SQLITE_OK; 82 } 83 }else{ 84 if( pbExists ) *pbExists = 1; 85 rc = unlink(zFile); 86 } 87 #endif 88 return rc; 89 } 90 91 /* 92 ** Delete the database file identified by the string argument passed to this 93 ** function. The string must contain a filename, not an SQLite URI. 94 */ 95 SQLITE_API int sqlite3_delete_database( 96 const char *zFile /* File to delete */ 97 ){ 98 char *zBuf; /* Buffer to sprintf() filenames to */ 99 int nBuf; /* Size of buffer in bytes */ 100 int rc = 0; /* System error code */ 101 int i; /* Iterate through azFmt[] and aMFile[] */ 102 103 const char *azFmt[] = { "%s", "%s-journal", "%s-wal", "%s-shm" }; 104 105 struct MFile { 106 const char *zFmt; 107 int iOffset; 108 int b83; 109 } aMFile[] = { 110 { "%s%03d", 0, 0 }, 111 { "%s-journal%03d", 0, 0 }, 112 { "%s-wal%03d", 0, 0 }, 113 { "%s%03d", 0, 1 }, 114 { "%s-journal%03d", SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET, 1 }, 115 { "%s-wal%03d", SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 }, 116 }; 117 118 #ifdef SQLITE_OS_WIN 119 sqlite3_vfs *pVfs = sqlite3_vfs_find("win32"); 120 #else 121 sqlite3_vfs *pVfs = 0; 122 #endif 123 124 /* Allocate a buffer large enough for any of the files that need to be 125 ** deleted. */ 126 nBuf = (int)strlen(zFile) + 100; 127 zBuf = (char*)sqlite3_malloc(nBuf); 128 if( zBuf==0 ) return SQLITE_NOMEM; 129 130 /* Delete both the regular and 8.3 filenames versions of the database, 131 ** journal, wal and shm files. */ 132 for(i=0; rc==0 && i<sizeof(azFmt)/sizeof(azFmt[0]); i++){ 133 sqlite3_snprintf(nBuf, zBuf, azFmt[i], zFile); 134 rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0); 135 if( rc==0 && i!=0 ){ 136 sqlite3Delete83Name(zBuf); 137 rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0); 138 } 139 } 140 141 /* Delete any multiplexor files */ 142 for(i=0; rc==0 && i<sizeof(aMFile)/sizeof(aMFile[0]); i++){ 143 struct MFile *p = &aMFile[i]; 144 int iChunk; 145 for(iChunk=1; iChunk<=MX_CHUNK_NUMBER; iChunk++){ 146 int bExists; 147 sqlite3_snprintf(nBuf, zBuf, p->zFmt, zFile, iChunk+p->iOffset); 148 if( p->b83 ) sqlite3Delete83Name(zBuf); 149 rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, &bExists); 150 if( bExists==0 || rc!=0 ) break; 151 } 152 } 153 154 sqlite3_free(zBuf); 155 return (rc ? SQLITE_ERROR : SQLITE_OK); 156 } 157