drop support for "experimental" loose objects
In git v1.4.3, we introduced a new loose object format that encoded some object information outside of the zlib stream. Ultimately the format was dropped in v1.5.3, but we kept the reading side around to help people migrate objects. Each time we open a loose object, we use a heuristic to check whether it is in the normal loose format, or the experimental one. This heuristic is robust in the face of valid data, but it tends to treat corrupted or garbage data as an experimental object. With the regular format, we would notice quickly that zlib's crc does not check out and complain. With the experimental object, we are likely to extract a nonsensical object size and try to allocate a huge buffer, resulting in xmalloc calling "die". This latter behavior is much worse, for two reasons. One, git reports an allocation error when the real error is corruption. And two, the program dies unconditionally, so you cannot even run fsck (which would otherwise ignore the broken object and keep going). We could try to improve the heuristic to err on the side of normal objects in the face of corruption, but there is really little point. The experimental format is long-dead, and was never enabled by default to begin with. We can instead simply remove it. The only affected repository would be one that explicitly set core.legacyheaders in 2007, and then never repacked in the intervening 6 years. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
becb4336cb
commit
b039718d92
74
sha1_file.c
74
sha1_file.c
@ -1372,51 +1372,6 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
|
||||
return map;
|
||||
}
|
||||
|
||||
/*
|
||||
* There used to be a second loose object header format which
|
||||
* was meant to mimic the in-pack format, allowing for direct
|
||||
* copy of the object data. This format turned up not to be
|
||||
* really worth it and we no longer write loose objects in that
|
||||
* format.
|
||||
*/
|
||||
static int experimental_loose_object(unsigned char *map)
|
||||
{
|
||||
unsigned int word;
|
||||
|
||||
/*
|
||||
* We must determine if the buffer contains the standard
|
||||
* zlib-deflated stream or the experimental format based
|
||||
* on the in-pack object format. Compare the header byte
|
||||
* for each format:
|
||||
*
|
||||
* RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7
|
||||
* Experimental pack-based : Stttssss : ttt = 1,2,3,4
|
||||
*
|
||||
* If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be
|
||||
* in standard loose-object format, UNLESS it is a Git-pack
|
||||
* format object *exactly* 8 bytes in size when inflated.
|
||||
*
|
||||
* However, RFC1950 also specifies that the 1st 16-bit word
|
||||
* must be divisible by 31 - this checksum tells us our buffer
|
||||
* is in the standard format, giving a false positive only if
|
||||
* the 1st word of the Git-pack format object happens to be
|
||||
* divisible by 31, ie:
|
||||
* ((byte0 * 256) + byte1) % 31 = 0
|
||||
* => 0ttt10000www1000 % 31 = 0
|
||||
*
|
||||
* As it happens, this case can only arise for www=3 & ttt=1
|
||||
* - ie, a Commit object, which would have to be 8 bytes in
|
||||
* size. As no Commit can be that small, we find that the
|
||||
* combination of these two criteria (bitmask & checksum)
|
||||
* can always correctly determine the buffer format.
|
||||
*/
|
||||
word = (map[0] << 8) + map[1];
|
||||
if ((map[0] & 0x8F) == 0x08 && !(word % 31))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned long unpack_object_header_buffer(const unsigned char *buf,
|
||||
unsigned long len, enum object_type *type, unsigned long *sizep)
|
||||
{
|
||||
@ -1444,14 +1399,6 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
|
||||
|
||||
int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
|
||||
{
|
||||
unsigned long size, used;
|
||||
static const char valid_loose_object_type[8] = {
|
||||
0, /* OBJ_EXT */
|
||||
1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
|
||||
0, /* "delta" and others are invalid in a loose object */
|
||||
};
|
||||
enum object_type type;
|
||||
|
||||
/* Get the data stream */
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
stream->next_in = map;
|
||||
@ -1459,27 +1406,6 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma
|
||||
stream->next_out = buffer;
|
||||
stream->avail_out = bufsiz;
|
||||
|
||||
if (experimental_loose_object(map)) {
|
||||
/*
|
||||
* The old experimental format we no longer produce;
|
||||
* we can still read it.
|
||||
*/
|
||||
used = unpack_object_header_buffer(map, mapsize, &type, &size);
|
||||
if (!used || !valid_loose_object_type[type])
|
||||
return -1;
|
||||
map += used;
|
||||
mapsize -= used;
|
||||
|
||||
/* Set up the stream for the rest.. */
|
||||
stream->next_in = map;
|
||||
stream->avail_in = mapsize;
|
||||
git_inflate_init(stream);
|
||||
|
||||
/* And generate the fake traditional header */
|
||||
stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
|
||||
typename(type), size);
|
||||
return 0;
|
||||
}
|
||||
git_inflate_init(stream);
|
||||
return git_inflate(stream, 0);
|
||||
}
|
||||
|
@ -1,66 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2011 Roberto Tyley
|
||||
#
|
||||
|
||||
test_description='Correctly identify and parse loose object headers
|
||||
|
||||
There are two file formats for loose objects - the original standard
|
||||
format, and the experimental format introduced with Git v1.4.3, later
|
||||
deprecated with v1.5.3. Although Git no longer writes the
|
||||
experimental format, objects in both formats must be read, with the
|
||||
format for a given file being determined by the header.
|
||||
|
||||
Detecting file format based on header is not entirely trivial, not
|
||||
least because the first byte of a zlib-deflated stream will vary
|
||||
depending on how much memory was allocated for the deflation window
|
||||
buffer when the object was written out (for example 4KB on Android,
|
||||
rather that 32KB on a normal PC).
|
||||
|
||||
The loose objects used as test vectors have been generated with the
|
||||
following Git versions:
|
||||
|
||||
standard format: Git v1.7.4.1
|
||||
experimental format: Git v1.4.3 (legacyheaders=false)
|
||||
standard format, deflated with 4KB window size: Agit/JGit on Android
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
assert_blob_equals() {
|
||||
printf "%s" "$2" >expected &&
|
||||
git cat-file -p "$1" >actual &&
|
||||
test_cmp expected actual
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
cp -R "$TEST_DIRECTORY/t1013/objects" .git/ &&
|
||||
git --version
|
||||
'
|
||||
|
||||
test_expect_success 'read standard-format loose objects' '
|
||||
git cat-file tag 8d4e360d6c70fbd72411991c02a09c442cf7a9fa &&
|
||||
git cat-file commit 6baee0540ea990d9761a3eb9ab183003a71c3696 &&
|
||||
git ls-tree 7a37b887a73791d12d26c0d3e39568a8fb0fa6e8 &&
|
||||
assert_blob_equals "257cc5642cb1a054f08cc83f2d943e56fd3ebe99" "foo$LF"
|
||||
'
|
||||
|
||||
test_expect_success 'read experimental-format loose objects' '
|
||||
git cat-file tag 76e7fa9941f4d5f97f64fea65a2cba436bc79cbb &&
|
||||
git cat-file commit 7875c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 &&
|
||||
git ls-tree 95b1625de3ba8b2214d1e0d0591138aea733f64f &&
|
||||
assert_blob_equals "2e65efe2a145dda7ee51d1741299f848e5bf752e" "a" &&
|
||||
assert_blob_equals "9ae9e86b7bd6cb1472d9373702d8249973da0832" "ab" &&
|
||||
assert_blob_equals "85df50785d62d3b05ab03d9cbf7e4a0b49449730" "abcd" &&
|
||||
assert_blob_equals "1656f9233d999f61ef23ef390b9c71d75399f435" "abcdefgh" &&
|
||||
assert_blob_equals "1e72a6b2c4a577ab0338860fa9fe87f761fc9bbd" "abcdefghi" &&
|
||||
assert_blob_equals "70e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd" "abcdefghijklmnop" &&
|
||||
assert_blob_equals "bd15045f6ce8ff75747562173640456a394412c8" "abcdefghijklmnopqrstuvwx"
|
||||
'
|
||||
|
||||
test_expect_success 'read standard-format objects deflated with smaller window buffer' '
|
||||
git cat-file tag f816d5255855ac160652ee5253b06cd8ee14165a &&
|
||||
git cat-file tag 149cedb5c46929d18e0f118e9fa31927487af3b6
|
||||
'
|
||||
|
||||
test_done
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
Âxś%ĚA‚0@Ń}O1{cSZ(<28>ăνáĂthŞ”’ZŚÜŢ Ë˙?
¦m×6dµiťÉ9…¤Gĺ<47>h´Ř¨ÁZR'Q¶…<C2B6>RŚˇ<C59A>‚řłp‘ç‚ÓqL9âĎ=g¸§<C2B8>sIĐoopÎ˙”eĎ«_1»€ł¤$×ç*Si«ëNwpP•RBôűĹÁú
|
||||
ł‡[(đ®d-ŤřÁL9á
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
H<EFBFBD>ЬС<0E>0<0C>aЯ{<7B>о
IЛe&Цј*Ѕ<1D>GАп^И§љПЫDхв<D185>wU<77>в<EFBFBD>ЌSБ4Њ<19>ЦЊ<C2AD> ,fХ[№пVAлКЮќxШЧі6[wtGЇLuИ?<3F>ІВМкз@<40>"gь{<7B>+byО%M
|
Loading…
Reference in New Issue
Block a user