OLD | NEW |
| (Empty) |
1 Index: src/btree.c | |
2 =================================================================== | |
3 --- src/btree.c 2009-09-09 06:45:19.000000000 -0700 | |
4 +++ src/btree.c 2009-09-14 18:17:53.000000000 -0700 | |
5 @@ -24,6 +24,12 @@ | |
6 static const char zMagicHeader[] = SQLITE_FILE_HEADER; | |
7 | |
8 /* | |
9 +** The header string that appears at the beginning of a SQLite | |
10 +** database which has been poisoned. | |
11 +*/ | |
12 +static const char zPoisonHeader[] = "SQLite poison 3"; | |
13 + | |
14 +/* | |
15 ** Set this global variable to 1 to enable tracing using the TRACE | |
16 ** macro. | |
17 */ | |
18 @@ -2337,6 +2343,7 @@ | |
19 if( rc ) return rc; | |
20 memcpy(data, zMagicHeader, sizeof(zMagicHeader)); | |
21 assert( sizeof(zMagicHeader)==16 ); | |
22 + assert( sizeof(zMagicHeader)==sizeof(zPoisonHeader) ); | |
23 put2byte(&data[16], pBt->pageSize); | |
24 data[18] = 1; | |
25 data[19] = 1; | |
26 @@ -7804,4 +7811,72 @@ | |
27 assert(!pCur->aOverflow); | |
28 pCur->isIncrblobHandle = 1; | |
29 } | |
30 + | |
31 +/* Poison the db so that other clients error out as quickly as | |
32 +** possible. | |
33 +*/ | |
34 +int sqlite3Poison(sqlite3 *db){ | |
35 + int rc; | |
36 + Btree *p; | |
37 + BtShared *pBt; | |
38 + unsigned char *pP1; | |
39 + | |
40 + if( db == NULL) return SQLITE_OK; | |
41 + | |
42 + /* Database 0 corrosponds to the main database. */ | |
43 + if( db->nDb<1 ) return SQLITE_OK; | |
44 + p = db->aDb[0].pBt; | |
45 + pBt = p->pBt; | |
46 + | |
47 + /* If in a transaction, roll it back. Committing any changes to a | |
48 + ** corrupt database may mess up evidence, we definitely don't want | |
49 + ** to allow poisoning to be rolled back, and the database is anyhow | |
50 + ** going bye-bye RSN. | |
51 + */ | |
52 + /* TODO(shess): Figure out if this might release the lock and let | |
53 + ** someone else get in there, which might deny us the lock a couple | |
54 + ** lines down. | |
55 + */ | |
56 + if( sqlite3BtreeIsInTrans(p) ) sqlite3BtreeRollback(p); | |
57 + | |
58 + /* Start an exclusive transaction. This will check the headers, so | |
59 + ** if someone else poisoned the database we should get an error. | |
60 + */ | |
61 + rc = sqlite3BtreeBeginTrans(p, 2); | |
62 + /* TODO(shess): Handle SQLITE_BUSY? */ | |
63 + if( rc!=SQLITE_OK ) return rc; | |
64 + | |
65 + /* Copied from sqlite3BtreeUpdateMeta(). Writing the old version of | |
66 + ** the page to the journal may be overkill, but it probably won't | |
67 + ** hurt. | |
68 + */ | |
69 + assert( pBt->inTrans==TRANS_WRITE ); | |
70 + assert( pBt->pPage1!=0 ); | |
71 + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); | |
72 + if( rc ) goto err; | |
73 + | |
74 + /* "SQLite format 3" changes to | |
75 + ** "SQLite poison 3". Be extra paranoid about making this change. | |
76 + */ | |
77 + if( sizeof(zMagicHeader)!=16 || | |
78 + sizeof(zPoisonHeader)!=sizeof(zMagicHeader) ){ | |
79 + rc = SQLITE_ERROR; | |
80 + goto err; | |
81 + } | |
82 + pP1 = pBt->pPage1->aData; | |
83 + if( memcmp(pP1, zMagicHeader, 16)!=0 ){ | |
84 + rc = SQLITE_CORRUPT; | |
85 + goto err; | |
86 + } | |
87 + memcpy(pP1, zPoisonHeader, 16); | |
88 + | |
89 + /* Push it to the database file. */ | |
90 + return sqlite3BtreeCommit(p); | |
91 + | |
92 + err: | |
93 + /* TODO(shess): What about errors, here? */ | |
94 + sqlite3BtreeRollback(p); | |
95 + return rc; | |
96 +} | |
97 + | |
98 #endif | |
OLD | NEW |