diff options
author | Junio C Hamano <gitster@pobox.com> | 2023-05-15 13:59:04 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2023-05-15 13:59:04 -0700 |
commit | cd2b740ca95291b81b8e75000d2ee76b4f735877 (patch) | |
tree | 31bf2437d5454699cdd86e325046e95a476b5ccd | |
parent | 29b8a3f49d3c521431650b670fa2fbcd9ad571b3 (diff) | |
parent | cf9cd8b55c55794cc5eb38a157855f1ca2edd5ab (diff) | |
download | git-cd2b740ca95291b81b8e75000d2ee76b4f735877.tar.gz |
Merge branch 'ds/fsck-bitmap'
"git fsck" learned to detect bit-flip breakages in the reachability
bitmap files.
* ds/fsck-bitmap:
fsck: use local repository
fsck: verify checksums of all .bitmap files
-rw-r--r-- | builtin/fsck.c | 10 | ||||
-rw-r--r-- | pack-bitmap.c | 45 | ||||
-rw-r--r-- | pack-bitmap.h | 2 | ||||
-rwxr-xr-x | t/t5326-multi-pack-bitmaps.sh | 44 |
4 files changed, 98 insertions, 3 deletions
diff --git a/builtin/fsck.c b/builtin/fsck.c index 2cd461b84c..dcc165bf0c 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -27,6 +27,7 @@ #include "run-command.h" #include "worktree.h" #include "pack-revindex.h" +#include "pack-bitmap.h" #define REACHABLE 0x0001 #define SEEN 0x0002 @@ -57,6 +58,7 @@ static int name_objects; #define ERROR_COMMIT_GRAPH 020 #define ERROR_MULTI_PACK_INDEX 040 #define ERROR_PACK_REV_INDEX 0100 +#define ERROR_BITMAP 0200 static const char *describe_object(const struct object_id *oid) { @@ -867,20 +869,20 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress) int res = 0; if (show_progress) { - for (struct packed_git *p = get_all_packs(the_repository); p; p = p->next) + for (struct packed_git *p = get_all_packs(r); p; p = p->next) pack_count++; progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count); pack_count = 0; } - for (struct packed_git *p = get_all_packs(the_repository); p; p = p->next) { + for (struct packed_git *p = get_all_packs(r); p; p = p->next) { int load_error = load_pack_revindex_from_disk(p); if (load_error < 0) { error(_("unable to load rev-index for pack '%s'"), p->pack_name); res = ERROR_PACK_REV_INDEX; } else if (!load_error && - !load_pack_revindex(the_repository, p) && + !load_pack_revindex(r, p) && verify_pack_revindex(p)) { error(_("invalid rev-index for pack '%s'"), p->pack_name); res = ERROR_PACK_REV_INDEX; @@ -1056,6 +1058,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) } errors_found |= check_pack_rev_indexes(the_repository, show_progress); + if (verify_bitmap_files(the_repository)) + errors_found |= ERROR_BITMAP; check_connectivity(); diff --git a/pack-bitmap.c b/pack-bitmap.c index e0fad723bf..999f962602 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -2346,3 +2346,48 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname) return 0; } + +static int verify_bitmap_file(const char *name) +{ + struct stat st; + unsigned char *data; + int fd = git_open(name); + int res = 0; + + /* It is OK to not have the file. */ + if (fd < 0 || fstat(fd, &st)) { + if (fd >= 0) + close(fd); + return 0; + } + + data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (!hashfile_checksum_valid(data, st.st_size)) + res = error(_("bitmap file '%s' has invalid checksum"), + name); + + munmap(data, st.st_size); + return res; +} + +int verify_bitmap_files(struct repository *r) +{ + int res = 0; + + for (struct multi_pack_index *m = get_multi_pack_index(r); + m; m = m->next) { + char *midx_bitmap_name = midx_bitmap_filename(m); + res |= verify_bitmap_file(midx_bitmap_name); + free(midx_bitmap_name); + } + + for (struct packed_git *p = get_all_packs(r); + p; p = p->next) { + char *pack_bitmap_name = pack_bitmap_filename(p); + res |= verify_bitmap_file(pack_bitmap_name); + free(pack_bitmap_name); + } + + return res; +} diff --git a/pack-bitmap.h b/pack-bitmap.h index f0180b5276..84591f041b 100644 --- a/pack-bitmap.h +++ b/pack-bitmap.h @@ -111,4 +111,6 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git); const struct string_list *bitmap_preferred_tips(struct repository *r); int bitmap_is_preferred_refname(struct repository *r, const char *refname); +int verify_bitmap_files(struct repository *r); + #endif diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index 0882cbb6e4..f771c442d4 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -434,4 +434,48 @@ test_expect_success 'tagged commits are selected for bitmapping' ' ) ' +corrupt_file () { + chmod a+w "$1" && + printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc +} + +test_expect_success 'git fsck correctly identifies good and bad bitmaps' ' + git init valid && + test_when_finished rm -rf valid && + + test_commit_bulk 20 && + git repack -adbf && + + # Move pack-bitmap aside so it is not deleted + # in next repack. + packbitmap=$(ls .git/objects/pack/pack-*.bitmap) && + mv "$packbitmap" "$packbitmap.bak" && + + test_commit_bulk 10 && + git repack -b --write-midx && + midxbitmap=$(ls .git/objects/pack/multi-pack-index-*.bitmap) && + + # Copy MIDX bitmap to backup. Copy pack bitmap from backup. + cp "$midxbitmap" "$midxbitmap.bak" && + cp "$packbitmap.bak" "$packbitmap" && + + # fsck works at first + git fsck 2>err && + test_must_be_empty err && + + corrupt_file "$packbitmap" && + test_must_fail git fsck 2>err && + grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err && + + cp "$packbitmap.bak" "$packbitmap" && + corrupt_file "$midxbitmap" && + test_must_fail git fsck 2>err && + grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err && + + corrupt_file "$packbitmap" && + test_must_fail git fsck 2>err && + grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err && + grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err +' + test_done |