@matheusbsbs / matheus-bagliano / commits / ac9391093f
Fork 0

restore legacy behavior for read_sha1_file()

Since commit 8eca0b47ff1598a6d163df9358c0e0c9bd92d4c8, it is possible for read_sha1_file() to return NULL even with existing objects when they are corrupted. Previously a corrupted object would have terminated the program immediately, effectively making read_sha1_file() return NULL only when specified object is not found. Let's restore this behavior for all users of read_sha1_file() and provide a separate function with the ability to not terminate when bad objects are encountered. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nicolas Pitre committed Jul 14, 2008 at 21:46 UTC ac9391093f54370ff3f06470e24d78b536a12327
3 files changed +89 -4
cache.h
+3
@@ -538,6 +538,9 @@ extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsig
538 extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
539 extern int force_object_loose(const unsigned char *sha1, time_t mtime);
540
541 +/* just like read_sha1_file(), but non fatal in presence of bad objects */
542 +extern void *read_object(const unsigned char *sha1, enum object_type *type, unsigned long *size);
543 +
544 extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
545
546 extern int move_temp_to_file(const char *tmpfile, const char *filename);
sha1_file.c
+26 -4
@@ -1006,6 +1006,18 @@ static void mark_bad_packed_object(struct packed_git *p,
1006 p->num_bad_objects++;
1007 }
1008
1009 +static int has_packed_and_bad(const unsigned char *sha1)
1010 +{
1011 + struct packed_git *p;
1012 + unsigned i;
1013 +
1014 + for (p = packed_git; p; p = p->next)
1015 + for (i = 0; i < p->num_bad_objects; i++)
1016 + if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
1017 + return 1;
1018 + return 0;
1019 +}
1020 +
1021 int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
1022 {
1023 unsigned char real_sha1[20];
@@ -1647,7 +1659,7 @@ static void *unpack_delta_entry(struct packed_git *p,
1659 sha1_to_hex(base_sha1), (uintmax_t)base_offset,
1660 p->pack_name);
1661 mark_bad_packed_object(p, base_sha1);
1650 - base = read_sha1_file(base_sha1, type, &base_size);
1662 + base = read_object(base_sha1, type, &base_size);
1663 if (!base)
1664 return NULL;
1665 }
@@ -1945,7 +1957,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
1957 error("failed to read object %s at offset %"PRIuMAX" from %s",
1958 sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
1959 mark_bad_packed_object(e.p, sha1);
1948 - data = read_sha1_file(sha1, type, size);
1960 + data = read_object(sha1, type, size);
1961 }
1962 return data;
1963 }
@@ -2010,8 +2022,8 @@ int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
2022 return 0;
2023 }
2024
2013 -void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
2014 - unsigned long *size)
2025 +void *read_object(const unsigned char *sha1, enum object_type *type,
2026 + unsigned long *size)
2027 {
2028 unsigned long mapsize;
2029 void *map, *buf;
@@ -2037,6 +2049,16 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
2049 return read_packed_sha1(sha1, type, size);
2050 }
2051
2052 +void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
2053 + unsigned long *size)
2054 +{
2055 + void *data = read_object(sha1, type, size);
2056 + /* legacy behavior is to die on corrupted objects */
2057 + if (!data && (has_loose_object(sha1) || has_packed_and_bad(sha1)))
2058 + die("object %s is corrupted", sha1_to_hex(sha1));
2059 + return data;
2060 +}
2061 +
2062 void *read_object_with_reference(const unsigned char *sha1,
2063 const char *required_type_name,
2064 unsigned long *size,
t/t6011-rev-list-with-bad-commit.sh new
+60
@@ -0,0 +1,60 @@
1 +#!/bin/sh
2 +
3 +test_description='git rev-list should notice bad commits'
4 +
5 +. ./test-lib.sh
6 +
7 +# Note:
8 +# - compression level is set to zero to make "corruptions" easier to perform
9 +# - reflog is disabled to avoid extra references which would twart the test
10 +
11 +test_expect_success 'setup' \
12 + '
13 + git init &&
14 + git config core.compression 0 &&
15 + git config core.logallrefupdates false &&
16 + echo "foo" > foo &&
17 + git add foo &&
18 + git commit -m "first commit" &&
19 + echo "bar" > bar &&
20 + git add bar &&
21 + git commit -m "second commit" &&
22 + echo "baz" > baz &&
23 + git add baz &&
24 + git commit -m "third commit" &&
25 + echo "foo again" >> foo &&
26 + git add foo &&
27 + git commit -m "fourth commit" &&
28 + git repack -a -f -d
29 + '
30 +
31 +test_expect_success 'verify number of revisions' \
32 + '
33 + revs=$(git rev-list --all | wc -l) &&
34 + test $revs -eq 4 &&
35 + first_commit=$(git rev-parse HEAD~3)
36 + '
37 +
38 +test_expect_success 'corrupt second commit object' \
39 + '
40 + perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
41 + test_must_fail git fsck --full
42 + '
43 +
44 +test_expect_success 'rev-list should fail' \
45 + '
46 + test_must_fail git rev-list --all > /dev/null
47 + '
48 +
49 +test_expect_success 'git repack _MUST_ fail' \
50 + '
51 + test_must_fail git repack -a -f -d
52 + '
53 +
54 +test_expect_success 'first commit is still available' \
55 + '
56 + git log $first_commit
57 + '
58 +
59 +test_done
60 +