Merge branch 'ds/sha256-leftover-bits'

midx and commit-graph files now use the byte defined in their file
format specification for identifying the hash function used for
object names.

* ds/sha256-leftover-bits:
  multi-pack-index: use hash version byte
  commit-graph: use the "hash version" byte
  t/README: document GIT_TEST_DEFAULT_HASH
This commit is contained in:
Junio C Hamano
2020-08-19 16:14:52 -07:00
10 changed files with 146 additions and 21 deletions

View File

@ -42,8 +42,13 @@ HEADER:
1-byte version number: 1-byte version number:
Currently, the only valid version is 1. Currently, the only valid version is 1.
1-byte Hash Version (1 = SHA-1) 1-byte Hash Version
We infer the hash length (H) from this value. We infer the hash length (H) from this value:
1 => SHA-1
2 => SHA-256
If the hash type does not match the repository's hash algorithm, the
commit-graph file should be ignored with a warning presented to the
user.
1-byte number (C) of "chunks" 1-byte number (C) of "chunks"

View File

@ -279,7 +279,12 @@ HEADER:
Git only writes or recognizes version 1. Git only writes or recognizes version 1.
1-byte Object Id Version 1-byte Object Id Version
Git only writes or recognizes version 1 (SHA1). We infer the length of object IDs (OIDs) from this value:
1 => SHA-1
2 => SHA-256
If the hash type does not match the repository's hash algorithm,
the multi-pack-index file should be ignored with a warning
presented to the user.
1-byte number of "chunks" 1-byte number of "chunks"

View File

@ -179,7 +179,14 @@ static char *get_chain_filename(struct object_directory *odb)
static uint8_t oid_version(void) static uint8_t oid_version(void)
{ {
return 1; switch (hash_algo_by_ptr(the_hash_algo)) {
case GIT_HASH_SHA1:
return 1;
case GIT_HASH_SHA256:
return 2;
default:
die(_("invalid hash version"));
}
} }
static struct commit_graph *alloc_commit_graph(void) static struct commit_graph *alloc_commit_graph(void)

35
midx.c
View File

@ -17,7 +17,6 @@
#define MIDX_BYTE_HASH_VERSION 5 #define MIDX_BYTE_HASH_VERSION 5
#define MIDX_BYTE_NUM_CHUNKS 6 #define MIDX_BYTE_NUM_CHUNKS 6
#define MIDX_BYTE_NUM_PACKS 8 #define MIDX_BYTE_NUM_PACKS 8
#define MIDX_HASH_VERSION 1
#define MIDX_HEADER_SIZE 12 #define MIDX_HEADER_SIZE 12
#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz) #define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
@ -36,6 +35,18 @@
#define PACK_EXPIRED UINT_MAX #define PACK_EXPIRED UINT_MAX
static uint8_t oid_version(void)
{
switch (hash_algo_by_ptr(the_hash_algo)) {
case GIT_HASH_SHA1:
return 1;
case GIT_HASH_SHA256:
return 2;
default:
die(_("invalid hash version"));
}
}
static char *get_midx_filename(const char *object_dir) static char *get_midx_filename(const char *object_dir)
{ {
return xstrfmt("%s/pack/multi-pack-index", object_dir); return xstrfmt("%s/pack/multi-pack-index", object_dir);
@ -90,8 +101,11 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
m->version); m->version);
hash_version = m->data[MIDX_BYTE_HASH_VERSION]; hash_version = m->data[MIDX_BYTE_HASH_VERSION];
if (hash_version != MIDX_HASH_VERSION) if (hash_version != oid_version()) {
die(_("hash version %u does not match"), hash_version); error(_("multi-pack-index hash version %u does not match version %u"),
hash_version, oid_version());
goto cleanup_fail;
}
m->hash_len = the_hash_algo->rawsz; m->hash_len = the_hash_algo->rawsz;
m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS]; m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
@ -418,7 +432,7 @@ static size_t write_midx_header(struct hashfile *f,
hashwrite_be32(f, MIDX_SIGNATURE); hashwrite_be32(f, MIDX_SIGNATURE);
byte_values[0] = MIDX_VERSION; byte_values[0] = MIDX_VERSION;
byte_values[1] = MIDX_HASH_VERSION; byte_values[1] = oid_version();
byte_values[2] = num_chunks; byte_values[2] = num_chunks;
byte_values[3] = 0; /* unused */ byte_values[3] = 0; /* unused */
hashwrite(f, byte_values, sizeof(byte_values)); hashwrite(f, byte_values, sizeof(byte_values));
@ -1105,8 +1119,17 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
struct multi_pack_index *m = load_multi_pack_index(object_dir, 1); struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
verify_midx_error = 0; verify_midx_error = 0;
if (!m) if (!m) {
return 0; int result = 0;
struct stat sb;
char *filename = get_midx_filename(object_dir);
if (!stat(filename, &sb)) {
error(_("multi-pack-index file exists, but failed to parse"));
result = 1;
}
free(filename);
return result;
}
if (flags & MIDX_PROGRESS) if (flags & MIDX_PROGRESS)
progress = start_progress(_("Looking for referenced packfiles"), progress = start_progress(_("Looking for referenced packfiles"),

View File

@ -421,6 +421,10 @@ GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=<boolean>, when true (which is
the default when running tests), errors out when an abbreviated option the default when running tests), errors out when an abbreviated option
is used. is used.
GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to
use in the test scripts. Recognized values for <hash-algo> are "sha1"
and "sha256".
Naming Tests Naming Tests
------------ ------------

View File

@ -7,14 +7,18 @@
static int read_midx_file(const char *object_dir) static int read_midx_file(const char *object_dir)
{ {
uint32_t i; uint32_t i;
struct multi_pack_index *m = load_multi_pack_index(object_dir, 1); struct multi_pack_index *m;
setup_git_directory();
m = load_multi_pack_index(object_dir, 1);
if (!m) if (!m)
return 1; return 1;
printf("header: %08x %d %d %d\n", printf("header: %08x %d %d %d %d\n",
m->signature, m->signature,
m->version, m->version,
m->hash_len,
m->num_chunks, m->num_chunks,
m->num_packs); m->num_packs);

View File

@ -30,12 +30,17 @@ test_expect_success 'setup test - repo, commits, commit graph, log outputs' '
rm file_to_be_deleted && rm file_to_be_deleted &&
git add . && git add . &&
git commit -m "file removed" && git commit -m "file removed" &&
git commit-graph write --reachable --changed-paths git commit-graph write --reachable --changed-paths &&
test_oid_cache <<-EOF
oid_version sha1:1
oid_version sha256:2
EOF
' '
graph_read_expect () { graph_read_expect () {
NUM_CHUNKS=5 NUM_CHUNKS=5
cat >expect <<- EOF cat >expect <<- EOF
header: 43475048 1 1 $NUM_CHUNKS 0 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
num_commits: $1 num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata bloom_indexes bloom_data chunks: oid_fanout oid_lookup commit_metadata bloom_indexes bloom_data
EOF EOF

View File

@ -10,7 +10,12 @@ test_expect_success 'setup full repo' '
cd "$TRASH_DIRECTORY/full" && cd "$TRASH_DIRECTORY/full" &&
git init && git init &&
git config core.commitGraph true && git config core.commitGraph true &&
objdir=".git/objects" objdir=".git/objects" &&
test_oid_cache <<-EOF
oid_version sha1:1
oid_version sha256:2
EOF
' '
test_expect_success POSIXPERM 'tweak umask for modebit tests' ' test_expect_success POSIXPERM 'tweak umask for modebit tests' '
@ -77,7 +82,7 @@ graph_read_expect() {
NUM_CHUNKS=$((3 + $(echo "$2" | wc -w))) NUM_CHUNKS=$((3 + $(echo "$2" | wc -w)))
fi fi
cat >expect <<- EOF cat >expect <<- EOF
header: 43475048 1 1 $NUM_CHUNKS 0 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
num_commits: $1 num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
EOF EOF
@ -412,6 +417,35 @@ test_expect_success 'replace-objects invalidates commit-graph' '
) )
' '
test_expect_success 'warn on improper hash version' '
git init --object-format=sha1 sha1 &&
(
cd sha1 &&
test_commit 1 &&
git commit-graph write --reachable &&
mv .git/objects/info/commit-graph ../cg-sha1
) &&
git init --object-format=sha256 sha256 &&
(
cd sha256 &&
test_commit 1 &&
git commit-graph write --reachable &&
mv .git/objects/info/commit-graph ../cg-sha256
) &&
(
cd sha1 &&
mv ../cg-sha256 .git/objects/info/commit-graph &&
git log -1 2>err &&
test_i18ngrep "commit-graph hash version 2 does not match version 1" err
) &&
(
cd sha256 &&
mv ../cg-sha1 .git/objects/info/commit-graph &&
git log -1 2>err &&
test_i18ngrep "commit-graph hash version 1 does not match version 2" err
)
'
# the verify tests below expect the commit-graph to contain # the verify tests below expect the commit-graph to contain
# exactly the commits reachable from the commits/8 branch. # exactly the commits reachable from the commits/8 branch.
# If the file changes the set of commits in the list, then the # If the file changes the set of commits in the list, then the

View File

@ -5,6 +5,8 @@ test_description='multi-pack-indexes'
objdir=.git/objects objdir=.git/objects
HASH_LEN=$(test_oid rawsz)
midx_read_expect () { midx_read_expect () {
NUM_PACKS=$1 NUM_PACKS=$1
NUM_OBJECTS=$2 NUM_OBJECTS=$2
@ -13,7 +15,7 @@ midx_read_expect () {
EXTRA_CHUNKS="$5" EXTRA_CHUNKS="$5"
{ {
cat <<-EOF && cat <<-EOF &&
header: 4d494458 1 $NUM_CHUNKS $NUM_PACKS header: 4d494458 1 $HASH_LEN $NUM_CHUNKS $NUM_PACKS
chunks: pack-names oid-fanout oid-lookup object-offsets$EXTRA_CHUNKS chunks: pack-names oid-fanout oid-lookup object-offsets$EXTRA_CHUNKS
num_objects: $NUM_OBJECTS num_objects: $NUM_OBJECTS
packs: packs:
@ -46,7 +48,7 @@ test_expect_success "don't write midx with no packs" '
test_path_is_missing pack/multi-pack-index test_path_is_missing pack/multi-pack-index
' '
test_expect_success "Warn if a midx contains no oid" ' test_expect_success SHA1 'warn if a midx contains no oid' '
cp "$TEST_DIRECTORY"/t5319/no-objects.midx $objdir/pack/multi-pack-index && cp "$TEST_DIRECTORY"/t5319/no-objects.midx $objdir/pack/multi-pack-index &&
test_must_fail git multi-pack-index verify && test_must_fail git multi-pack-index verify &&
rm $objdir/pack/multi-pack-index rm $objdir/pack/multi-pack-index
@ -198,6 +200,40 @@ test_expect_success 'write midx with twelve packs' '
compare_results_with_midx "twelve packs" compare_results_with_midx "twelve packs"
test_expect_success 'warn on improper hash version' '
git init --object-format=sha1 sha1 &&
(
cd sha1 &&
git config core.multiPackIndex true &&
test_commit 1 &&
git repack -a &&
git multi-pack-index write &&
mv .git/objects/pack/multi-pack-index ../mpi-sha1
) &&
git init --object-format=sha256 sha256 &&
(
cd sha256 &&
git config core.multiPackIndex true &&
test_commit 1 &&
git repack -a &&
git multi-pack-index write &&
mv .git/objects/pack/multi-pack-index ../mpi-sha256
) &&
(
cd sha1 &&
mv ../mpi-sha256 .git/objects/pack/multi-pack-index &&
git log -1 2>err &&
test_i18ngrep "multi-pack-index hash version 2 does not match version 1" err
) &&
(
cd sha256 &&
mv ../mpi-sha1 .git/objects/pack/multi-pack-index &&
git log -1 2>err &&
test_i18ngrep "multi-pack-index hash version 1 does not match version 2" err
)
'
test_expect_success 'verify multi-pack-index success' ' test_expect_success 'verify multi-pack-index success' '
git multi-pack-index verify --object-dir=$objdir git multi-pack-index verify --object-dir=$objdir
' '
@ -243,7 +279,6 @@ test_expect_success 'verify bad signature' '
"multi-pack-index signature" "multi-pack-index signature"
' '
HASH_LEN=$(test_oid rawsz)
NUM_OBJECTS=74 NUM_OBJECTS=74
MIDX_BYTE_VERSION=4 MIDX_BYTE_VERSION=4
MIDX_BYTE_OID_VERSION=5 MIDX_BYTE_OID_VERSION=5
@ -272,7 +307,7 @@ test_expect_success 'verify bad version' '
' '
test_expect_success 'verify bad OID version' ' test_expect_success 'verify bad OID version' '
corrupt_midx_and_verify $MIDX_BYTE_OID_VERSION "\02" $objdir \ corrupt_midx_and_verify $MIDX_BYTE_OID_VERSION "\03" $objdir \
"hash version" "hash version"
' '

View File

@ -18,6 +18,9 @@ test_expect_success 'setup repo' '
base sha1:1376 base sha1:1376
base sha256:1496 base sha256:1496
oid_version sha1:1
oid_version sha256:2
EOM EOM
' '
@ -28,7 +31,7 @@ graph_read_expect() {
NUM_BASE=$2 NUM_BASE=$2
fi fi
cat >expect <<- EOF cat >expect <<- EOF
header: 43475048 1 1 3 $NUM_BASE header: 43475048 1 $(test_oid oid_version) 3 $NUM_BASE
num_commits: $1 num_commits: $1
chunks: oid_fanout oid_lookup commit_metadata chunks: oid_fanout oid_lookup commit_metadata
EOF EOF