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 #if SQLITE_OS_WIN 23 # include <io.h> 24 # define F_OK 0 25 #else 26 # include <unistd.h> 27 #endif 28 #include <string.h> 29 #include <errno.h> 30 #include "sqlite3.h" 31 32 /* The following #defines are copied from test_multiplex.c */ 33 #ifndef MX_CHUNK_NUMBER 34 # define MX_CHUNK_NUMBER 299 35 #endif 36 #ifndef SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 37 # define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400 38 #endif 39 #ifndef SQLITE_MULTIPLEX_WAL_8_3_OFFSET 40 # define SQLITE_MULTIPLEX_WAL_8_3_OFFSET 700 41 #endif 42 43 /* 44 ** This routine is a copy of (most of) the code from SQLite function 45 ** sqlite3FileSuffix3(). It modifies the filename in buffer z in the 46 ** same way as SQLite does when in 8.3 filenames mode. 47 */ 48 static void sqlite3Delete83Name(char *z){ 49 int i, sz; 50 sz = strlen(z); 51 for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} 52 if( z[i]=='.' && (sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); 53 } 54 55 /* 56 ** zFile is a filename. Assuming no error occurs, if this file exists, 57 ** set *pbExists to true and unlink it. Or, if the file does not exist, 58 ** set *pbExists to false before returning. 59 ** 60 ** If an error occurs, the value of errno is returned. Or, if no error 61 ** occurs, zero is returned. 62 */ 63 static int sqlite3DeleteUnlinkIfExists(const char *zFile, int *pbExists){ 64 int rc; 65 rc = access(zFile, F_OK); 66 if( rc ){ 67 if( errno==ENOENT ){ 68 if( pbExists ) *pbExists = 0; 69 return 0; 70 } 71 return errno; 72 } 73 if( pbExists ) *pbExists = 1; 74 rc = unlink(zFile); 75 if( rc ) return errno; 76 return 0; 77 } 78 79 /* 80 ** Delete the database file identified by the string argument passed to this 81 ** function. The string must contain a filename, not an SQLite URI. 82 */ 83 int sqlite3_delete_database( 84 const char *zFile /* File to delete */ 85 ){ 86 char *zBuf; /* Buffer to sprintf() filenames to */ 87 int nBuf; /* Size of buffer in bytes */ 88 int rc = 0; /* System error code */ 89 int i; /* Iterate through azFmt[] and aMFile[] */ 90 91 const char *azFmt[] = { "%s", "%s-journal", "%s-wal", "%s-shm" }; 92 93 struct MFile { 94 const char *zFmt; 95 int iOffset; 96 int b83; 97 } aMFile[] = { 98 { "%s%03d", 0, 0 }, 99 { "%s-journal%03d", 0, 0 }, 100 { "%s-wal%03d", 0, 0 }, 101 { "%s%03d", 0, 1 }, 102 { "%s-journal%03d", SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET, 1 }, 103 { "%s-wal%03d", SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 }, 104 }; 105 106 /* Allocate a buffer large enough for any of the files that need to be 107 ** deleted. */ 108 nBuf = strlen(zFile) + 100; 109 zBuf = (char*)sqlite3_malloc(nBuf); 110 if( zBuf==0 ) return SQLITE_NOMEM; 111 112 /* Delete both the regular and 8.3 filenames versions of the database, 113 ** journal, wal and shm files. */ 114 for(i=0; rc==0 && i<sizeof(azFmt)/sizeof(azFmt[0]); i++){ 115 sqlite3_snprintf(nBuf, zBuf, azFmt[i], zFile); 116 rc = sqlite3DeleteUnlinkIfExists(zBuf, 0); 117 if( rc==0 && i!=0 ){ 118 sqlite3Delete83Name(zBuf); 119 rc = sqlite3DeleteUnlinkIfExists(zBuf, 0); 120 } 121 } 122 123 /* Delete any multiplexor files */ 124 for(i=0; rc==0 && i<sizeof(aMFile)/sizeof(aMFile[0]); i++){ 125 struct MFile *p = &aMFile[i]; 126 int iChunk; 127 for(iChunk=1; iChunk<=MX_CHUNK_NUMBER; iChunk++){ 128 int bExists; 129 sqlite3_snprintf(nBuf, zBuf, p->zFmt, zFile, iChunk+p->iOffset); 130 if( p->b83 ) sqlite3Delete83Name(zBuf); 131 rc = sqlite3DeleteUnlinkIfExists(zBuf, &bExists); 132 if( bExists==0 || rc!=0 ) break; 133 } 134 } 135 136 sqlite3_free(zBuf); 137 return (rc ? SQLITE_ERROR : SQLITE_OK); 138 } 139