Skip to content

Commit a881169

Browse files
mhaggergitster
authored andcommitted
read_packed_refs(): make parsing of the header line more robust
The old code parsed the traits in the `packed-refs` header by looking for the string " trait " (i.e., the name of the trait with a space on either side) in the header line. This is fragile, because if any other implementation of Git forgets to write the trailing space, the last trait would silently be ignored (and the error might never be noticed). So instead, use `string_list_split_in_place()` to split the traits into tokens then use `unsorted_string_list_has_string()` to look for the tokens we are interested in. This means that we can read the traits correctly even if the header line is missing a trailing space (or indeed, if it is missing the space after the colon, or if it has multiple spaces somewhere). However, older Git clients (and perhaps other Git implementations) still require the surrounding spaces, so we still have to output the header with a trailing space. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 36f2353 commit a881169

1 file changed

Lines changed: 15 additions & 6 deletions

File tree

refs/packed-backend.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,25 +257,30 @@ static struct packed_ref_cache *read_packed_refs(struct packed_ref_store *refs)
257257

258258
/* If the file has a header line, process it: */
259259
if (pos < eof && *pos == '#') {
260-
const char *traits;
260+
char *p;
261+
struct string_list traits = STRING_LIST_INIT_NODUP;
261262

262263
eol = memchr(pos, '\n', eof - pos);
263264
if (!eol)
264265
die_unterminated_line(refs->path, pos, eof - pos);
265266

266-
strbuf_add(&line, pos, eol + 1 - pos);
267+
strbuf_add(&line, pos, eol - pos);
267268

268-
if (!skip_prefix(line.buf, "# pack-refs with:", &traits))
269+
if (!skip_prefix(line.buf, "# pack-refs with:", (const char **)&p))
269270
die_invalid_line(refs->path, pos, eof - pos);
270271

271-
if (strstr(traits, " fully-peeled "))
272+
string_list_split_in_place(&traits, p, ' ', -1);
273+
274+
if (unsorted_string_list_has_string(&traits, "fully-peeled"))
272275
peeled = PEELED_FULLY;
273-
else if (strstr(traits, " peeled "))
276+
else if (unsorted_string_list_has_string(&traits, "peeled"))
274277
peeled = PEELED_TAGS;
275278
/* perhaps other traits later as well */
276279

277280
/* The "+ 1" is for the LF character. */
278281
pos = eol + 1;
282+
283+
string_list_clear(&traits, 0);
279284
strbuf_reset(&line);
280285
}
281286

@@ -610,7 +615,11 @@ int packed_refs_is_locked(struct ref_store *ref_store)
610615

611616
/*
612617
* The packed-refs header line that we write out. Perhaps other
613-
* traits will be added later. The trailing space is required.
618+
* traits will be added later.
619+
*
620+
* Note that earlier versions of Git used to parse these traits by
621+
* looking for " trait " in the line. For this reason, the space after
622+
* the colon and the trailing space are required.
614623
*/
615624
static const char PACKED_REFS_HEADER[] =
616625
"# pack-refs with: peeled fully-peeled \n";

0 commit comments

Comments
 (0)