Skip to content

Commit 771e7d5

Browse files
peffgitster
authored andcommitted
sha1_file: fix error message for alternate objects
When we fail to open a corrupt loose object, we report an error and mention the filename via sha1_file_name(). However, that function will always give us a path in the local repository, whereas the corrupt object may have come from an alternate. The result is a very misleading error message. Teach the open_sha1_file() and stat_sha1_file() helpers to pass back the path they found, so that we can report it correctly. Note that the pointers we return go to static storage (e.g., from sha1_file_name()), which is slightly dangerous. However, these helpers are static local helpers, and the names are used for immediately generating error messages. The simplicity is an acceptable tradeoff for the danger. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0b20f1a commit 771e7d5

File tree

2 files changed

+41
-15
lines changed

2 files changed

+41
-15
lines changed

sha1_file.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,39 +1613,54 @@ int git_open(const char *name)
16131613
}
16141614
}
16151615

1616-
static int stat_sha1_file(const unsigned char *sha1, struct stat *st)
1616+
/*
1617+
* Find "sha1" as a loose object in the local repository or in an alternate.
1618+
* Returns 0 on success, negative on failure.
1619+
*
1620+
* The "path" out-parameter will give the path of the object we found (if any).
1621+
* Note that it may point to static storage and is only valid until another
1622+
* call to sha1_file_name(), etc.
1623+
*/
1624+
static int stat_sha1_file(const unsigned char *sha1, struct stat *st,
1625+
const char **path)
16171626
{
16181627
struct alternate_object_database *alt;
16191628

1620-
if (!lstat(sha1_file_name(sha1), st))
1629+
*path = sha1_file_name(sha1);
1630+
if (!lstat(*path, st))
16211631
return 0;
16221632

16231633
prepare_alt_odb();
16241634
errno = ENOENT;
16251635
for (alt = alt_odb_list; alt; alt = alt->next) {
1626-
const char *path = alt_sha1_path(alt, sha1);
1627-
if (!lstat(path, st))
1636+
*path = alt_sha1_path(alt, sha1);
1637+
if (!lstat(*path, st))
16281638
return 0;
16291639
}
16301640

16311641
return -1;
16321642
}
16331643

1634-
static int open_sha1_file(const unsigned char *sha1)
1644+
/*
1645+
* Like stat_sha1_file(), but actually open the object and return the
1646+
* descriptor. See the caveats on the "path" parameter above.
1647+
*/
1648+
static int open_sha1_file(const unsigned char *sha1, const char **path)
16351649
{
16361650
int fd;
16371651
struct alternate_object_database *alt;
16381652
int most_interesting_errno;
16391653

1640-
fd = git_open(sha1_file_name(sha1));
1654+
*path = sha1_file_name(sha1);
1655+
fd = git_open(*path);
16411656
if (fd >= 0)
16421657
return fd;
16431658
most_interesting_errno = errno;
16441659

16451660
prepare_alt_odb();
16461661
for (alt = alt_odb_list; alt; alt = alt->next) {
1647-
const char *path = alt_sha1_path(alt, sha1);
1648-
fd = git_open(path);
1662+
*path = alt_sha1_path(alt, sha1);
1663+
fd = git_open(*path);
16491664
if (fd >= 0)
16501665
return fd;
16511666
if (most_interesting_errno == ENOENT)
@@ -1657,10 +1672,11 @@ static int open_sha1_file(const unsigned char *sha1)
16571672

16581673
void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
16591674
{
1675+
const char *path;
16601676
void *map;
16611677
int fd;
16621678

1663-
fd = open_sha1_file(sha1);
1679+
fd = open_sha1_file(sha1, &path);
16641680
map = NULL;
16651681
if (fd >= 0) {
16661682
struct stat st;
@@ -1669,7 +1685,7 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
16691685
*size = xsize_t(st.st_size);
16701686
if (!*size) {
16711687
/* mmap() is forbidden on empty files */
1672-
error("object file %s is empty", sha1_file_name(sha1));
1688+
error("object file %s is empty", path);
16731689
return NULL;
16741690
}
16751691
map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -2789,8 +2805,9 @@ static int sha1_loose_object_info(const unsigned char *sha1,
27892805
* object even exists.
27902806
*/
27912807
if (!oi->typep && !oi->typename && !oi->sizep) {
2808+
const char *path;
27922809
struct stat st;
2793-
if (stat_sha1_file(sha1, &st) < 0)
2810+
if (stat_sha1_file(sha1, &st, &path) < 0)
27942811
return -1;
27952812
if (oi->disk_sizep)
27962813
*oi->disk_sizep = st.st_size;
@@ -2986,6 +3003,8 @@ void *read_sha1_file_extended(const unsigned char *sha1,
29863003
{
29873004
void *data;
29883005
const struct packed_git *p;
3006+
const char *path;
3007+
struct stat st;
29893008
const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
29903009

29913010
errno = 0;
@@ -3001,12 +3020,9 @@ void *read_sha1_file_extended(const unsigned char *sha1,
30013020
die("replacement %s not found for %s",
30023021
sha1_to_hex(repl), sha1_to_hex(sha1));
30033022

3004-
if (has_loose_object(repl)) {
3005-
const char *path = sha1_file_name(sha1);
3006-
3023+
if (!stat_sha1_file(repl, &st, &path))
30073024
die("loose object %s (stored in %s) is corrupt",
30083025
sha1_to_hex(repl), path);
3009-
}
30103026

30113027
if ((p = has_packed_and_bad(repl)) != NULL)
30123028
die("packed object %s (stored in %s) is corrupt",

t/t1450-fsck.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,4 +550,14 @@ test_expect_success 'fsck --name-objects' '
550550
)
551551
'
552552

553+
test_expect_success 'alternate objects are correctly blamed' '
554+
test_when_finished "rm -rf alt.git .git/objects/info/alternates" &&
555+
git init --bare alt.git &&
556+
echo "../../alt.git/objects" >.git/objects/info/alternates &&
557+
mkdir alt.git/objects/12 &&
558+
>alt.git/objects/12/34567890123456789012345678901234567890 &&
559+
test_must_fail git fsck >out 2>&1 &&
560+
grep alt.git out
561+
'
562+
553563
test_done

0 commit comments

Comments
 (0)