diff options
-rw-r--r-- | refs.c | 54 | ||||
-rwxr-xr-x[-rw-r--r--] | t/t1400-update-ref.sh | 64 |
2 files changed, 104 insertions, 14 deletions
@@ -432,11 +432,12 @@ int write_ref_sha1(struct ref_lock *lock, int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1) { - const char *logfile, *logdata, *logend, *rec, *c; + const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec; char *tz_c; int logfd, tz; struct stat st; unsigned long date; + unsigned char logged_sha1[20]; logfile = git_path("logs/%s", ref); logfd = open(logfile, O_RDONLY, 0); @@ -448,32 +449,57 @@ int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1) logdata = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0); close(logfd); + lastrec = NULL; rec = logend = logdata + st.st_size; while (logdata < rec) { if (logdata < rec && *(rec-1) == '\n') rec--; - while (logdata < rec && *(rec-1) != '\n') + lastgt = NULL; + while (logdata < rec && *(rec-1) != '\n') { rec--; - c = rec; - while (c < logend && *c != '>' && *c != '\n') - c++; - if (c == logend || *c == '\n') + if (*rec == '>') + lastgt = rec; + } + if (!lastgt) die("Log %s is corrupt.", logfile); - date = strtoul(c + 1, NULL, 10); + date = strtoul(lastgt + 1, &tz_c, 10); if (date <= at_time) { - if (get_sha1_hex(rec + 41, sha1)) - die("Log %s is corrupt.", logfile); + if (lastrec) { + if (get_sha1_hex(lastrec, logged_sha1)) + die("Log %s is corrupt.", logfile); + if (get_sha1_hex(rec + 41, sha1)) + die("Log %s is corrupt.", logfile); + if (memcmp(logged_sha1, sha1, 20)) { + tz = strtoul(tz_c, NULL, 10); + fprintf(stderr, + "warning: Log %s has gap after %s.\n", + logfile, show_rfc2822_date(date, tz)); + } + } else if (date == at_time) { + if (get_sha1_hex(rec + 41, sha1)) + die("Log %s is corrupt.", logfile); + } else { + if (get_sha1_hex(rec + 41, logged_sha1)) + die("Log %s is corrupt.", logfile); + if (memcmp(logged_sha1, sha1, 20)) { + tz = strtoul(tz_c, NULL, 10); + fprintf(stderr, + "warning: Log %s unexpectedly ended on %s.\n", + logfile, show_rfc2822_date(date, tz)); + } + } munmap((void*)logdata, st.st_size); return 0; } + lastrec = rec; } - c = logdata; - while (c < logend && *c != '>' && *c != '\n') - c++; - if (c == logend || *c == '\n') + rec = logdata; + while (rec < logend && *rec != '>' && *rec != '\n') + rec++; + if (rec == logend || *rec == '\n') die("Log %s is corrupt.", logfile); - date = strtoul(c, &tz_c, 10); + date = strtoul(rec + 1, &tz_c, 10); tz = strtoul(tz_c, NULL, 10); if (get_sha1_hex(logdata, sha1)) die("Log %s is corrupt.", logfile); diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index f338c53774..7858d86b93 100644..100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -9,6 +9,10 @@ test_description='Test git-update-ref and basic ref logging' Z=0000000000000000000000000000000000000000 A=1111111111111111111111111111111111111111 B=2222222222222222222222222222222222222222 +C=3333333333333333333333333333333333333333 +D=4444444444444444444444444444444444444444 +E=5555555555555555555555555555555555555555 +F=6666666666666666666666666666666666666666 m=refs/heads/master test_expect_success \ @@ -109,4 +113,64 @@ test_expect_success \ 'diff expect .git/logs/$m' rm -f .git/$m .git/logs/$m expect +git-update-ref $m $D +cat >.git/logs/$m <<EOF +$C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500 +$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500 +$F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500 +$Z $E $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 -0500 +EOF + +ed="Thu, 26 May 2005 18:32:00 -0500" +gd="Thu, 26 May 2005 18:33:00 -0500" +ld="Thu, 26 May 2005 18:43:00 -0500" +test_expect_success \ + 'Query "master@May 25 2005" (before history)' \ + 'rm -f o e + git-rev-parse --verify "master@May 25 2005" >o 2>e && + test $C = $(cat o) && + test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"' +test_expect_success \ + "Query master@2005-05-25 (before history)" \ + 'rm -f o e + git-rev-parse --verify master@2005-05-25 >o 2>e && + test $C = $(cat o) && + echo test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"' +test_expect_success \ + 'Query "master@May 26 2005 23:31:59" (1 second before history)' \ + 'rm -f o e + git-rev-parse --verify "master@May 26 2005 23:31:59" >o 2>e && + test $C = $(cat o) && + test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"' +test_expect_success \ + 'Query "master@May 26 2005 23:32:00" (exactly history start)' \ + 'rm -f o e + git-rev-parse --verify "master@May 26 2005 23:32:00" >o 2>e && + test $A = $(cat o) && + test "" = "$(cat e)"' +test_expect_success \ + 'Query "master@2005-05-26 23:33:01" (middle of history with gap)' \ + 'rm -f o e + git-rev-parse --verify "master@2005-05-26 23:33:01" >o 2>e && + test $B = $(cat o) && + test "warning: Log .git/logs/$m has gap after $gd." = "$(cat e)"' +test_expect_success \ + 'Query "master@2005-05-26 23:33:01" (middle of history)' \ + 'rm -f o e + git-rev-parse --verify "master@2005-05-26 23:38:00" >o 2>e && + test $Z = $(cat o) && + test "" = "$(cat e)"' +test_expect_success \ + 'Query "master@2005-05-26 23:43:00" (exact end of history)' \ + 'rm -f o e + git-rev-parse --verify "master@2005-05-26 23:43:00" >o 2>e && + test $E = $(cat o) && + test "" = "$(cat e)"' +test_expect_success \ + 'Query "master@2005-05-28" (past end of history)' \ + 'rm -f o e + git-rev-parse --verify "master@2005-05-28" >o 2>e && + test $D = $(cat o) && + test "warning: Log .git/logs/$m unexpectedly ended on $ld." = "$(cat e)"' + test_done |