Skip to content

Commit 11ef76a

Browse files
committed
index: 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_index_checksum` function without a replacement. This is an abstraction that callers should not care about (and indeed do not seem to be using). Remove the unused `git_index__changed_relative_to` function.
1 parent afca16a commit 11ef76a

File tree

4 files changed

+55
-48
lines changed

4 files changed

+55
-48
lines changed

include/git2/index.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,17 +296,20 @@ GIT_EXTERN(int) git_index_write(git_index *index);
296296
*/
297297
GIT_EXTERN(const char *) git_index_path(const git_index *index);
298298

299+
#ifndef GIT_DEPRECATE_HARD
299300
/**
300301
* Get the checksum of the index
301302
*
302303
* This checksum is the SHA-1 hash over the index file (except the
303304
* last 20 bytes which are the checksum itself). In cases where the
304305
* index does not exist on-disk, it will be zeroed out.
305306
*
307+
* @deprecated this function is deprecated with no replacement
306308
* @param index an existing index object
307309
* @return a pointer to the checksum of the index
308310
*/
309311
GIT_EXTERN(const git_oid *) git_index_checksum(git_index *index);
312+
#endif
310313

311314
/**
312315
* Read a tree into the index file with stats

src/index.c

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarr
3434

3535
#define minimal_entry_size (offsetof(struct entry_short, path))
3636

37-
static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;
3837
static const size_t INDEX_HEADER_SIZE = 12;
3938

4039
static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2;
@@ -121,7 +120,7 @@ static int read_header(struct index_header *dest, const void *buffer);
121120

122121
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
123122
static bool is_index_extended(git_index *index);
124-
static int write_index(git_oid *checksum, git_index *index, git_filebuf *file);
123+
static int write_index(unsigned char checksum[GIT_HASH_SHA1_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file);
125124

126125
static void index_entry_free(git_index_entry *entry);
127126
static void index_entry_reuc_free(git_index_reuc_entry *reuc);
@@ -607,10 +606,12 @@ int git_index_caps(const git_index *index)
607606
(index->no_symlinks ? GIT_INDEX_CAPABILITY_NO_SYMLINKS : 0));
608607
}
609608

609+
#ifndef GIT_DEPRECATE_HARD
610610
const git_oid *git_index_checksum(git_index *index)
611611
{
612-
return &index->checksum;
612+
return (git_oid *)index->checksum;
613613
}
614+
#endif
614615

615616
/**
616617
* Returns 1 for changed, 0 for not changed and <0 for errors
@@ -619,24 +620,25 @@ static int compare_checksum(git_index *index)
619620
{
620621
int fd;
621622
ssize_t bytes_read;
622-
git_oid checksum = {{ 0 }};
623+
unsigned char checksum[GIT_HASH_SHA1_SIZE];
624+
size_t checksum_size = GIT_HASH_SHA1_SIZE;
623625

624626
if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0)
625627
return fd;
626628

627-
if (p_lseek(fd, -20, SEEK_END) < 0) {
629+
if (p_lseek(fd, (0 - (ssize_t)checksum_size), SEEK_END) < 0) {
628630
p_close(fd);
629631
git_error_set(GIT_ERROR_OS, "failed to seek to end of file");
630632
return -1;
631633
}
632634

633-
bytes_read = p_read(fd, &checksum, GIT_OID_RAWSZ);
635+
bytes_read = p_read(fd, checksum, checksum_size);
634636
p_close(fd);
635637

636-
if (bytes_read < 0)
638+
if (bytes_read < (ssize_t)checksum_size)
637639
return -1;
638640

639-
return !!git_oid_cmp(&checksum, &index->checksum);
641+
return !!memcmp(checksum, index->checksum, checksum_size);
640642
}
641643

642644
int git_index_read(git_index *index, int force)
@@ -703,16 +705,6 @@ int git_index_read_safely(git_index *index)
703705
return git_index_read(index, false);
704706
}
705707

706-
int git_index__changed_relative_to(
707-
git_index *index, const git_oid *checksum)
708-
{
709-
/* attempt to update index (ignoring errors) */
710-
if (git_index_read(index, false) < 0)
711-
git_error_clear();
712-
713-
return !!git_oid_cmp(&index->checksum, checksum);
714-
}
715-
716708
static bool is_racy_entry(git_index *index, const git_index_entry *entry)
717709
{
718710
/* Git special-cases submodules in the check */
@@ -2470,8 +2462,9 @@ static int read_entry(
24702462
git_index_entry entry = {{0}};
24712463
bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP;
24722464
char *tmp_path = NULL;
2465+
size_t checksum_size = GIT_HASH_SHA1_SIZE;
24732466

2474-
if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
2467+
if (checksum_size + minimal_entry_size > buffer_size)
24752468
return -1;
24762469

24772470
/* buffer is not guaranteed to be aligned */
@@ -2552,7 +2545,7 @@ static int read_entry(
25522545
if (entry_size == 0)
25532546
return -1;
25542547

2555-
if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
2548+
if (checksum_size + entry_size > buffer_size)
25562549
return -1;
25572550

25582551
if (index_entry_dup(out, index, &entry) < 0) {
@@ -2586,6 +2579,7 @@ static int read_extension(size_t *read_len, git_index *index, const char *buffer
25862579
{
25872580
struct index_extension dest;
25882581
size_t total_size;
2582+
size_t checksum_size = GIT_HASH_SHA1_SIZE;
25892583

25902584
/* buffer is not guaranteed to be aligned */
25912585
memcpy(&dest, buffer, sizeof(struct index_extension));
@@ -2595,7 +2589,7 @@ static int read_extension(size_t *read_len, git_index *index, const char *buffer
25952589

25962590
if (dest.extension_size > total_size ||
25972591
buffer_size < total_size ||
2598-
buffer_size - total_size < INDEX_FOOTER_SIZE) {
2592+
buffer_size - total_size < checksum_size) {
25992593
index_error_invalid("extension is truncated");
26002594
return -1;
26012595
}
@@ -2632,7 +2626,8 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
26322626
int error = 0;
26332627
unsigned int i;
26342628
struct index_header header = { 0 };
2635-
git_oid checksum_calculated, checksum_expected;
2629+
unsigned char checksum[GIT_HASH_SHA1_SIZE];
2630+
size_t checksum_size = GIT_HASH_SHA1_SIZE;
26362631
const char *last = NULL;
26372632
const char *empty = "";
26382633

@@ -2644,12 +2639,12 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
26442639
buffer_size -= _increase;\
26452640
}
26462641

2647-
if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE)
2642+
if (buffer_size < INDEX_HEADER_SIZE + checksum_size)
26482643
return index_error_invalid("insufficient buffer space");
26492644

26502645
/* Precalculate the SHA1 of the files's contents -- we'll match it to
26512646
* the provided SHA1 in the footer */
2652-
git_hash_buf(checksum_calculated.id, buffer, buffer_size - INDEX_FOOTER_SIZE, GIT_HASH_ALGORITHM_SHA1);
2647+
git_hash_buf(checksum, buffer, buffer_size - checksum_size, GIT_HASH_ALGORITHM_SHA1);
26532648

26542649
/* Parse header */
26552650
if ((error = read_header(&header, buffer)) < 0)
@@ -2667,7 +2662,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
26672662
return error;
26682663

26692664
/* Parse all the entries */
2670-
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
2665+
for (i = 0; i < header.entry_count && buffer_size > checksum_size; ++i) {
26712666
git_index_entry *entry = NULL;
26722667
size_t entry_size;
26732668

@@ -2699,7 +2694,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
26992694
}
27002695

27012696
/* There's still space for some extensions! */
2702-
while (buffer_size > INDEX_FOOTER_SIZE) {
2697+
while (buffer_size > checksum_size) {
27032698
size_t extension_size;
27042699

27052700
if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) {
@@ -2709,22 +2704,20 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
27092704
seek_forward(extension_size);
27102705
}
27112706

2712-
if (buffer_size != INDEX_FOOTER_SIZE) {
2707+
if (buffer_size != checksum_size) {
27132708
error = index_error_invalid(
27142709
"buffer size does not match index footer size");
27152710
goto done;
27162711
}
27172712

27182713
/* 160-bit SHA-1 over the content of the index file before this checksum. */
2719-
git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer);
2720-
2721-
if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) {
2714+
if (memcmp(checksum, buffer, checksum_size) != 0) {
27222715
error = index_error_invalid(
27232716
"calculated checksum does not match expected");
27242717
goto done;
27252718
}
27262719

2727-
git_oid_cpy(&index->checksum, &checksum_calculated);
2720+
memcpy(index->checksum, checksum, checksum_size);
27282721

27292722
#undef seek_forward
27302723

@@ -3040,16 +3033,21 @@ static void clear_uptodate(git_index *index)
30403033
entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE;
30413034
}
30423035

3043-
static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
3036+
static int write_index(
3037+
unsigned char checksum[GIT_HASH_SHA1_SIZE],
3038+
size_t *checksum_size,
3039+
git_index *index,
3040+
git_filebuf *file)
30443041
{
3045-
git_oid hash_final;
30463042
struct index_header header;
30473043
bool is_extended;
30483044
uint32_t index_version_number;
30493045

30503046
GIT_ASSERT_ARG(index);
30513047
GIT_ASSERT_ARG(file);
30523048

3049+
*checksum_size = GIT_HASH_SHA1_SIZE;
3050+
30533051
if (index->version <= INDEX_VERSION_NUMBER_EXT) {
30543052
is_extended = is_index_extended(index);
30553053
index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER_LB;
@@ -3080,11 +3078,10 @@ static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
30803078
return -1;
30813079

30823080
/* get out the hash for all the contents we've appended to the file */
3083-
git_filebuf_hash(hash_final.id, file);
3084-
git_oid_cpy(checksum, &hash_final);
3081+
git_filebuf_hash(checksum, file);
30853082

30863083
/* write it at the end of the file */
3087-
if (git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ) < 0)
3084+
if (git_filebuf_write(file, checksum, *checksum_size) < 0)
30883085
return -1;
30893086

30903087
/* file entries are no longer up to date */
@@ -3714,16 +3711,17 @@ int git_indexwriter_init_for_operation(
37143711

37153712
int git_indexwriter_commit(git_indexwriter *writer)
37163713
{
3714+
unsigned char checksum[GIT_HASH_SHA1_SIZE];
3715+
size_t checksum_size;
37173716
int error;
3718-
git_oid checksum = {{ 0 }};
37193717

37203718
if (!writer->should_write)
37213719
return 0;
37223720

37233721
git_vector_sort(&writer->index->entries);
37243722
git_vector_sort(&writer->index->reuc);
37253723

3726-
if ((error = write_index(&checksum, writer->index, &writer->file)) < 0) {
3724+
if ((error = write_index(checksum, &checksum_size, writer->index, &writer->file)) < 0) {
37273725
git_indexwriter_cleanup(writer);
37283726
return error;
37293727
}
@@ -3739,7 +3737,7 @@ int git_indexwriter_commit(git_indexwriter *writer)
37393737

37403738
writer->index->dirty = 0;
37413739
writer->index->on_disk = 1;
3742-
git_oid_cpy(&writer->index->checksum, &checksum);
3740+
memcpy(writer->index->checksum, checksum, checksum_size);
37433741

37443742
git_index_free(writer->index);
37453743
writer->index = NULL;

src/index.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct git_index {
2727

2828
char *index_file_path;
2929
git_futils_filestamp stamp;
30-
git_oid checksum; /* checksum at the end of the file */
30+
unsigned char checksum[GIT_HASH_SHA1_SIZE];
3131

3232
git_vector entries;
3333
git_idxmap *entries_map;
@@ -133,10 +133,13 @@ extern unsigned int git_index__create_mode(unsigned int mode);
133133

134134
GIT_INLINE(const git_futils_filestamp *) git_index__filestamp(git_index *index)
135135
{
136-
return &index->stamp;
136+
return &index->stamp;
137137
}
138138

139-
extern int git_index__changed_relative_to(git_index *index, const git_oid *checksum);
139+
GIT_INLINE(unsigned char *) git_index__checksum(git_index *index)
140+
{
141+
return index->checksum;
142+
}
140143

141144
/* Copy the current entries vector *and* increment the index refcount.
142145
* Call `git_index__release_snapshot` when done.

tests/diff/workdir.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "clar_libgit2.h"
22
#include "diff_helpers.h"
33
#include "repository.h"
4+
#include "index.h"
45
#include "git2/sys/diff.h"
56
#include "../checkout/checkout_helpers.h"
67

@@ -2004,7 +2005,9 @@ void test_diff_workdir__only_writes_index_when_necessary(void)
20042005
git_diff *diff = NULL;
20052006
git_reference *head;
20062007
git_object *head_object;
2007-
git_oid initial, first, second;
2008+
unsigned char initial[GIT_HASH_SHA1_SIZE],
2009+
first[GIT_HASH_SHA1_SIZE],
2010+
second[GIT_HASH_SHA1_SIZE];
20082011
git_str path = GIT_STR_INIT;
20092012
struct stat st;
20102013
struct p_timeval times[2];
@@ -2019,7 +2022,7 @@ void test_diff_workdir__only_writes_index_when_necessary(void)
20192022

20202023
cl_git_pass(git_reset(g_repo, head_object, GIT_RESET_HARD, NULL));
20212024

2022-
git_oid_cpy(&initial, git_index_checksum(index));
2025+
memcpy(initial, git_index__checksum(index), GIT_HASH_SHA1_SIZE);
20232026

20242027
/* update the index timestamp to avoid raciness */
20252028
cl_must_pass(p_stat("status/.git/index", &st));
@@ -2035,8 +2038,8 @@ void test_diff_workdir__only_writes_index_when_necessary(void)
20352038
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
20362039
git_diff_free(diff);
20372040

2038-
git_oid_cpy(&first, git_index_checksum(index));
2039-
cl_assert(!git_oid_equal(&initial, &first));
2041+
memcpy(first, git_index__checksum(index), GIT_HASH_SHA1_SIZE);
2042+
cl_assert(memcmp(initial, first, GIT_HASH_SHA1_SIZE) != 0);
20402043

20412044
/* touch all the files so stat times are different */
20422045
cl_git_pass(git_str_sets(&path, "status"));
@@ -2046,8 +2049,8 @@ void test_diff_workdir__only_writes_index_when_necessary(void)
20462049
git_diff_free(diff);
20472050

20482051
/* ensure the second diff did update the index */
2049-
git_oid_cpy(&second, git_index_checksum(index));
2050-
cl_assert(!git_oid_equal(&first, &second));
2052+
memcpy(second, git_index__checksum(index), GIT_HASH_SHA1_SIZE);
2053+
cl_assert(memcmp(first, second, GIT_HASH_SHA1_SIZE) != 0);
20512054

20522055
git_str_dispose(&path);
20532056
git_object_free(head_object);

0 commit comments

Comments
 (0)