Fossil SCM
Add the test-integrity command for verifying repository integrity. Also add an "all" version of this command.
Commit
d56734549a258b3f70d5430801f8216683f93d8b
Parent
174d61b90a7e4fe…
2 files changed
+2
+42
+2
| --- src/allrepo.c | ||
| +++ src/allrepo.c | ||
| @@ -103,10 +103,12 @@ | ||
| 103 | 103 | zCmd = "pull -autourl -R"; |
| 104 | 104 | }else if( strncmp(zCmd, "rebuild", n)==0 ){ |
| 105 | 105 | zCmd = "rebuild"; |
| 106 | 106 | }else if( strncmp(zCmd, "sync", n)==0 ){ |
| 107 | 107 | zCmd = "sync -autourl -R"; |
| 108 | + }else if( strncmp(zCmd, "test-integrity", n)==0 ){ | |
| 109 | + zCmd = "test-integrity"; | |
| 108 | 110 | }else if( strncmp(zCmd, "ignore", n)==0 ){ |
| 109 | 111 | int j; |
| 110 | 112 | db_begin_transaction(); |
| 111 | 113 | for(j=3; j<g.argc; j++){ |
| 112 | 114 | db_multi_exec("DELETE FROM global_config WHERE name GLOB 'repo:%q'", |
| 113 | 115 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -103,10 +103,12 @@ | |
| 103 | zCmd = "pull -autourl -R"; |
| 104 | }else if( strncmp(zCmd, "rebuild", n)==0 ){ |
| 105 | zCmd = "rebuild"; |
| 106 | }else if( strncmp(zCmd, "sync", n)==0 ){ |
| 107 | zCmd = "sync -autourl -R"; |
| 108 | }else if( strncmp(zCmd, "ignore", n)==0 ){ |
| 109 | int j; |
| 110 | db_begin_transaction(); |
| 111 | for(j=3; j<g.argc; j++){ |
| 112 | db_multi_exec("DELETE FROM global_config WHERE name GLOB 'repo:%q'", |
| 113 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -103,10 +103,12 @@ | |
| 103 | zCmd = "pull -autourl -R"; |
| 104 | }else if( strncmp(zCmd, "rebuild", n)==0 ){ |
| 105 | zCmd = "rebuild"; |
| 106 | }else if( strncmp(zCmd, "sync", n)==0 ){ |
| 107 | zCmd = "sync -autourl -R"; |
| 108 | }else if( strncmp(zCmd, "test-integrity", n)==0 ){ |
| 109 | zCmd = "test-integrity"; |
| 110 | }else if( strncmp(zCmd, "ignore", n)==0 ){ |
| 111 | int j; |
| 112 | db_begin_transaction(); |
| 113 | for(j=3; j<g.argc; j++){ |
| 114 | db_multi_exec("DELETE FROM global_config WHERE name GLOB 'repo:%q'", |
| 115 |
+42
| --- src/content.c | ||
| +++ src/content.c | ||
| @@ -746,5 +746,47 @@ | ||
| 746 | 746 | void test_content_deltify_cmd(void){ |
| 747 | 747 | if( g.argc!=5 ) usage("RID SRCID FORCE"); |
| 748 | 748 | db_must_be_within_tree(); |
| 749 | 749 | content_deltify(atoi(g.argv[2]), atoi(g.argv[3]), atoi(g.argv[4])); |
| 750 | 750 | } |
| 751 | + | |
| 752 | +/* | |
| 753 | +** COMMAND: test-integrity | |
| 754 | +** | |
| 755 | +** Verify that all content can be extracted from the BLOB table correctly. | |
| 756 | +** If the BLOB table is correct, then the repository can always be | |
| 757 | +** successfully reconstructed using "fossil rebuild". | |
| 758 | +*/ | |
| 759 | +void test_integrity(void){ | |
| 760 | + Stmt q; | |
| 761 | + Blob content; | |
| 762 | + Blob cksum; | |
| 763 | + int n1 = 0; | |
| 764 | + int n2 = 0; | |
| 765 | + db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); | |
| 766 | + db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid"); | |
| 767 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 768 | + int rid = db_column_int(&q, 0); | |
| 769 | + const char *zUuid = db_column_text(&q, 1); | |
| 770 | + int size = db_column_int(&q, 2); | |
| 771 | + n1++; | |
| 772 | + if( size<0 ){ | |
| 773 | + printf("skip phantom %d %s\n", rid, zUuid); | |
| 774 | + continue; /* Ignore phantoms */ | |
| 775 | + } | |
| 776 | + content_get(rid, &content); | |
| 777 | + if( blob_size(&content)!=size ){ | |
| 778 | + fossil_fatal("size mismatch on blob rid=%d: %d vs %d", | |
| 779 | + rid, blob_size(&content), size); | |
| 780 | + } | |
| 781 | + sha1sum_blob(&content, &cksum); | |
| 782 | + if( strcmp(blob_str(&cksum), zUuid)!=0 ){ | |
| 783 | + fossil_fatal("checksum mismatch on blob rid=%d: %s vs %s", | |
| 784 | + rid, blob_str(&cksum), zUuid); | |
| 785 | + } | |
| 786 | + blob_reset(&cksum); | |
| 787 | + blob_reset(&content); | |
| 788 | + n2++; | |
| 789 | + } | |
| 790 | + db_finalize(&q); | |
| 791 | + printf("%d non-phantom blobs (out of %d total) verified\n", n2, n1); | |
| 792 | +} | |
| 751 | 793 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -746,5 +746,47 @@ | |
| 746 | void test_content_deltify_cmd(void){ |
| 747 | if( g.argc!=5 ) usage("RID SRCID FORCE"); |
| 748 | db_must_be_within_tree(); |
| 749 | content_deltify(atoi(g.argv[2]), atoi(g.argv[3]), atoi(g.argv[4])); |
| 750 | } |
| 751 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -746,5 +746,47 @@ | |
| 746 | void test_content_deltify_cmd(void){ |
| 747 | if( g.argc!=5 ) usage("RID SRCID FORCE"); |
| 748 | db_must_be_within_tree(); |
| 749 | content_deltify(atoi(g.argv[2]), atoi(g.argv[3]), atoi(g.argv[4])); |
| 750 | } |
| 751 | |
| 752 | /* |
| 753 | ** COMMAND: test-integrity |
| 754 | ** |
| 755 | ** Verify that all content can be extracted from the BLOB table correctly. |
| 756 | ** If the BLOB table is correct, then the repository can always be |
| 757 | ** successfully reconstructed using "fossil rebuild". |
| 758 | */ |
| 759 | void test_integrity(void){ |
| 760 | Stmt q; |
| 761 | Blob content; |
| 762 | Blob cksum; |
| 763 | int n1 = 0; |
| 764 | int n2 = 0; |
| 765 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 2); |
| 766 | db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid"); |
| 767 | while( db_step(&q)==SQLITE_ROW ){ |
| 768 | int rid = db_column_int(&q, 0); |
| 769 | const char *zUuid = db_column_text(&q, 1); |
| 770 | int size = db_column_int(&q, 2); |
| 771 | n1++; |
| 772 | if( size<0 ){ |
| 773 | printf("skip phantom %d %s\n", rid, zUuid); |
| 774 | continue; /* Ignore phantoms */ |
| 775 | } |
| 776 | content_get(rid, &content); |
| 777 | if( blob_size(&content)!=size ){ |
| 778 | fossil_fatal("size mismatch on blob rid=%d: %d vs %d", |
| 779 | rid, blob_size(&content), size); |
| 780 | } |
| 781 | sha1sum_blob(&content, &cksum); |
| 782 | if( strcmp(blob_str(&cksum), zUuid)!=0 ){ |
| 783 | fossil_fatal("checksum mismatch on blob rid=%d: %s vs %s", |
| 784 | rid, blob_str(&cksum), zUuid); |
| 785 | } |
| 786 | blob_reset(&cksum); |
| 787 | blob_reset(&content); |
| 788 | n2++; |
| 789 | } |
| 790 | db_finalize(&q); |
| 791 | printf("%d non-phantom blobs (out of %d total) verified\n", n2, n1); |
| 792 | } |
| 793 |