Skip to content

Commit

Permalink
Merge branch 'jk/for-each-reflog-ent-reverse'
Browse files Browse the repository at this point in the history
The code that reads the reflog from the newer to the older entries
did not handle an entry that crosses a boundary of block it uses to
read them correctly.

* jk/for-each-reflog-ent-reverse:
  for_each_reflog_ent_reverse: turn leftover check into assertion
  for_each_reflog_ent_reverse: fix newlines on block boundaries
  • Loading branch information
Junio C Hamano committed Dec 22, 2014
2 parents 12b9f08 + 69216bf commit 6f3abb7
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 12 deletions.
49 changes: 37 additions & 12 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3413,29 +3413,54 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void

bp = find_beginning_of_line(buf, scanp);

if (*bp != '\n') {
strbuf_splice(&sb, 0, 0, buf, endp - buf);
if (pos)
break; /* need to fill another block */
scanp = buf - 1; /* leave loop */
} else {
if (*bp == '\n') {
/*
* (bp + 1) thru endp is the beginning of the
* current line we have in sb
* The newline is the end of the previous line,
* so we know we have complete line starting
* at (bp + 1). Prefix it onto any prior data
* we collected for the line and process it.
*/
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
ret = show_one_reflog_ent(&sb, fn, cb_data);
strbuf_reset(&sb);
if (ret)
break;
} else if (!pos) {
/*
* We are at the start of the buffer, and the
* start of the file; there is no previous
* line, and we have everything for this one.
* Process it, and we can end the loop.
*/
strbuf_splice(&sb, 0, 0, buf, endp - buf);
ret = show_one_reflog_ent(&sb, fn, cb_data);
strbuf_reset(&sb);
break;
}
ret = show_one_reflog_ent(&sb, fn, cb_data);
strbuf_reset(&sb);
if (ret)

if (bp == buf) {
/*
* We are at the start of the buffer, and there
* is more file to read backwards. Which means
* we are in the middle of a line. Note that we
* may get here even if *bp was a newline; that
* just means we are at the exact end of the
* previous line, rather than some spot in the
* middle.
*
* Save away what we have to be combined with
* the data from the next read.
*/
strbuf_splice(&sb, 0, 0, buf, endp - buf);
break;
}
}

}
if (!ret && sb.len)
ret = show_one_reflog_ent(&sb, fn, cb_data);
die("BUG: reverse reflog parser had leftover data");

fclose(logfp);
strbuf_release(&sb);
Expand Down
30 changes: 30 additions & 0 deletions t/t1410-reflog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,34 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' '
test_cmp expect actual
'

# Triggering the bug detected by this test requires a newline to fall
# exactly BUFSIZ-1 bytes from the end of the file. We don't know
# what that value is, since it's platform dependent. However, if
# we choose some value N, we also catch any D which divides N evenly
# (since we will read backwards in chunks of D). So we choose 8K,
# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
#
# Each line is 114 characters, so we need 75 to still have a few before the
# last 8K. The 89-character padding on the final entry lines up our
# newline exactly.
test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
git checkout -b reflogskip &&
z38=00000000000000000000000000000000000000 &&
ident="abc <xyz> 0000000001 +0000" &&
for i in $(test_seq 1 75); do
printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" &&
if test $i = 75; then
for j in $(test_seq 1 89); do
printf X
done
else
printf X
fi &&
printf "\n"
done >.git/logs/refs/heads/reflogskip &&
git rev-parse reflogskip@{73} >actual &&
echo ${z38}03 >expect &&
test_cmp expect actual
'

test_done

0 comments on commit 6f3abb7

Please sign in to comment.