drh | 4e6861d | 2020-07-20 14:54:36 +0000 | [diff] [blame] | 1 | /* |
| 2 | ** Try to enlarge an SQLite database by appending many unused pages. |
| 3 | ** The resulting database will fail PRAGMA integrity_check due to the |
| 4 | ** appended unused pages, but it should work otherwise. |
| 5 | ** |
| 6 | ** Usage: |
| 7 | ** |
| 8 | ** enlargedb DATABASE N |
| 9 | ** |
| 10 | ** Adds N blank pages onto the end of DATABASE. N can be decimal |
| 11 | ** or hex. The total number of pages after adding must be no greater |
| 12 | ** than 4294967297 |
| 13 | */ |
| 14 | #include <stdio.h> |
| 15 | #include <string.h> |
| 16 | #include <stdlib.h> |
| 17 | |
| 18 | int main(int argc, char **argv){ |
| 19 | char *zEnd; |
| 20 | long long int toAppend; |
| 21 | long long int currentSz; |
| 22 | long long int newSz; |
| 23 | FILE *f; |
| 24 | size_t got; |
| 25 | int pgsz; |
| 26 | char zero = 0; |
| 27 | unsigned char buf[100]; |
| 28 | |
| 29 | if( argc!=3 ) goto usage_error; |
| 30 | toAppend = strtoll(argv[2], &zEnd, 0); |
| 31 | if( zEnd==argv[2] || zEnd[0] ) goto usage_error; |
| 32 | if( toAppend<1 ){ |
| 33 | fprintf(stderr, "N must be at least 1\n"); |
| 34 | exit(1); |
| 35 | } |
| 36 | f = fopen(argv[1], "r+b"); |
| 37 | if( f==0 ){ |
| 38 | fprintf(stderr, "cannot open \"%s\" for reading and writing\n", argv[1]); |
| 39 | exit(1); |
| 40 | } |
| 41 | got = fread(buf, 1, sizeof(buf), f); |
| 42 | if( got!=sizeof(buf) ) goto not_valid_db; |
| 43 | if( strcmp((char*)buf,"SQLite format 3")!=0 ) goto not_valid_db; |
| 44 | pgsz = (buf[16]<<8) + buf[17]; |
| 45 | if( pgsz==1 ) pgsz = 65536; |
| 46 | if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto not_valid_db; |
| 47 | currentSz = (buf[28]<<24) + (buf[29]<<16) + (buf[30]<<8) + buf[31]; |
| 48 | newSz = currentSz + toAppend; |
| 49 | if( newSz > 0xffffffff ) newSz = 0xffffffff; |
| 50 | buf[28] = (newSz>>24) & 0xff; |
| 51 | buf[29] = (newSz>>16) & 0xff; |
| 52 | buf[30] = (newSz>>8) & 0xff; |
| 53 | buf[31] = newSz & 0xff; |
| 54 | fseek(f, 28, SEEK_SET); |
| 55 | fwrite(&buf[28],4,1,f); |
| 56 | fseek(f, (long)(newSz*pgsz - 1), SEEK_SET); |
| 57 | fwrite(&zero,1,1,f); |
| 58 | fclose(f); |
| 59 | return 0; |
| 60 | |
| 61 | not_valid_db: |
| 62 | fprintf(stderr,"not a valid database: %s\n", argv[1]); |
| 63 | exit(1); |
| 64 | |
| 65 | usage_error: |
| 66 | fprintf(stderr,"Usage: %s DATABASE N\n", argv[0]); |
| 67 | exit(1); |
| 68 | } |