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 */
sqlite3Delete83Name(char * z)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 */
sqlite3DeleteUnlinkIfExists(sqlite3_vfs * pVfs,const char * zFile,int * pbExists)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 */
sqlite3_delete_database(const char * zFile)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