Skip to content

Commit d2458af

Browse files
committed
indexer: use a byte array for checksum
The index's checksum is not an object ID, so we should not use the `git_oid` type. Use a byte array for checksum calculation and storage. Deprecate the `git_indexer_hash` function. Callers should use the new `git_indexer_name` function which provides a unique packfile name.
1 parent 11ef76a commit d2458af

File tree

5 files changed

+53
-31
lines changed

5 files changed

+53
-31
lines changed

examples/index-pack.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv)
1717
git_indexer *idx;
1818
git_indexer_progress stats = {0, 0};
1919
int error;
20-
char hash[GIT_OID_HEXSZ + 1] = {0};
2120
int fd;
2221
ssize_t read_bytes;
2322
char buf[512];
@@ -61,8 +60,7 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv)
6160

6261
printf("\rIndexing %u of %u\n", stats.indexed_objects, stats.total_objects);
6362

64-
git_oid_fmt(hash, git_indexer_hash(idx));
65-
puts(hash);
63+
puts(git_indexer_name(idx));
6664

6765
cleanup:
6866
close(fd);

include/git2/indexer.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,30 @@ GIT_EXTERN(int) git_indexer_append(git_indexer *idx, const void *data, size_t si
129129
*/
130130
GIT_EXTERN(int) git_indexer_commit(git_indexer *idx, git_indexer_progress *stats);
131131

132+
#ifndef GIT_DEPRECATE_HARD
132133
/**
133134
* Get the packfile's hash
134135
*
135136
* A packfile's name is derived from the sorted hashing of all object
136137
* names. This is only correct after the index has been finalized.
137138
*
139+
* @deprecated use git_indexer_name
138140
* @param idx the indexer instance
139141
* @return the packfile's hash
140142
*/
141143
GIT_EXTERN(const git_oid *) git_indexer_hash(const git_indexer *idx);
144+
#endif
145+
146+
/**
147+
* Get the unique name for the resulting packfile.
148+
*
149+
* The packfile's name is derived from the packfile's content.
150+
* This is only correct after the index has been finalized.
151+
*
152+
* @param idx the indexer instance
153+
* @return a NUL terminated string for the packfile name
154+
*/
155+
GIT_EXTERN(const char *) git_indexer_name(const git_indexer *idx);
142156

143157
/**
144158
* Free the indexer and its resources

src/indexer.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ struct git_indexer {
5555
git_vector deltas;
5656
unsigned int fanout[256];
5757
git_hash_ctx hash_ctx;
58-
git_oid hash;
58+
unsigned char checksum[GIT_HASH_SHA1_SIZE];
59+
char name[(GIT_HASH_SHA1_SIZE * 2) + 1];
5960
git_indexer_progress_cb progress_cb;
6061
void *progress_payload;
6162
char objbuf[8*1024];
@@ -76,9 +77,16 @@ struct delta_info {
7677
off64_t delta_off;
7778
};
7879

80+
#ifndef GIT_DEPRECATE_HARD
7981
const git_oid *git_indexer_hash(const git_indexer *idx)
8082
{
81-
return &idx->hash;
83+
return (git_oid *)idx->checksum;
84+
}
85+
#endif
86+
87+
const char *git_indexer_name(const git_indexer *idx)
88+
{
89+
return idx->name;
8290
}
8391

8492
static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack)
@@ -897,8 +905,7 @@ static int index_path(git_str *path, git_indexer *idx, const char *suffix)
897905

898906
git_str_truncate(path, slash);
899907
git_str_puts(path, prefix);
900-
git_oid_fmt(path->ptr + git_str_len(path), &idx->hash);
901-
path->size += GIT_OID_HEXSZ;
908+
git_str_puts(path, idx->name);
902909
git_str_puts(path, suffix);
903910

904911
return git_str_oom(path) ? -1 : 0;
@@ -919,12 +926,13 @@ static int inject_object(git_indexer *idx, git_oid *id)
919926
git_odb_object *obj = NULL;
920927
struct entry *entry = NULL;
921928
struct git_pack_entry *pentry = NULL;
922-
git_oid foo = {{0}};
929+
unsigned char empty_checksum[GIT_HASH_SHA1_SIZE] = {0};
923930
unsigned char hdr[64];
924931
git_str buf = GIT_STR_INIT;
925932
off64_t entry_start;
926933
const void *data;
927934
size_t len, hdr_len;
935+
size_t checksum_size = GIT_HASH_SHA1_SIZE;
928936
int error;
929937

930938
if ((error = seek_back_trailer(idx)) < 0)
@@ -966,7 +974,7 @@ static int inject_object(git_indexer *idx, git_oid *id)
966974

967975
/* Write a fake trailer so the pack functions play ball */
968976

969-
if ((error = append_to_pack(idx, &foo, GIT_OID_RAWSZ)) < 0)
977+
if ((error = append_to_pack(idx, empty_checksum, checksum_size)) < 0)
970978
goto cleanup;
971979

972980
idx->pack->mwf.size += GIT_OID_RAWSZ;
@@ -1160,37 +1168,39 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
11601168
struct git_pack_idx_header hdr;
11611169
git_str filename = GIT_STR_INIT;
11621170
struct entry *entry;
1163-
git_oid trailer_hash, file_hash;
1171+
unsigned char checksum[GIT_HASH_SHA1_SIZE];
11641172
git_filebuf index_file = {0};
11651173
void *packfile_trailer;
1174+
size_t checksum_size = GIT_HASH_SHA1_SIZE;
1175+
bool mismatch;
11661176

11671177
if (!idx->parsed_header) {
11681178
git_error_set(GIT_ERROR_INDEXER, "incomplete pack header");
11691179
return -1;
11701180
}
11711181

11721182
/* Test for this before resolve_deltas(), as it plays with idx->off */
1173-
if (idx->off + 20 < idx->pack->mwf.size) {
1183+
if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) {
11741184
git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack");
11751185
return -1;
11761186
}
1177-
if (idx->off + 20 > idx->pack->mwf.size) {
1187+
if (idx->off + (ssize_t)checksum_size > idx->pack->mwf.size) {
11781188
git_error_set(GIT_ERROR_INDEXER, "missing trailer at the end of the pack");
11791189
return -1;
11801190
}
11811191

1182-
packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left);
1192+
packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - checksum_size, checksum_size, &left);
11831193
if (packfile_trailer == NULL) {
11841194
git_mwindow_close(&w);
11851195
goto on_error;
11861196
}
11871197

11881198
/* Compare the packfile trailer as it was sent to us and what we calculated */
1189-
git_oid_fromraw(&file_hash, packfile_trailer);
1199+
git_hash_final(checksum, &idx->trailer);
1200+
mismatch = !!memcmp(checksum, packfile_trailer, checksum_size);
11901201
git_mwindow_close(&w);
11911202

1192-
git_hash_final(trailer_hash.id, &idx->trailer);
1193-
if (git_oid_cmp(&file_hash, &trailer_hash)) {
1203+
if (mismatch) {
11941204
git_error_set(GIT_ERROR_INDEXER, "packfile trailer mismatch");
11951205
return -1;
11961206
}
@@ -1210,8 +1220,8 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
12101220
if (update_header_and_rehash(idx, stats) < 0)
12111221
return -1;
12121222

1213-
git_hash_final(trailer_hash.id, &idx->trailer);
1214-
write_at(idx, &trailer_hash, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ);
1223+
git_hash_final(checksum, &idx->trailer);
1224+
write_at(idx, checksum, idx->pack->mwf.size - checksum_size, checksum_size);
12151225
}
12161226

12171227
/*
@@ -1230,7 +1240,9 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
12301240

12311241
/* Use the trailer hash as the pack file name to ensure
12321242
* files with different contents have different names */
1233-
git_oid_cpy(&idx->hash, &trailer_hash);
1243+
memcpy(idx->checksum, checksum, checksum_size);
1244+
if (git_hash_fmt(idx->name, checksum, checksum_size) < 0)
1245+
return -1;
12341246

12351247
git_str_sets(&filename, idx->pack->pack_name);
12361248
git_str_shorten(&filename, strlen("pack"));
@@ -1291,14 +1303,14 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
12911303
}
12921304

12931305
/* Write out the packfile trailer to the index */
1294-
if (git_filebuf_write(&index_file, &trailer_hash, GIT_OID_RAWSZ) < 0)
1306+
if (git_filebuf_write(&index_file, checksum, checksum_size) < 0)
12951307
goto on_error;
12961308

12971309
/* Write out the hash of the idx */
1298-
if (git_filebuf_hash(trailer_hash.id, &index_file) < 0)
1310+
if (git_filebuf_hash(checksum, &index_file) < 0)
12991311
goto on_error;
13001312

1301-
git_filebuf_write(&index_file, &trailer_hash, sizeof(git_oid));
1313+
git_filebuf_write(&index_file, checksum, checksum_size);
13021314

13031315
/* Figure out what the final name should be */
13041316
if (index_path(&filename, idx, ".idx") < 0)

tests/pack/indexer.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,7 @@ void test_pack_indexer__fix_thin(void)
169169
cl_assert_equal_i(stats.indexed_objects, 2);
170170
cl_assert_equal_i(stats.local_objects, 1);
171171

172-
git_oid_fromstr(&should_id, "fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13");
173-
cl_assert_equal_oid(&should_id, git_indexer_hash(idx));
172+
cl_assert_equal_s("fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13", git_indexer_name(idx));
174173

175174
git_indexer_free(idx);
176175
git_odb_free(odb);

tests/pack/packbuilder.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "iterator.h"
66
#include "vector.h"
77
#include "posix.h"
8+
#include "hash.h"
89

910
static git_repository *_repo;
1011
static git_revwalk *_revwalker;
@@ -98,17 +99,16 @@ void test_pack_packbuilder__create_pack(void)
9899
git_indexer_progress stats;
99100
git_str buf = GIT_STR_INIT, path = GIT_STR_INIT;
100101
git_hash_ctx ctx;
101-
git_oid hash;
102-
char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0';
102+
unsigned char hash[GIT_HASH_SHA1_SIZE];
103+
char hex[(GIT_HASH_SHA1_SIZE * 2) + 1];
103104

104105
seed_packbuilder();
105106

106107
cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL));
107108
cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats));
108109
cl_git_pass(git_indexer_commit(_indexer, &stats));
109110

110-
git_oid_fmt(hex, git_indexer_hash(_indexer));
111-
git_str_printf(&path, "pack-%s.pack", hex);
111+
git_str_printf(&path, "pack-%s.pack", git_indexer_name(_indexer));
112112

113113
/*
114114
* By default, packfiles are created with only one thread.
@@ -128,14 +128,13 @@ void test_pack_packbuilder__create_pack(void)
128128

129129
cl_git_pass(git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1));
130130
cl_git_pass(git_hash_update(&ctx, buf.ptr, buf.size));
131-
cl_git_pass(git_hash_final(hash.id, &ctx));
131+
cl_git_pass(git_hash_final(hash, &ctx));
132132
git_hash_ctx_cleanup(&ctx);
133133

134134
git_str_dispose(&path);
135135
git_str_dispose(&buf);
136136

137-
git_oid_fmt(hex, &hash);
138-
137+
git_hash_fmt(hex, hash, GIT_HASH_SHA1_SIZE);
139138
cl_assert_equal_s(hex, "5d410bdf97cf896f9007681b92868471d636954b");
140139
}
141140

0 commit comments

Comments
 (0)