summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--refs.c54
-rwxr-xr-x[-rw-r--r--]t/t1400-update-ref.sh64
2 files changed, 104 insertions, 14 deletions
diff --git a/refs.c b/refs.c
index ae9825dead..9d37a028c3 100644
--- a/refs.c
+++ b/refs.c
@@ -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