Annotation of embedaddon/sqlite3/tool/showwal.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** A utility for printing content from a write-ahead log file.
! 3: */
! 4: #include <stdio.h>
! 5: #include <ctype.h>
! 6: #include <sys/types.h>
! 7: #include <sys/stat.h>
! 8: #include <fcntl.h>
! 9: #include <unistd.h>
! 10: #include <stdlib.h>
! 11: #include <string.h>
! 12:
! 13:
! 14: static int pagesize = 1024; /* Size of a database page */
! 15: static int fd = -1; /* File descriptor for reading the WAL file */
! 16: static int mxFrame = 0; /* Last frame */
! 17: static int perLine = 16; /* HEX elements to print per line */
! 18:
! 19: typedef long long int i64; /* Datatype for 64-bit integers */
! 20:
! 21:
! 22: /*
! 23: ** Convert the var-int format into i64. Return the number of bytes
! 24: ** in the var-int. Write the var-int value into *pVal.
! 25: */
! 26: static int decodeVarint(const unsigned char *z, i64 *pVal){
! 27: i64 v = 0;
! 28: int i;
! 29: for(i=0; i<8; i++){
! 30: v = (v<<7) + (z[i]&0x7f);
! 31: if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
! 32: }
! 33: v = (v<<8) + (z[i]&0xff);
! 34: *pVal = v;
! 35: return 9;
! 36: }
! 37:
! 38: /* Report an out-of-memory error and die.
! 39: */
! 40: static void out_of_memory(void){
! 41: fprintf(stderr,"Out of memory...\n");
! 42: exit(1);
! 43: }
! 44:
! 45: /*
! 46: ** Read content from the file.
! 47: **
! 48: ** Space to hold the content is obtained from malloc() and needs to be
! 49: ** freed by the caller.
! 50: */
! 51: static unsigned char *getContent(int ofst, int nByte){
! 52: unsigned char *aData;
! 53: aData = malloc(nByte);
! 54: if( aData==0 ) out_of_memory();
! 55: lseek(fd, ofst, SEEK_SET);
! 56: read(fd, aData, nByte);
! 57: return aData;
! 58: }
! 59:
! 60: /*
! 61: ** Print a range of bytes as hex and as ascii.
! 62: */
! 63: static void print_byte_range(
! 64: int ofst, /* First byte in the range of bytes to print */
! 65: int nByte, /* Number of bytes to print */
! 66: unsigned char *aData, /* Content to print */
! 67: int printOfst /* Add this amount to the index on the left column */
! 68: ){
! 69: int i, j;
! 70: const char *zOfstFmt;
! 71:
! 72: if( ((printOfst+nByte)&~0xfff)==0 ){
! 73: zOfstFmt = " %03x: ";
! 74: }else if( ((printOfst+nByte)&~0xffff)==0 ){
! 75: zOfstFmt = " %04x: ";
! 76: }else if( ((printOfst+nByte)&~0xfffff)==0 ){
! 77: zOfstFmt = " %05x: ";
! 78: }else if( ((printOfst+nByte)&~0xffffff)==0 ){
! 79: zOfstFmt = " %06x: ";
! 80: }else{
! 81: zOfstFmt = " %08x: ";
! 82: }
! 83:
! 84: for(i=0; i<nByte; i += perLine){
! 85: fprintf(stdout, zOfstFmt, i+printOfst);
! 86: for(j=0; j<perLine; j++){
! 87: if( i+j>nByte ){
! 88: fprintf(stdout, " ");
! 89: }else{
! 90: fprintf(stdout,"%02x ", aData[i+j]);
! 91: }
! 92: }
! 93: for(j=0; j<perLine; j++){
! 94: if( i+j>nByte ){
! 95: fprintf(stdout, " ");
! 96: }else{
! 97: fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
! 98: }
! 99: }
! 100: fprintf(stdout,"\n");
! 101: }
! 102: }
! 103:
! 104: /* Print a line of decode output showing a 4-byte integer.
! 105: */
! 106: static void print_decode_line(
! 107: unsigned char *aData, /* Content being decoded */
! 108: int ofst, int nByte, /* Start and size of decode */
! 109: int asHex, /* If true, output value as hex */
! 110: const char *zMsg /* Message to append */
! 111: ){
! 112: int i, j;
! 113: int val = aData[ofst];
! 114: char zBuf[100];
! 115: sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
! 116: i = strlen(zBuf);
! 117: for(j=1; j<4; j++){
! 118: if( j>=nByte ){
! 119: sprintf(&zBuf[i], " ");
! 120: }else{
! 121: sprintf(&zBuf[i], " %02x", aData[ofst+j]);
! 122: val = val*256 + aData[ofst+j];
! 123: }
! 124: i += strlen(&zBuf[i]);
! 125: }
! 126: if( asHex ){
! 127: sprintf(&zBuf[i], " 0x%08x", val);
! 128: }else{
! 129: sprintf(&zBuf[i], " %9d", val);
! 130: }
! 131: printf("%s %s\n", zBuf, zMsg);
! 132: }
! 133:
! 134: /*
! 135: ** Print an entire page of content as hex
! 136: */
! 137: static void print_frame(int iFrame){
! 138: int iStart;
! 139: unsigned char *aData;
! 140: iStart = 32 + (iFrame-1)*(pagesize+24);
! 141: fprintf(stdout, "Frame %d: (offsets 0x%x..0x%x)\n",
! 142: iFrame, iStart, iStart+pagesize+24);
! 143: aData = getContent(iStart, pagesize+24);
! 144: print_decode_line(aData, 0, 4, 0, "Page number");
! 145: print_decode_line(aData, 4, 4, 0, "DB size, or 0 for non-commit");
! 146: print_decode_line(aData, 8, 4, 1, "Salt-1");
! 147: print_decode_line(aData,12, 4, 1, "Salt-2");
! 148: print_decode_line(aData,16, 4, 1, "Checksum-1");
! 149: print_decode_line(aData,20, 4, 1, "Checksum-2");
! 150: print_byte_range(iStart+24, pagesize, aData+24, 0);
! 151: free(aData);
! 152: }
! 153:
! 154: /*
! 155: ** extract a 32-bit big-endian integer
! 156: */
! 157: static unsigned int getInt32(const unsigned char *a){
! 158: unsigned int x = (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
! 159: return x;
! 160: }
! 161:
! 162: /*
! 163: ** Print an entire page of content as hex
! 164: */
! 165: static void print_oneline_frame(int iFrame){
! 166: int iStart;
! 167: unsigned char *aData;
! 168: iStart = 32 + (iFrame-1)*(pagesize+24);
! 169: aData = getContent(iStart, 24);
! 170: fprintf(stdout, "Frame %4d: %6d %6d 0x%08x 0x%08x 0x%08x 0x%08x\n",
! 171: iFrame,
! 172: getInt32(aData),
! 173: getInt32(aData+4),
! 174: getInt32(aData+8),
! 175: getInt32(aData+12),
! 176: getInt32(aData+16),
! 177: getInt32(aData+20)
! 178: );
! 179: free(aData);
! 180: }
! 181:
! 182: /*
! 183: ** Decode the WAL header.
! 184: */
! 185: static void print_wal_header(void){
! 186: unsigned char *aData;
! 187: aData = getContent(0, 32);
! 188: printf("WAL Header:\n");
! 189: print_decode_line(aData, 0, 4,1,"Magic. 0x377f0682 (le) or 0x377f0683 (be)");
! 190: print_decode_line(aData, 4, 4, 0, "File format");
! 191: print_decode_line(aData, 8, 4, 0, "Database page size");
! 192: print_decode_line(aData, 12,4, 0, "Checkpoint sequence number");
! 193: print_decode_line(aData, 16,4, 1, "Salt-1");
! 194: print_decode_line(aData, 20,4, 1, "Salt-2");
! 195: print_decode_line(aData, 24,4, 1, "Checksum-1");
! 196: print_decode_line(aData, 28,4, 1, "Checksum-2");
! 197: free(aData);
! 198: }
! 199:
! 200: /*
! 201: ** Create a description for a single cell.
! 202: */
! 203: static int describeCell(unsigned char cType, unsigned char *a, char **pzDesc){
! 204: int i;
! 205: int nDesc = 0;
! 206: int n = 0;
! 207: int leftChild;
! 208: i64 nPayload;
! 209: i64 rowid;
! 210: static char zDesc[100];
! 211: i = 0;
! 212: if( cType<=5 ){
! 213: leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
! 214: a += 4;
! 215: n += 4;
! 216: sprintf(zDesc, "left-child: %d ", leftChild);
! 217: nDesc = strlen(zDesc);
! 218: }
! 219: if( cType!=5 ){
! 220: i = decodeVarint(a, &nPayload);
! 221: a += i;
! 222: n += i;
! 223: sprintf(&zDesc[nDesc], "sz: %lld ", nPayload);
! 224: nDesc += strlen(&zDesc[nDesc]);
! 225: }
! 226: if( cType==5 || cType==13 ){
! 227: i = decodeVarint(a, &rowid);
! 228: a += i;
! 229: n += i;
! 230: sprintf(&zDesc[nDesc], "rowid: %lld ", rowid);
! 231: nDesc += strlen(&zDesc[nDesc]);
! 232: }
! 233: *pzDesc = zDesc;
! 234: return n;
! 235: }
! 236:
! 237: /*
! 238: ** Decode a btree page
! 239: */
! 240: static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){
! 241: const char *zType = "unknown";
! 242: int nCell;
! 243: int i;
! 244: int iCellPtr;
! 245: switch( a[0] ){
! 246: case 2: zType = "index interior node"; break;
! 247: case 5: zType = "table interior node"; break;
! 248: case 10: zType = "index leaf"; break;
! 249: case 13: zType = "table leaf"; break;
! 250: }
! 251: printf("Decode of btree page %d:\n", pgno);
! 252: print_decode_line(a, 0, 1, 0, zType);
! 253: print_decode_line(a, 1, 2, 0, "Offset to first freeblock");
! 254: print_decode_line(a, 3, 2, 0, "Number of cells on this page");
! 255: nCell = a[3]*256 + a[4];
! 256: print_decode_line(a, 5, 2, 0, "Offset to cell content area");
! 257: print_decode_line(a, 7, 1, 0, "Fragmented byte count");
! 258: if( a[0]==2 || a[0]==5 ){
! 259: print_decode_line(a, 8, 4, 0, "Right child");
! 260: iCellPtr = 12;
! 261: }else{
! 262: iCellPtr = 8;
! 263: }
! 264: for(i=0; i<nCell; i++){
! 265: int cofst = iCellPtr + i*2;
! 266: char *zDesc;
! 267: cofst = a[cofst]*256 + a[cofst+1];
! 268: describeCell(a[0], &a[cofst-hdrSize], &zDesc);
! 269: printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
! 270: }
! 271: }
! 272:
! 273: int main(int argc, char **argv){
! 274: struct stat sbuf;
! 275: unsigned char zPgSz[2];
! 276: if( argc<2 ){
! 277: fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]);
! 278: exit(1);
! 279: }
! 280: fd = open(argv[1], O_RDONLY);
! 281: if( fd<0 ){
! 282: fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
! 283: exit(1);
! 284: }
! 285: zPgSz[0] = 0;
! 286: zPgSz[1] = 0;
! 287: lseek(fd, 10, SEEK_SET);
! 288: read(fd, zPgSz, 2);
! 289: pagesize = zPgSz[0]*256 + zPgSz[1];
! 290: if( pagesize==0 ) pagesize = 1024;
! 291: printf("Pagesize: %d\n", pagesize);
! 292: fstat(fd, &sbuf);
! 293: if( sbuf.st_size<32 ){
! 294: printf("file too small to be a WAL\n");
! 295: return 0;
! 296: }
! 297: mxFrame = (sbuf.st_size - 32)/(pagesize + 24);
! 298: printf("Available pages: 1..%d\n", mxFrame);
! 299: if( argc==2 ){
! 300: int i;
! 301: print_wal_header();
! 302: for(i=1; i<=mxFrame; i++) print_oneline_frame(i);
! 303: }else{
! 304: int i;
! 305: for(i=2; i<argc; i++){
! 306: int iStart, iEnd;
! 307: char *zLeft;
! 308: if( strcmp(argv[i], "header")==0 ){
! 309: print_wal_header();
! 310: continue;
! 311: }
! 312: if( !isdigit(argv[i][0]) ){
! 313: fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
! 314: continue;
! 315: }
! 316: iStart = strtol(argv[i], &zLeft, 0);
! 317: if( zLeft && strcmp(zLeft,"..end")==0 ){
! 318: iEnd = mxFrame;
! 319: }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
! 320: iEnd = strtol(&zLeft[2], 0, 0);
! 321: #if 0
! 322: }else if( zLeft && zLeft[0]=='b' ){
! 323: int ofst, nByte, hdrSize;
! 324: unsigned char *a;
! 325: if( iStart==1 ){
! 326: ofst = hdrSize = 100;
! 327: nByte = pagesize-100;
! 328: }else{
! 329: hdrSize = 0;
! 330: ofst = (iStart-1)*pagesize;
! 331: nByte = pagesize;
! 332: }
! 333: a = getContent(ofst, nByte);
! 334: decode_btree_page(a, iStart, hdrSize);
! 335: free(a);
! 336: continue;
! 337: #endif
! 338: }else{
! 339: iEnd = iStart;
! 340: }
! 341: if( iStart<1 || iEnd<iStart || iEnd>mxFrame ){
! 342: fprintf(stderr,
! 343: "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
! 344: mxFrame);
! 345: exit(1);
! 346: }
! 347: while( iStart<=iEnd ){
! 348: print_frame(iStart);
! 349: iStart++;
! 350: }
! 351: }
! 352: }
! 353: close(fd);
! 354: return 0;
! 355: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>