Annotation of embedaddon/sqlite3/tool/showwal.c, revision 1.1.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>