mirror of
https://github.com/git/git
synced 2024-10-02 14:45:21 +00:00
restore legacy behavior for read_sha1_file()
Since commit 8eca0b47ff
, 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>
This commit is contained in:
parent
25a1f374f0
commit
ac9391093f
3
cache.h
3
cache.h
|
@ -538,6 +538,9 @@ extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsig
|
||||||
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
|
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
|
||||||
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
|
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
|
||||||
|
|
||||||
|
/* just like read_sha1_file(), but non fatal in presence of bad objects */
|
||||||
|
extern void *read_object(const unsigned char *sha1, enum object_type *type, unsigned long *size);
|
||||||
|
|
||||||
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
|
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
|
||||||
|
|
||||||
extern int move_temp_to_file(const char *tmpfile, const char *filename);
|
extern int move_temp_to_file(const char *tmpfile, const char *filename);
|
||||||
|
|
30
sha1_file.c
30
sha1_file.c
|
@ -1006,6 +1006,18 @@ static void mark_bad_packed_object(struct packed_git *p,
|
||||||
p->num_bad_objects++;
|
p->num_bad_objects++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int has_packed_and_bad(const unsigned char *sha1)
|
||||||
|
{
|
||||||
|
struct packed_git *p;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (p = packed_git; p; p = p->next)
|
||||||
|
for (i = 0; i < p->num_bad_objects; i++)
|
||||||
|
if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
|
int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
|
||||||
{
|
{
|
||||||
unsigned char real_sha1[20];
|
unsigned char real_sha1[20];
|
||||||
|
@ -1647,7 +1659,7 @@ static void *unpack_delta_entry(struct packed_git *p,
|
||||||
sha1_to_hex(base_sha1), (uintmax_t)base_offset,
|
sha1_to_hex(base_sha1), (uintmax_t)base_offset,
|
||||||
p->pack_name);
|
p->pack_name);
|
||||||
mark_bad_packed_object(p, base_sha1);
|
mark_bad_packed_object(p, base_sha1);
|
||||||
base = read_sha1_file(base_sha1, type, &base_size);
|
base = read_object(base_sha1, type, &base_size);
|
||||||
if (!base)
|
if (!base)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1945,7 +1957,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
|
||||||
error("failed to read object %s at offset %"PRIuMAX" from %s",
|
error("failed to read object %s at offset %"PRIuMAX" from %s",
|
||||||
sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
|
sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
|
||||||
mark_bad_packed_object(e.p, sha1);
|
mark_bad_packed_object(e.p, sha1);
|
||||||
data = read_sha1_file(sha1, type, size);
|
data = read_object(sha1, type, size);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -2010,8 +2022,8 @@ int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
|
void *read_object(const unsigned char *sha1, enum object_type *type,
|
||||||
unsigned long *size)
|
unsigned long *size)
|
||||||
{
|
{
|
||||||
unsigned long mapsize;
|
unsigned long mapsize;
|
||||||
void *map, *buf;
|
void *map, *buf;
|
||||||
|
@ -2037,6 +2049,16 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
|
||||||
return read_packed_sha1(sha1, type, size);
|
return read_packed_sha1(sha1, type, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
|
||||||
|
unsigned long *size)
|
||||||
|
{
|
||||||
|
void *data = read_object(sha1, type, size);
|
||||||
|
/* legacy behavior is to die on corrupted objects */
|
||||||
|
if (!data && (has_loose_object(sha1) || has_packed_and_bad(sha1)))
|
||||||
|
die("object %s is corrupted", sha1_to_hex(sha1));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
void *read_object_with_reference(const unsigned char *sha1,
|
void *read_object_with_reference(const unsigned char *sha1,
|
||||||
const char *required_type_name,
|
const char *required_type_name,
|
||||||
unsigned long *size,
|
unsigned long *size,
|
||||||
|
|
60
t/t6011-rev-list-with-bad-commit.sh
Executable file
60
t/t6011-rev-list-with-bad-commit.sh
Executable file
|
@ -0,0 +1,60 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='git rev-list should notice bad commits'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
# Note:
|
||||||
|
# - compression level is set to zero to make "corruptions" easier to perform
|
||||||
|
# - reflog is disabled to avoid extra references which would twart the test
|
||||||
|
|
||||||
|
test_expect_success 'setup' \
|
||||||
|
'
|
||||||
|
git init &&
|
||||||
|
git config core.compression 0 &&
|
||||||
|
git config core.logallrefupdates false &&
|
||||||
|
echo "foo" > foo &&
|
||||||
|
git add foo &&
|
||||||
|
git commit -m "first commit" &&
|
||||||
|
echo "bar" > bar &&
|
||||||
|
git add bar &&
|
||||||
|
git commit -m "second commit" &&
|
||||||
|
echo "baz" > baz &&
|
||||||
|
git add baz &&
|
||||||
|
git commit -m "third commit" &&
|
||||||
|
echo "foo again" >> foo &&
|
||||||
|
git add foo &&
|
||||||
|
git commit -m "fourth commit" &&
|
||||||
|
git repack -a -f -d
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'verify number of revisions' \
|
||||||
|
'
|
||||||
|
revs=$(git rev-list --all | wc -l) &&
|
||||||
|
test $revs -eq 4 &&
|
||||||
|
first_commit=$(git rev-parse HEAD~3)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'corrupt second commit object' \
|
||||||
|
'
|
||||||
|
perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack &&
|
||||||
|
test_must_fail git fsck --full
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rev-list should fail' \
|
||||||
|
'
|
||||||
|
test_must_fail git rev-list --all > /dev/null
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git repack _MUST_ fail' \
|
||||||
|
'
|
||||||
|
test_must_fail git repack -a -f -d
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'first commit is still available' \
|
||||||
|
'
|
||||||
|
git log $first_commit
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
||||||
|
|
Loading…
Reference in a new issue