Skip to content

Commit 1190a1a

Browse files
peffgitster
authored andcommitted
pack-objects: name pack files after trailer hash
Our current scheme for naming packfiles is to calculate the sha1 hash of the sorted list of objects contained in the packfile. This gives us a unique name, so we are reasonably sure that two packs with the same name will contain the same objects. It does not, however, tell us that two such packs have the exact same bytes. This makes things awkward if we repack the same set of objects. Due to run-to-run variations, the bytes may not be identical (e.g., changed zlib or git versions, different source object reuse due to new packs in the repository, or even different deltas due to races during a multi-threaded delta search). In theory, this could be helpful to a program that cares that the packfile contains a certain set of objects, but does not care about the particular representation. In practice, no part of git makes use of that, and in many cases it is potentially harmful. For example, if a dumb http client fetches the .idx file, it must be sure to get the exact .pack that matches it. Similarly, a partial transfer of a .pack file cannot be safely resumed, as the actual bytes may have changed. This could also affect a local client which opened the .idx and .pack files, closes the .pack file (due to memory or file descriptor limits), and then re-opens a changed packfile. In all of these cases, git can detect the problem, as we have the sha1 of the bytes themselves in the pack trailer (which we verify on transfer), and the .idx file references the trailer from the matching packfile. But it would be simpler and more efficient to actually get the correct bytes, rather than noticing the problem and having to restart the operation. This patch simply uses the pack trailer sha1 as the pack name. It should be similarly unique, but covers the exact representation of the objects. Other parts of git should not care, as the pack name is returned by pack-objects and is essentially opaque. One test needs to be updated, because it actually corrupts a pack and expects that re-packing the corrupted bytes will use the same name. It won't anymore, but we can easily just use the name that pack-objects hands back. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e74435a commit 1190a1a

File tree

3 files changed

+4
-10
lines changed

3 files changed

+4
-10
lines changed

pack-write.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,13 @@ static int need_large_offset(off_t offset, const struct pack_idx_option *opts)
4444
*/
4545
const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects,
4646
int nr_objects, const struct pack_idx_option *opts,
47-
unsigned char *sha1)
47+
const unsigned char *sha1)
4848
{
4949
struct sha1file *f;
5050
struct pack_idx_entry **sorted_by_sha, **list, **last;
5151
off_t last_obj_offset = 0;
5252
uint32_t array[256];
5353
int i, fd;
54-
git_SHA_CTX ctx;
5554
uint32_t index_version;
5655

5756
if (nr_objects) {
@@ -114,9 +113,6 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
114113
}
115114
sha1write(f, array, 256 * 4);
116115

117-
/* compute the SHA1 hash of sorted object names. */
118-
git_SHA1_Init(&ctx);
119-
120116
/*
121117
* Write the actual SHA1 entries..
122118
*/
@@ -128,7 +124,6 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
128124
sha1write(f, &offset, 4);
129125
}
130126
sha1write(f, obj->sha1, 20);
131-
git_SHA1_Update(&ctx, obj->sha1, 20);
132127
if ((opts->flags & WRITE_IDX_STRICT) &&
133128
(i && !hashcmp(list[-2]->sha1, obj->sha1)))
134129
die("The same object %s appears twice in the pack",
@@ -178,7 +173,6 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
178173
sha1write(f, sha1, 20);
179174
sha1close(f, NULL, ((opts->flags & WRITE_IDX_VERIFY)
180175
? CSUM_CLOSE : CSUM_FSYNC));
181-
git_SHA1_Final(sha1, &ctx);
182176
return index_name;
183177
}
184178

pack.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct pack_idx_entry {
7676
struct progress;
7777
typedef int (*verify_fn)(const unsigned char*, enum object_type, unsigned long, void*, int*);
7878

79-
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, unsigned char *sha1);
79+
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1);
8080
extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
8181
extern int verify_pack_index(struct packed_git *);
8282
extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uint32_t);

t/t5302-pack-index.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,11 @@ test_expect_success \
174174
test_expect_success \
175175
'[index v1] 5) pack-objects happily reuses corrupted data' \
176176
'pack4=$(git pack-objects test-4 <obj-list) &&
177-
test -f "test-4-${pack1}.pack"'
177+
test -f "test-4-${pack4}.pack"'
178178

179179
test_expect_success \
180180
'[index v1] 6) newly created pack is BAD !' \
181-
'test_must_fail git verify-pack -v "test-4-${pack1}.pack"'
181+
'test_must_fail git verify-pack -v "test-4-${pack4}.pack"'
182182

183183
test_expect_success \
184184
'[index v2] 1) stream pack to repository' \

0 commit comments

Comments
 (0)