2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
29 #include "repository.h"
33 #include "git2/blob.h"
35 #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
36 #define short_entry_size(len) entry_size(struct entry_short, len)
37 #define long_entry_size(len) entry_size(struct entry_long, len)
39 #define minimal_entry_size (offsetof(struct entry_short, path))
41 static const size_t INDEX_FOOTER_SIZE
= GIT_OID_RAWSZ
;
42 static const size_t INDEX_HEADER_SIZE
= 12;
44 static const unsigned int INDEX_VERSION_NUMBER
= 2;
45 static const unsigned int INDEX_VERSION_NUMBER_EXT
= 3;
47 static const unsigned int INDEX_HEADER_SIG
= 0x44495243;
48 static const char INDEX_EXT_TREECACHE_SIG
[] = {'T', 'R', 'E', 'E'};
49 static const char INDEX_EXT_UNMERGED_SIG
[] = {'R', 'E', 'U', 'C'};
57 struct index_extension
{
59 uint32_t extension_size
;
68 struct entry_time ctime
;
69 struct entry_time mtime
;
78 char path
[1]; /* arbitrary length */
82 struct entry_time ctime
;
83 struct entry_time mtime
;
92 uint16_t flags_extended
;
93 char path
[1]; /* arbitrary length */
96 /* local declarations */
97 static size_t read_extension(git_index
*index
, const char *buffer
, size_t buffer_size
);
98 static size_t read_entry(git_index_entry
*dest
, const void *buffer
, size_t buffer_size
);
99 static int read_header(struct index_header
*dest
, const void *buffer
);
101 static int read_tree(git_index
*index
, const char *buffer
, size_t buffer_size
);
102 static int read_tree_internal(git_index_tree
**, const char **, const char *, git_index_tree
*);
104 static int parse_index(git_index
*index
, const char *buffer
, size_t buffer_size
);
105 static int is_index_extended(git_index
*index
);
106 static void sort_index(git_index
*index
);
107 static int write_index(git_index
*index
, git_filebuf
*file
);
109 int index_srch(const void *key
, const void *array_member
)
111 const char *filename
= (const char *)key
;
112 const git_index_entry
*entry
= *(const git_index_entry
**)(array_member
);
114 return strcmp(filename
, entry
->path
);
117 int index_cmp(const void *a
, const void *b
)
119 const git_index_entry
*entry_a
= *(const git_index_entry
**)(a
);
120 const git_index_entry
*entry_b
= *(const git_index_entry
**)(b
);
122 return strcmp(entry_a
->path
, entry_b
->path
);
125 int unmerged_srch(const void *key
, const void *array_member
)
127 const char *path
= (const char *) key
;
128 const git_index_entry_unmerged
*entry
= *(const git_index_entry_unmerged
**) (array_member
);
130 return strcmp(path
, entry
->path
);
133 int unmerged_cmp(const void *a
, const void *b
)
135 const git_index_entry_unmerged
*info_a
= *(const git_index_entry_unmerged
**)(a
);
136 const git_index_entry_unmerged
*info_b
= *(const git_index_entry_unmerged
**)(b
);
138 return strcmp(info_a
->path
, info_b
->path
);
141 static int index_initialize(git_index
**index_out
, git_repository
*owner
, const char *index_path
)
145 assert(index_out
&& index_path
);
147 index
= git__malloc(sizeof(git_index
));
151 memset(index
, 0x0, sizeof(git_index
));
153 index
->index_file_path
= git__strdup(index_path
);
154 if (index
->index_file_path
== NULL
) {
159 index
->repository
= owner
;
161 git_vector_init(&index
->entries
, 32, index_cmp
);
163 /* Check if index file is stored on disk already */
164 if (gitfo_exists(index
->index_file_path
) == 0)
168 return git_index_read(index
);
171 int git_index_open(git_index
**index_out
, const char *index_path
)
173 assert(index_out
&& index_path
);
174 return index_initialize(index_out
, NULL
, index_path
);
178 * Moved from `repository.c`
180 int git_repository_index(git_index
**index_out
, git_repository
*repo
)
182 assert(index_out
&& repo
);
185 return git__throw(GIT_EBAREINDEX
, "Failed to open index. Repository is bare");
187 return index_initialize(index_out
, repo
, repo
->path_index
);
190 void git_index_free(git_index
*index
)
195 git_index_clear(index
);
196 git_vector_free(&index
->entries
);
197 git_vector_free(&index
->unmerged
);
199 free(index
->index_file_path
);
203 static void free_tree(git_index_tree
*tree
)
210 for (i
= 0; i
< tree
->children_count
; ++i
)
211 free_tree(tree
->children
[i
]);
214 free(tree
->children
);
218 void git_index_clear(git_index
*index
)
224 for (i
= 0; i
< index
->entries
.length
; ++i
) {
226 e
= git_vector_get(&index
->entries
, i
);
227 free((char *)e
->path
);
231 for (i
= 0; i
< index
->unmerged
.length
; ++i
) {
232 git_index_entry_unmerged
*e
;
233 e
= git_vector_get(&index
->unmerged
, i
);
234 free((char *)e
->path
);
238 git_vector_clear(&index
->entries
);
239 git_vector_clear(&index
->unmerged
);
240 index
->last_modified
= 0;
242 free_tree(index
->tree
);
246 int git_index_read(git_index
*index
)
249 int error
= GIT_SUCCESS
;
251 assert(index
->index_file_path
);
253 if (!index
->on_disk
|| gitfo_exists(index
->index_file_path
) < 0) {
254 git_index_clear(index
);
259 if (gitfo_stat(index
->index_file_path
, &indexst
) < 0)
260 return git__throw(GIT_EOSERR
, "Failed to read index. %s does not exist or is corrupted", index
->index_file_path
);
262 if (!S_ISREG(indexst
.st_mode
))
263 return git__throw(GIT_ENOTFOUND
, "Failed to read index. %s is not an index file", index
->index_file_path
);
265 if (indexst
.st_mtime
!= index
->last_modified
) {
269 if ((error
= gitfo_read_file(&buffer
, index
->index_file_path
)) < GIT_SUCCESS
)
270 return git__rethrow(error
, "Failed to read index");
272 git_index_clear(index
);
273 error
= parse_index(index
, buffer
.data
, buffer
.len
);
275 if (error
== GIT_SUCCESS
)
276 index
->last_modified
= indexst
.st_mtime
;
278 gitfo_free_buf(&buffer
);
281 if (error
< GIT_SUCCESS
)
282 return git__rethrow(error
, "Failed to read index");
286 int git_index_write(git_index
*index
)
294 if ((error
= git_filebuf_open(&file
, index
->index_file_path
, GIT_FILEBUF_HASH_CONTENTS
)) < GIT_SUCCESS
)
295 return git__rethrow(error
, "Failed to write index");
297 if ((error
= write_index(index
, &file
)) < GIT_SUCCESS
) {
298 git_filebuf_cleanup(&file
);
299 return git__rethrow(error
, "Failed to write index");
302 if ((error
= git_filebuf_commit(&file
)) < GIT_SUCCESS
)
303 return git__rethrow(error
, "Failed to write index");
305 if (gitfo_stat(index
->index_file_path
, &indexst
) == 0) {
306 index
->last_modified
= indexst
.st_mtime
;
313 unsigned int git_index_entrycount(git_index
*index
)
316 return index
->entries
.length
;
319 unsigned int git_index_entrycount_unmerged(git_index
*index
)
322 return index
->unmerged
.length
;
325 git_index_entry
*git_index_get(git_index
*index
, int n
)
329 return git_vector_get(&index
->entries
, (unsigned int)n
);
332 static void sort_index(git_index
*index
)
334 git_vector_sort(&index
->entries
);
337 static int index_insert(git_index
*index
, const git_index_entry
*source_entry
, int replace
)
339 git_index_entry
*entry
;
343 assert(index
&& source_entry
);
345 if (source_entry
->path
== NULL
)
346 return git__throw(GIT_EMISSINGOBJDATA
, "Failed to insert into index. Entry has no path");
348 entry
= git__malloc(sizeof(git_index_entry
));
352 memcpy(entry
, source_entry
, sizeof(git_index_entry
));
354 /* duplicate the path string so we own it */
355 entry
->path
= git__strdup(entry
->path
);
356 if (entry
->path
== NULL
)
359 /* make sure that the path length flag is correct */
360 path_length
= strlen(entry
->path
);
362 entry
->flags
&= ~GIT_IDXENTRY_NAMEMASK
;
364 if (path_length
< GIT_IDXENTRY_NAMEMASK
)
365 entry
->flags
|= path_length
& GIT_IDXENTRY_NAMEMASK
;
367 entry
->flags
|= GIT_IDXENTRY_NAMEMASK
;;
370 /* look if an entry with this path already exists */
371 position
= git_index_find(index
, source_entry
->path
);
373 /* if no entry exists and replace is not set,
374 * add the entry at the end;
375 * the index is no longer sorted */
376 if (!replace
|| position
== GIT_ENOTFOUND
) {
377 if (git_vector_insert(&index
->entries
, entry
) < GIT_SUCCESS
)
380 /* if a previous entry exists and replace is set,
383 git_index_entry
**entry_array
= (git_index_entry
**)index
->entries
.contents
;
385 free((char *)entry_array
[position
]->path
);
386 free(entry_array
[position
]);
388 entry_array
[position
] = entry
;
394 static int index_init_entry(git_index_entry
*entry
, git_index
*index
, const char *rel_path
, int stage
)
396 char full_path
[GIT_PATH_MAX
];
400 if (index
->repository
== NULL
)
401 return git__throw(GIT_EBAREINDEX
, "Failed to initialize entry. Repository is bare");
403 git__joinpath(full_path
, index
->repository
->path_workdir
, rel_path
);
405 if (gitfo_exists(full_path
) < 0)
406 return git__throw(GIT_ENOTFOUND
, "Failed to initialize entry. %s does not exist", full_path
);
408 if (gitfo_stat(full_path
, &st
) < 0)
409 return git__throw(GIT_EOSERR
, "Failed to initialize entry. %s appears to be corrupted", full_path
);
411 if (stage
< 0 || stage
> 3)
412 return git__throw(GIT_ERROR
, "Failed to initialize entry. Invalid stage %i", stage
);
414 memset(entry
, 0x0, sizeof(git_index_entry
));
416 entry
->ctime
.seconds
= (git_time_t
)st
.st_ctime
;
417 entry
->mtime
.seconds
= (git_time_t
)st
.st_mtime
;
418 /* entry.mtime.nanoseconds = st.st_mtimensec; */
419 /* entry.ctime.nanoseconds = st.st_ctimensec; */
420 entry
->dev
= st
.st_rdev
;
421 entry
->ino
= st
.st_ino
;
422 entry
->mode
= st
.st_mode
;
423 entry
->uid
= st
.st_uid
;
424 entry
->gid
= st
.st_gid
;
425 entry
->file_size
= st
.st_size
;
427 /* write the blob to disk and get the oid */
428 if ((error
= git_blob_create_fromfile(&entry
->oid
, index
->repository
, rel_path
)) < GIT_SUCCESS
)
429 return git__rethrow(error
, "Failed to initialize index entry");
431 entry
->flags
|= (stage
<< GIT_IDXENTRY_STAGESHIFT
);
432 entry
->path
= (char *)rel_path
; /* do not duplicate; index_insert already does this */
436 int git_index_add(git_index
*index
, const char *path
, int stage
)
439 git_index_entry entry
;
441 if ((error
= index_init_entry(&entry
, index
, path
, stage
)) < GIT_SUCCESS
)
442 return git__rethrow(error
, "Failed to add to index");
444 return index_insert(index
, &entry
, 1);
447 int git_index_append(git_index
*index
, const char *path
, int stage
)
450 git_index_entry entry
;
452 if ((error
= index_init_entry(&entry
, index
, path
, stage
)) < GIT_SUCCESS
)
453 return git__rethrow(error
, "Failed to append to index");
455 return index_insert(index
, &entry
, 0);
458 int git_index_add2(git_index
*index
, const git_index_entry
*source_entry
)
460 return index_insert(index
, source_entry
, 1);
463 int git_index_append2(git_index
*index
, const git_index_entry
*source_entry
)
465 return index_insert(index
, source_entry
, 0);
469 int git_index_remove(git_index
*index
, int position
)
473 return git_vector_remove(&index
->entries
, (unsigned int)position
);
476 int git_index_find(git_index
*index
, const char *path
)
479 return git_vector_bsearch2(&index
->entries
, index_srch
, path
);
482 const git_index_entry_unmerged
*git_index_get_unmerged(git_index
*index
, const char *path
)
485 assert(index
&& path
);
487 if (!index
->unmerged
.length
)
490 if ((pos
= git_vector_bsearch2(&index
->unmerged
, unmerged_srch
, path
)) < GIT_SUCCESS
)
493 return git_vector_get(&index
->unmerged
, pos
);
497 static int read_tree_internal(git_index_tree
**out
,
498 const char **buffer_in
, const char *buffer_end
, git_index_tree
*parent
)
500 git_index_tree
*tree
;
501 const char *name_start
, *buffer
;
503 int error
= GIT_SUCCESS
;
505 if ((tree
= git__malloc(sizeof(git_index_tree
))) == NULL
)
508 memset(tree
, 0x0, sizeof(git_index_tree
));
509 tree
->parent
= parent
;
511 buffer
= name_start
= *buffer_in
;
513 if ((buffer
= memchr(buffer
, '\0', buffer_end
- buffer
)) == NULL
) {
514 error
= GIT_EOBJCORRUPTED
;
518 /* NUL-terminated tree name */
519 tree
->name
= git__strdup(name_start
);
520 if (tree
->name
== NULL
) {
525 if (++buffer
>= buffer_end
) {
526 error
= GIT_EOBJCORRUPTED
;
530 /* Blank-terminated ASCII decimal number of entries in this tree */
531 if (git__strtol32(&count
, buffer
, &buffer
, 10) < GIT_SUCCESS
|| count
< -1) {
532 error
= GIT_EOBJCORRUPTED
;
536 /* Invalidated TREE. Free the tree but report success */
538 /* FIXME: return buffer_end or the end position for
539 * this single tree entry */
540 *buffer_in
= buffer_end
;
542 free_tree(tree
); /* Needs to be done manually */
546 tree
->entries
= (size_t)count
;
548 if (*buffer
!= ' ' || ++buffer
>= buffer_end
) {
549 error
= GIT_EOBJCORRUPTED
;
553 /* Number of children of the tree, newline-terminated */
554 if (git__strtol32(&count
, buffer
, &buffer
, 10) < GIT_SUCCESS
||
556 error
= GIT_EOBJCORRUPTED
;
560 tree
->children_count
= (size_t)count
;
562 if (*buffer
!= '\n' || ++buffer
>= buffer_end
) {
563 error
= GIT_EOBJCORRUPTED
;
567 /* 160-bit SHA-1 for this tree and it's children */
568 if (buffer
+ GIT_OID_RAWSZ
> buffer_end
) {
569 error
= GIT_EOBJCORRUPTED
;
573 git_oid_mkraw(&tree
->oid
, (const unsigned char *)buffer
);
574 buffer
+= GIT_OID_RAWSZ
;
576 /* Parse children: */
577 if (tree
->children_count
> 0) {
581 tree
->children
= git__malloc(tree
->children_count
* sizeof(git_index_tree
*));
582 if (tree
->children
== NULL
)
585 for (i
= 0; i
< tree
->children_count
; ++i
) {
586 err
= read_tree_internal(&tree
->children
[i
], &buffer
, buffer_end
, tree
);
588 if (err
< GIT_SUCCESS
)
602 static int read_tree(git_index
*index
, const char *buffer
, size_t buffer_size
)
604 const char *buffer_end
= buffer
+ buffer_size
;
607 error
= read_tree_internal(&index
->tree
, &buffer
, buffer_end
, NULL
);
609 if (buffer
< buffer_end
)
610 return GIT_EOBJCORRUPTED
;
615 static int read_unmerged(git_index
*index
, const char *buffer
, size_t size
)
621 git_vector_init(&index
->unmerged
, 16, unmerged_cmp
);
624 git_index_entry_unmerged
*lost
;
626 len
= strlen(buffer
) + 1;
628 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
630 if ((lost
= git__malloc(sizeof(git_index_entry_unmerged
))) == NULL
)
633 if (git_vector_insert(&index
->unmerged
, lost
) < GIT_SUCCESS
)
634 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
636 lost
->path
= git__strdup(buffer
);
643 for (i
= 0; i
< 3; i
++) {
644 if (git__strtol32((long int *) &lost
->mode
[i
], buffer
, &endptr
, 8) < GIT_SUCCESS
||
645 !endptr
|| endptr
== buffer
|| *endptr
)
648 len
= (endptr
+ 1) - (char *) buffer
;
650 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
656 for (i
= 0; i
< 3; i
++) {
660 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
661 git_oid_mkraw(&lost
->oid
[i
], (unsigned char *) buffer
);
670 static size_t read_entry(git_index_entry
*dest
, const void *buffer
, size_t buffer_size
)
672 size_t path_length
, entry_size
;
674 const char *path_ptr
;
675 const struct entry_short
*source
;
677 if (INDEX_FOOTER_SIZE
+ minimal_entry_size
> buffer_size
)
680 memset(dest
, 0x0, sizeof(git_index_entry
));
682 source
= (const struct entry_short
*)(buffer
);
684 dest
->ctime
.seconds
= (git_time_t
)ntohl(source
->ctime
.seconds
);
685 dest
->ctime
.nanoseconds
= ntohl(source
->ctime
.nanoseconds
);
686 dest
->mtime
.seconds
= (git_time_t
)ntohl(source
->mtime
.seconds
);
687 dest
->mtime
.nanoseconds
= ntohl(source
->mtime
.nanoseconds
);
688 dest
->dev
= ntohl(source
->dev
);
689 dest
->ino
= ntohl(source
->ino
);
690 dest
->mode
= ntohl(source
->mode
);
691 dest
->uid
= ntohl(source
->uid
);
692 dest
->gid
= ntohl(source
->gid
);
693 dest
->file_size
= ntohl(source
->file_size
);
694 git_oid_cpy(&dest
->oid
, &source
->oid
);
695 dest
->flags
= ntohs(source
->flags
);
697 if (dest
->flags
& GIT_IDXENTRY_EXTENDED
) {
698 struct entry_long
*source_l
= (struct entry_long
*)source
;
699 path_ptr
= source_l
->path
;
701 flags_raw
= ntohs(source_l
->flags_extended
);
702 memcpy(&dest
->flags_extended
, &flags_raw
, 2);
704 path_ptr
= source
->path
;
706 path_length
= dest
->flags
& GIT_IDXENTRY_NAMEMASK
;
708 /* if this is a very long string, we must find its
709 * real length without overflowing */
710 if (path_length
== 0xFFF) {
711 const char *path_end
;
713 path_end
= memchr(path_ptr
, '\0', buffer_size
);
714 if (path_end
== NULL
)
717 path_length
= path_end
- path_ptr
;
720 if (dest
->flags
& GIT_IDXENTRY_EXTENDED
)
721 entry_size
= long_entry_size(path_length
);
723 entry_size
= short_entry_size(path_length
);
725 if (INDEX_FOOTER_SIZE
+ entry_size
> buffer_size
)
728 dest
->path
= git__strdup(path_ptr
);
734 static int read_header(struct index_header
*dest
, const void *buffer
)
736 const struct index_header
*source
;
737 source
= (const struct index_header
*)(buffer
);
739 dest
->signature
= ntohl(source
->signature
);
740 if (dest
->signature
!= INDEX_HEADER_SIG
)
741 return GIT_EOBJCORRUPTED
;
743 dest
->version
= ntohl(source
->version
);
744 if (dest
->version
!= INDEX_VERSION_NUMBER_EXT
&&
745 dest
->version
!= INDEX_VERSION_NUMBER
)
746 return GIT_EOBJCORRUPTED
;
748 dest
->entry_count
= ntohl(source
->entry_count
);
752 static size_t read_extension(git_index
*index
, const char *buffer
, size_t buffer_size
)
754 const struct index_extension
*source
;
755 struct index_extension dest
;
758 source
= (const struct index_extension
*)(buffer
);
760 memcpy(dest
.signature
, source
->signature
, 4);
761 dest
.extension_size
= ntohl(source
->extension_size
);
763 total_size
= dest
.extension_size
+ sizeof(struct index_extension
);
765 if (buffer_size
- total_size
< INDEX_FOOTER_SIZE
)
768 /* optional extension */
769 if (dest
.signature
[0] >= 'A' && dest
.signature
[0] <= 'Z') {
771 if (memcmp(dest
.signature
, INDEX_EXT_TREECACHE_SIG
, 4) == 0) {
772 if (read_tree(index
, buffer
+ 8, dest
.extension_size
) < GIT_SUCCESS
)
774 } else if (memcmp(dest
.signature
, INDEX_EXT_UNMERGED_SIG
, 4) == 0) {
775 if (read_unmerged(index
, buffer
+ 8, dest
.extension_size
) < GIT_SUCCESS
)
778 /* else, unsupported extension. We cannot parse this, but we can skip
779 * it by returning `total_size */
781 /* we cannot handle non-ignorable extensions;
782 * in fact they aren't even defined in the standard */
789 static int parse_index(git_index
*index
, const char *buffer
, size_t buffer_size
)
792 struct index_header header
;
793 git_oid checksum_calculated
, checksum_expected
;
795 #define seek_forward(_increase) { \
796 if (_increase >= buffer_size) \
797 return git__throw(GIT_EOBJCORRUPTED, "Failed to seek forward. Buffer size exceeded"); \
798 buffer += _increase; \
799 buffer_size -= _increase;\
802 if (buffer_size
< INDEX_HEADER_SIZE
+ INDEX_FOOTER_SIZE
)
803 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Buffer too small");
805 /* Precalculate the SHA1 of the files's contents -- we'll match it to
806 * the provided SHA1 in the footer */
807 git_hash_buf(&checksum_calculated
, (const void *)buffer
, buffer_size
- INDEX_FOOTER_SIZE
);
810 if (read_header(&header
, buffer
) < GIT_SUCCESS
)
811 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Header is corrupted");
813 seek_forward(INDEX_HEADER_SIZE
);
815 git_vector_clear(&index
->entries
);
817 /* Parse all the entries */
818 for (i
= 0; i
< header
.entry_count
&& buffer_size
> INDEX_FOOTER_SIZE
; ++i
) {
820 git_index_entry
*entry
;
822 entry
= git__malloc(sizeof(git_index_entry
));
826 entry_size
= read_entry(entry
, buffer
, buffer_size
);
828 /* 0 bytes read means an object corruption */
830 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Entry size is zero");
832 if (git_vector_insert(&index
->entries
, entry
) < GIT_SUCCESS
)
835 seek_forward(entry_size
);
838 if (i
!= header
.entry_count
)
839 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Header entries changed while parsing");
841 /* There's still space for some extensions! */
842 while (buffer_size
> INDEX_FOOTER_SIZE
) {
843 size_t extension_size
;
845 extension_size
= read_extension(index
, buffer
, buffer_size
);
847 /* see if we have read any bytes from the extension */
848 if (extension_size
== 0)
849 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Extension size is zero");
851 seek_forward(extension_size
);
854 if (buffer_size
!= INDEX_FOOTER_SIZE
)
855 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Buffer size does not match index footer size");
857 /* 160-bit SHA-1 over the content of the index file before this checksum. */
858 git_oid_mkraw(&checksum_expected
, (const unsigned char *)buffer
);
860 if (git_oid_cmp(&checksum_calculated
, &checksum_expected
) != 0)
861 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Calculated checksum does not match expected checksum");
865 /* force sorting in the vector: the entries are
866 * assured to be sorted on the index */
867 index
->entries
.sorted
= 1;
871 static int is_index_extended(git_index
*index
)
873 unsigned int i
, extended
;
877 for (i
= 0; i
< index
->entries
.length
; ++i
) {
878 git_index_entry
*entry
;
879 entry
= git_vector_get(&index
->entries
, i
);
880 entry
->flags
&= ~GIT_IDXENTRY_EXTENDED
;
881 if (entry
->flags_extended
& GIT_IDXENTRY_EXTENDED_FLAGS
) {
883 entry
->flags
|= GIT_IDXENTRY_EXTENDED
;
889 static int write_disk_entry(git_filebuf
*file
, git_index_entry
*entry
)
891 struct entry_short
*ondisk
;
892 size_t path_len
, disk_size
;
895 path_len
= strlen(entry
->path
);
897 if (entry
->flags
& GIT_IDXENTRY_EXTENDED
)
898 disk_size
= long_entry_size(path_len
);
900 disk_size
= short_entry_size(path_len
);
902 if (git_filebuf_reserve(file
, (void **)&ondisk
, disk_size
) < GIT_SUCCESS
)
905 memset(ondisk
, 0x0, disk_size
);
907 ondisk
->ctime
.seconds
= htonl((unsigned long)entry
->ctime
.seconds
);
908 ondisk
->mtime
.seconds
= htonl((unsigned long)entry
->mtime
.seconds
);
909 ondisk
->ctime
.nanoseconds
= htonl(entry
->ctime
.nanoseconds
);
910 ondisk
->mtime
.nanoseconds
= htonl(entry
->mtime
.nanoseconds
);
911 ondisk
->dev
= htonl(entry
->dev
);
912 ondisk
->ino
= htonl(entry
->ino
);
913 ondisk
->mode
= htonl(entry
->mode
);
914 ondisk
->uid
= htonl(entry
->uid
);
915 ondisk
->gid
= htonl(entry
->gid
);
916 ondisk
->file_size
= htonl((unsigned long)entry
->file_size
);
918 git_oid_cpy(&ondisk
->oid
, &entry
->oid
);
920 ondisk
->flags
= htons(entry
->flags
);
922 if (entry
->flags
& GIT_IDXENTRY_EXTENDED
) {
923 struct entry_long
*ondisk_ext
;
924 ondisk_ext
= (struct entry_long
*)ondisk
;
925 ondisk_ext
->flags_extended
= htons(entry
->flags_extended
);
926 path
= ondisk_ext
->path
;
931 memcpy(path
, entry
->path
, path_len
);
936 static int write_entries(git_index
*index
, git_filebuf
*file
)
940 for (i
= 0; i
< index
->entries
.length
; ++i
) {
941 git_index_entry
*entry
;
942 entry
= git_vector_get(&index
->entries
, i
);
943 if (write_disk_entry(file
, entry
) < GIT_SUCCESS
)
950 static int write_index(git_index
*index
, git_filebuf
*file
)
952 int error
= GIT_SUCCESS
;
955 struct index_header header
;
959 assert(index
&& file
);
961 is_extended
= is_index_extended(index
);
963 header
.signature
= htonl(INDEX_HEADER_SIG
);
964 header
.version
= htonl(is_extended
? INDEX_VERSION_NUMBER_EXT
: INDEX_VERSION_NUMBER
);
965 header
.entry_count
= htonl(index
->entries
.length
);
967 git_filebuf_write(file
, &header
, sizeof(struct index_header
));
969 error
= write_entries(index
, file
);
970 if (error
< GIT_SUCCESS
)
971 return git__rethrow(error
, "Failed to write index");
973 /* TODO: write extensions (tree cache) */
975 /* get out the hash for all the contents we've appended to the file */
976 git_filebuf_hash(&hash_final
, file
);
978 /* write it at the end of the file */
979 git_filebuf_write(file
, hash_final
.id
, GIT_OID_RAWSZ
);
981 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write index");