Fossil SCM
Update the fingerprint mechanism so that it if the revised hash algorithm fails, it retries using the legacy hash algorithm before reporting an error (and alarming users). The revised hash is always stored. The "test-fingerprint" command is updated to show both the old and the new hash algorithm and the fingerprint currently stored in the localdb.
Commit
36d3685833e1eb1a2802c0094c7e7bc7a588bb209328e6ab4b0259a163e96296
Parent
e5e094071d75c96…
1 file changed
+39
-19
M
src/db.c
+39
-19
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1735,11 +1735,11 @@ | ||
| 1735 | 1735 | char *z; |
| 1736 | 1736 | stash_rid_renumbering_event(); |
| 1737 | 1737 | vfile_rid_renumbering_event(0); |
| 1738 | 1738 | undo_reset(); |
| 1739 | 1739 | bisect_reset(); |
| 1740 | - z = db_fingerprint(0); | |
| 1740 | + z = db_fingerprint(0, 1); | |
| 1741 | 1741 | db_lset("fingerprint", z); |
| 1742 | 1742 | fossil_free(z); |
| 1743 | 1743 | fossil_print( |
| 1744 | 1744 | "WARNING: The repository database has been replaced by a clone.\n" |
| 1745 | 1745 | "Bisect history and undo have been lost.\n" |
| @@ -3933,18 +3933,30 @@ | ||
| 3933 | 3933 | ** the remaining fields of the RCVFROM table entry. MD5 is used for this |
| 3934 | 3934 | ** because it is 4x faster than SHA3 and 5x faster than SHA1, and there |
| 3935 | 3935 | ** are no security concerns - this is just a checksum, not a security |
| 3936 | 3936 | ** token. |
| 3937 | 3937 | */ |
| 3938 | -char *db_fingerprint(int rcvid){ | |
| 3938 | +char *db_fingerprint(int rcvid, int iVersion){ | |
| 3939 | 3939 | char *z = 0; |
| 3940 | 3940 | Blob sql = BLOB_INITIALIZER; |
| 3941 | 3941 | Stmt q; |
| 3942 | - blob_append_sql(&sql, | |
| 3943 | - "SELECT rcvid, quote(uid), datetime(mtime), quote(nonce), quote(ipaddr)" | |
| 3944 | - " FROM rcvfrom" | |
| 3945 | - ); | |
| 3942 | + if( iVersion==0 ){ | |
| 3943 | + /* The original fingerprint algorithm used "quote(mtime)". But this | |
| 3944 | + ** could give slightly different answers depending on how the floating- | |
| 3945 | + ** point hardware is configured. For example, it gave different | |
| 3946 | + ** answers on native Linux versus running under valgrind. */ | |
| 3947 | + blob_append_sql(&sql, | |
| 3948 | + "SELECT rcvid, quote(uid), quote(mtime), quote(nonce), quote(ipaddr)" | |
| 3949 | + " FROM rcvfrom" | |
| 3950 | + ); | |
| 3951 | + }else{ | |
| 3952 | + /* These days, we use "datetime(mtime)" for more consistent answers */ | |
| 3953 | + blob_append_sql(&sql, | |
| 3954 | + "SELECT rcvid, quote(uid), datetime(mtime), quote(nonce), quote(ipaddr)" | |
| 3955 | + " FROM rcvfrom" | |
| 3956 | + ); | |
| 3957 | + } | |
| 3946 | 3958 | if( rcvid<=0 ){ |
| 3947 | 3959 | blob_append_sql(&sql, " ORDER BY rcvid DESC LIMIT 1"); |
| 3948 | 3960 | }else{ |
| 3949 | 3961 | blob_append_sql(&sql, " WHERE rcvid=%d", rcvid); |
| 3950 | 3962 | } |
| @@ -3963,30 +3975,31 @@ | ||
| 3963 | 3975 | } |
| 3964 | 3976 | |
| 3965 | 3977 | /* |
| 3966 | 3978 | ** COMMAND: test-fingerprint |
| 3967 | 3979 | ** |
| 3968 | -** Usage: %fossil test-fingerprint ?RCVID? ?--check? | |
| 3980 | +** Usage: %fossil test-fingerprint ?RCVID? | |
| 3969 | 3981 | ** |
| 3970 | -** Display the repository fingerprint. Or if the --check option | |
| 3971 | -** is provided and this command is run from a checkout, invoke the | |
| 3972 | -** db_fingerprint_ok() method and print its result. | |
| 3982 | +** Display the repository fingerprint using the supplied RCVID or | |
| 3983 | +** using the latest RCVID if not is given on the command line. | |
| 3984 | +** Show both the legacy and the newer version of the fingerprint, | |
| 3985 | +** and the currently stored fingerprint if there is one. | |
| 3973 | 3986 | */ |
| 3974 | 3987 | void test_fingerprint(void){ |
| 3975 | 3988 | int rcvid = 0; |
| 3976 | - if( find_option("check",0,0)!=0 ){ | |
| 3977 | - db_must_be_within_tree(); | |
| 3978 | - fossil_print("db_fingerprint_ok() => %d\n", db_fingerprint_ok()); | |
| 3979 | - return; | |
| 3980 | - } | |
| 3981 | 3989 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0); |
| 3982 | 3990 | if( g.argc==3 ){ |
| 3983 | 3991 | rcvid = atoi(g.argv[2]); |
| 3984 | 3992 | }else if( g.argc!=2 ){ |
| 3985 | 3993 | fossil_fatal("wrong number of arguments"); |
| 3986 | 3994 | } |
| 3987 | - fossil_print("%z\n", db_fingerprint(rcvid)); | |
| 3995 | + fossil_print("legecy: %z\n", db_fingerprint(rcvid, 0)); | |
| 3996 | + fossil_print("version-1: %z\n", db_fingerprint(rcvid, 1)); | |
| 3997 | + if( g.localOpen ){ | |
| 3998 | + fossil_print("localdb: %z\n", db_lget("fingerprint","(none)")); | |
| 3999 | + fossil_print("db_fingerprint_ok(): %d\n", db_fingerprint_ok()); | |
| 4000 | + } | |
| 3988 | 4001 | } |
| 3989 | 4002 | |
| 3990 | 4003 | /* |
| 3991 | 4004 | ** Set the value of the "checkout" entry in the VVAR table. |
| 3992 | 4005 | ** |
| @@ -3996,11 +4009,11 @@ | ||
| 3996 | 4009 | char *z; |
| 3997 | 4010 | db_lset_int("checkout", rid); |
| 3998 | 4011 | z = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); |
| 3999 | 4012 | db_lset("checkout-hash", z); |
| 4000 | 4013 | fossil_free(z); |
| 4001 | - z = db_fingerprint(0); | |
| 4014 | + z = db_fingerprint(0, 1); | |
| 4002 | 4015 | db_lset("fingerprint", z); |
| 4003 | 4016 | fossil_free(z); |
| 4004 | 4017 | } |
| 4005 | 4018 | |
| 4006 | 4019 | /* |
| @@ -4018,11 +4031,18 @@ | ||
| 4018 | 4031 | if( zCkout==0 ){ |
| 4019 | 4032 | /* This is an older checkout that does not record a fingerprint. |
| 4020 | 4033 | ** We have to assume everything is ok */ |
| 4021 | 4034 | return 2; |
| 4022 | 4035 | } |
| 4023 | - zRepo = db_fingerprint(atoi(zCkout)); | |
| 4036 | + zRepo = db_fingerprint(atoi(zCkout), 1); | |
| 4024 | 4037 | rc = fossil_strcmp(zCkout,zRepo)==0; |
| 4025 | - fossil_free(zCkout); | |
| 4026 | 4038 | fossil_free(zRepo); |
| 4039 | + /* If the initial test fails, try again using the older fingerprint | |
| 4040 | + ** algorithm */ | |
| 4041 | + if( !rc ){ | |
| 4042 | + zRepo = db_fingerprint(atoi(zCkout), 0); | |
| 4043 | + rc = fossil_strcmp(zCkout,zRepo)==0; | |
| 4044 | + fossil_free(zRepo); | |
| 4045 | + } | |
| 4046 | + fossil_free(zCkout); | |
| 4027 | 4047 | return rc; |
| 4028 | 4048 | } |
| 4029 | 4049 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1735,11 +1735,11 @@ | |
| 1735 | char *z; |
| 1736 | stash_rid_renumbering_event(); |
| 1737 | vfile_rid_renumbering_event(0); |
| 1738 | undo_reset(); |
| 1739 | bisect_reset(); |
| 1740 | z = db_fingerprint(0); |
| 1741 | db_lset("fingerprint", z); |
| 1742 | fossil_free(z); |
| 1743 | fossil_print( |
| 1744 | "WARNING: The repository database has been replaced by a clone.\n" |
| 1745 | "Bisect history and undo have been lost.\n" |
| @@ -3933,18 +3933,30 @@ | |
| 3933 | ** the remaining fields of the RCVFROM table entry. MD5 is used for this |
| 3934 | ** because it is 4x faster than SHA3 and 5x faster than SHA1, and there |
| 3935 | ** are no security concerns - this is just a checksum, not a security |
| 3936 | ** token. |
| 3937 | */ |
| 3938 | char *db_fingerprint(int rcvid){ |
| 3939 | char *z = 0; |
| 3940 | Blob sql = BLOB_INITIALIZER; |
| 3941 | Stmt q; |
| 3942 | blob_append_sql(&sql, |
| 3943 | "SELECT rcvid, quote(uid), datetime(mtime), quote(nonce), quote(ipaddr)" |
| 3944 | " FROM rcvfrom" |
| 3945 | ); |
| 3946 | if( rcvid<=0 ){ |
| 3947 | blob_append_sql(&sql, " ORDER BY rcvid DESC LIMIT 1"); |
| 3948 | }else{ |
| 3949 | blob_append_sql(&sql, " WHERE rcvid=%d", rcvid); |
| 3950 | } |
| @@ -3963,30 +3975,31 @@ | |
| 3963 | } |
| 3964 | |
| 3965 | /* |
| 3966 | ** COMMAND: test-fingerprint |
| 3967 | ** |
| 3968 | ** Usage: %fossil test-fingerprint ?RCVID? ?--check? |
| 3969 | ** |
| 3970 | ** Display the repository fingerprint. Or if the --check option |
| 3971 | ** is provided and this command is run from a checkout, invoke the |
| 3972 | ** db_fingerprint_ok() method and print its result. |
| 3973 | */ |
| 3974 | void test_fingerprint(void){ |
| 3975 | int rcvid = 0; |
| 3976 | if( find_option("check",0,0)!=0 ){ |
| 3977 | db_must_be_within_tree(); |
| 3978 | fossil_print("db_fingerprint_ok() => %d\n", db_fingerprint_ok()); |
| 3979 | return; |
| 3980 | } |
| 3981 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0); |
| 3982 | if( g.argc==3 ){ |
| 3983 | rcvid = atoi(g.argv[2]); |
| 3984 | }else if( g.argc!=2 ){ |
| 3985 | fossil_fatal("wrong number of arguments"); |
| 3986 | } |
| 3987 | fossil_print("%z\n", db_fingerprint(rcvid)); |
| 3988 | } |
| 3989 | |
| 3990 | /* |
| 3991 | ** Set the value of the "checkout" entry in the VVAR table. |
| 3992 | ** |
| @@ -3996,11 +4009,11 @@ | |
| 3996 | char *z; |
| 3997 | db_lset_int("checkout", rid); |
| 3998 | z = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); |
| 3999 | db_lset("checkout-hash", z); |
| 4000 | fossil_free(z); |
| 4001 | z = db_fingerprint(0); |
| 4002 | db_lset("fingerprint", z); |
| 4003 | fossil_free(z); |
| 4004 | } |
| 4005 | |
| 4006 | /* |
| @@ -4018,11 +4031,18 @@ | |
| 4018 | if( zCkout==0 ){ |
| 4019 | /* This is an older checkout that does not record a fingerprint. |
| 4020 | ** We have to assume everything is ok */ |
| 4021 | return 2; |
| 4022 | } |
| 4023 | zRepo = db_fingerprint(atoi(zCkout)); |
| 4024 | rc = fossil_strcmp(zCkout,zRepo)==0; |
| 4025 | fossil_free(zCkout); |
| 4026 | fossil_free(zRepo); |
| 4027 | return rc; |
| 4028 | } |
| 4029 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1735,11 +1735,11 @@ | |
| 1735 | char *z; |
| 1736 | stash_rid_renumbering_event(); |
| 1737 | vfile_rid_renumbering_event(0); |
| 1738 | undo_reset(); |
| 1739 | bisect_reset(); |
| 1740 | z = db_fingerprint(0, 1); |
| 1741 | db_lset("fingerprint", z); |
| 1742 | fossil_free(z); |
| 1743 | fossil_print( |
| 1744 | "WARNING: The repository database has been replaced by a clone.\n" |
| 1745 | "Bisect history and undo have been lost.\n" |
| @@ -3933,18 +3933,30 @@ | |
| 3933 | ** the remaining fields of the RCVFROM table entry. MD5 is used for this |
| 3934 | ** because it is 4x faster than SHA3 and 5x faster than SHA1, and there |
| 3935 | ** are no security concerns - this is just a checksum, not a security |
| 3936 | ** token. |
| 3937 | */ |
| 3938 | char *db_fingerprint(int rcvid, int iVersion){ |
| 3939 | char *z = 0; |
| 3940 | Blob sql = BLOB_INITIALIZER; |
| 3941 | Stmt q; |
| 3942 | if( iVersion==0 ){ |
| 3943 | /* The original fingerprint algorithm used "quote(mtime)". But this |
| 3944 | ** could give slightly different answers depending on how the floating- |
| 3945 | ** point hardware is configured. For example, it gave different |
| 3946 | ** answers on native Linux versus running under valgrind. */ |
| 3947 | blob_append_sql(&sql, |
| 3948 | "SELECT rcvid, quote(uid), quote(mtime), quote(nonce), quote(ipaddr)" |
| 3949 | " FROM rcvfrom" |
| 3950 | ); |
| 3951 | }else{ |
| 3952 | /* These days, we use "datetime(mtime)" for more consistent answers */ |
| 3953 | blob_append_sql(&sql, |
| 3954 | "SELECT rcvid, quote(uid), datetime(mtime), quote(nonce), quote(ipaddr)" |
| 3955 | " FROM rcvfrom" |
| 3956 | ); |
| 3957 | } |
| 3958 | if( rcvid<=0 ){ |
| 3959 | blob_append_sql(&sql, " ORDER BY rcvid DESC LIMIT 1"); |
| 3960 | }else{ |
| 3961 | blob_append_sql(&sql, " WHERE rcvid=%d", rcvid); |
| 3962 | } |
| @@ -3963,30 +3975,31 @@ | |
| 3975 | } |
| 3976 | |
| 3977 | /* |
| 3978 | ** COMMAND: test-fingerprint |
| 3979 | ** |
| 3980 | ** Usage: %fossil test-fingerprint ?RCVID? |
| 3981 | ** |
| 3982 | ** Display the repository fingerprint using the supplied RCVID or |
| 3983 | ** using the latest RCVID if not is given on the command line. |
| 3984 | ** Show both the legacy and the newer version of the fingerprint, |
| 3985 | ** and the currently stored fingerprint if there is one. |
| 3986 | */ |
| 3987 | void test_fingerprint(void){ |
| 3988 | int rcvid = 0; |
| 3989 | db_find_and_open_repository(OPEN_ANY_SCHEMA,0); |
| 3990 | if( g.argc==3 ){ |
| 3991 | rcvid = atoi(g.argv[2]); |
| 3992 | }else if( g.argc!=2 ){ |
| 3993 | fossil_fatal("wrong number of arguments"); |
| 3994 | } |
| 3995 | fossil_print("legecy: %z\n", db_fingerprint(rcvid, 0)); |
| 3996 | fossil_print("version-1: %z\n", db_fingerprint(rcvid, 1)); |
| 3997 | if( g.localOpen ){ |
| 3998 | fossil_print("localdb: %z\n", db_lget("fingerprint","(none)")); |
| 3999 | fossil_print("db_fingerprint_ok(): %d\n", db_fingerprint_ok()); |
| 4000 | } |
| 4001 | } |
| 4002 | |
| 4003 | /* |
| 4004 | ** Set the value of the "checkout" entry in the VVAR table. |
| 4005 | ** |
| @@ -3996,11 +4009,11 @@ | |
| 4009 | char *z; |
| 4010 | db_lset_int("checkout", rid); |
| 4011 | z = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); |
| 4012 | db_lset("checkout-hash", z); |
| 4013 | fossil_free(z); |
| 4014 | z = db_fingerprint(0, 1); |
| 4015 | db_lset("fingerprint", z); |
| 4016 | fossil_free(z); |
| 4017 | } |
| 4018 | |
| 4019 | /* |
| @@ -4018,11 +4031,18 @@ | |
| 4031 | if( zCkout==0 ){ |
| 4032 | /* This is an older checkout that does not record a fingerprint. |
| 4033 | ** We have to assume everything is ok */ |
| 4034 | return 2; |
| 4035 | } |
| 4036 | zRepo = db_fingerprint(atoi(zCkout), 1); |
| 4037 | rc = fossil_strcmp(zCkout,zRepo)==0; |
| 4038 | fossil_free(zRepo); |
| 4039 | /* If the initial test fails, try again using the older fingerprint |
| 4040 | ** algorithm */ |
| 4041 | if( !rc ){ |
| 4042 | zRepo = db_fingerprint(atoi(zCkout), 0); |
| 4043 | rc = fossil_strcmp(zCkout,zRepo)==0; |
| 4044 | fossil_free(zRepo); |
| 4045 | } |
| 4046 | fossil_free(zCkout); |
| 4047 | return rc; |
| 4048 | } |
| 4049 |