2 * Copyright (C) 2009-2011 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
11 #include "repository.h"
15 #include "git2/blob.h"
17 #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
18 #define short_entry_size(len) entry_size(struct entry_short, len)
19 #define long_entry_size(len) entry_size(struct entry_long, len)
21 #define minimal_entry_size (offsetof(struct entry_short, path))
23 static const size_t INDEX_FOOTER_SIZE
= GIT_OID_RAWSZ
;
24 static const size_t INDEX_HEADER_SIZE
= 12;
26 static const unsigned int INDEX_VERSION_NUMBER
= 2;
27 static const unsigned int INDEX_VERSION_NUMBER_EXT
= 3;
29 static const unsigned int INDEX_HEADER_SIG
= 0x44495243;
30 static const char INDEX_EXT_TREECACHE_SIG
[] = {'T', 'R', 'E', 'E'};
31 static const char INDEX_EXT_UNMERGED_SIG
[] = {'R', 'E', 'U', 'C'};
39 struct index_extension
{
41 uint32_t extension_size
;
50 struct entry_time ctime
;
51 struct entry_time mtime
;
60 char path
[1]; /* arbitrary length */
64 struct entry_time ctime
;
65 struct entry_time mtime
;
74 uint16_t flags_extended
;
75 char path
[1]; /* arbitrary length */
78 /* local declarations */
79 static size_t read_extension(git_index
*index
, const char *buffer
, size_t buffer_size
);
80 static size_t read_entry(git_index_entry
*dest
, const void *buffer
, size_t buffer_size
);
81 static int read_header(struct index_header
*dest
, const void *buffer
);
83 static int read_tree(git_index
*index
, const char *buffer
, size_t buffer_size
);
84 static int read_tree_internal(git_index_tree
**, const char **, const char *, git_index_tree
*);
86 static int parse_index(git_index
*index
, const char *buffer
, size_t buffer_size
);
87 static int is_index_extended(git_index
*index
);
88 static int write_index(git_index
*index
, git_filebuf
*file
);
90 static int index_srch(const void *key
, const void *array_member
)
92 const git_index_entry
*entry
= array_member
;
94 return strcmp(key
, entry
->path
);
97 static int index_cmp(const void *a
, const void *b
)
99 const git_index_entry
*entry_a
= a
;
100 const git_index_entry
*entry_b
= b
;
102 return strcmp(entry_a
->path
, entry_b
->path
);
105 static int unmerged_srch(const void *key
, const void *array_member
)
107 const git_index_entry_unmerged
*entry
= array_member
;
109 return strcmp(key
, entry
->path
);
112 static int unmerged_cmp(const void *a
, const void *b
)
114 const git_index_entry_unmerged
*info_a
= a
;
115 const git_index_entry_unmerged
*info_b
= b
;
117 return strcmp(info_a
->path
, info_b
->path
);
120 static unsigned int index_create_mode(unsigned int mode
)
124 if (S_ISDIR(mode
) || (mode
& S_IFMT
) == (S_IFLNK
| S_IFDIR
))
125 return (S_IFLNK
| S_IFDIR
);
126 return S_IFREG
| ((mode
& 0100) ? 0755 : 0644);
129 static int index_initialize(git_index
**index_out
, git_repository
*owner
, const char *index_path
)
133 assert(index_out
&& index_path
);
135 index
= git__malloc(sizeof(git_index
));
139 memset(index
, 0x0, sizeof(git_index
));
141 index
->index_file_path
= git__strdup(index_path
);
142 if (index
->index_file_path
== NULL
) {
147 index
->repository
= owner
;
149 git_vector_init(&index
->entries
, 32, index_cmp
);
151 /* Check if index file is stored on disk already */
152 if (git_futils_exists(index
->index_file_path
) == 0)
156 return git_index_read(index
);
159 int git_index_open(git_index
**index_out
, const char *index_path
)
161 return index_initialize(index_out
, NULL
, index_path
);
165 * Moved from `repository.c`
167 int git_repository_index(git_index
**index_out
, git_repository
*repo
)
170 return git__throw(GIT_EBAREINDEX
, "Failed to open index. Repository is bare");
172 return index_initialize(index_out
, repo
, repo
->path_index
);
175 void git_index_free(git_index
*index
)
180 git_index_clear(index
);
181 git_vector_free(&index
->entries
);
182 git_vector_free(&index
->unmerged
);
184 free(index
->index_file_path
);
188 static void free_tree(git_index_tree
*tree
)
195 for (i
= 0; i
< tree
->children_count
; ++i
)
196 free_tree(tree
->children
[i
]);
199 free(tree
->children
);
203 void git_index_clear(git_index
*index
)
209 for (i
= 0; i
< index
->entries
.length
; ++i
) {
211 e
= git_vector_get(&index
->entries
, i
);
216 for (i
= 0; i
< index
->unmerged
.length
; ++i
) {
217 git_index_entry_unmerged
*e
;
218 e
= git_vector_get(&index
->unmerged
, i
);
223 git_vector_clear(&index
->entries
);
224 git_vector_clear(&index
->unmerged
);
225 index
->last_modified
= 0;
227 free_tree(index
->tree
);
231 int git_index_read(git_index
*index
)
233 int error
= GIT_SUCCESS
, updated
;
234 git_fbuffer buffer
= GIT_FBUFFER_INIT
;
237 assert(index
->index_file_path
);
239 if (!index
->on_disk
|| git_futils_exists(index
->index_file_path
) < 0) {
240 git_index_clear(index
);
245 /* We don't want to update the mtime if we fail to parse the index */
246 mtime
= index
->last_modified
;
247 error
= git_futils_readbuffer_updated(&buffer
, index
->index_file_path
, &mtime
, &updated
);
248 if (error
< GIT_SUCCESS
)
249 return git__rethrow(error
, "Failed to read index");
252 git_index_clear(index
);
253 error
= parse_index(index
, buffer
.data
, buffer
.len
);
255 if (error
== GIT_SUCCESS
)
256 index
->last_modified
= mtime
;
258 git_futils_freebuffer(&buffer
);
261 if (error
< GIT_SUCCESS
)
262 return git__rethrow(error
, "Failed to parse index");
266 int git_index_write(git_index
*index
)
272 git_vector_sort(&index
->entries
);
274 if ((error
= git_filebuf_open(&file
, index
->index_file_path
, GIT_FILEBUF_HASH_CONTENTS
)) < GIT_SUCCESS
)
275 return git__rethrow(error
, "Failed to write index");
277 if ((error
= write_index(index
, &file
)) < GIT_SUCCESS
) {
278 git_filebuf_cleanup(&file
);
279 return git__rethrow(error
, "Failed to write index");
282 if ((error
= git_filebuf_commit(&file
)) < GIT_SUCCESS
)
283 return git__rethrow(error
, "Failed to write index");
285 if (p_stat(index
->index_file_path
, &indexst
) == 0) {
286 index
->last_modified
= indexst
.st_mtime
;
293 unsigned int git_index_entrycount(git_index
*index
)
296 return index
->entries
.length
;
299 unsigned int git_index_entrycount_unmerged(git_index
*index
)
302 return index
->unmerged
.length
;
305 git_index_entry
*git_index_get(git_index
*index
, unsigned int n
)
307 git_vector_sort(&index
->entries
);
308 return git_vector_get(&index
->entries
, n
);
311 static int index_entry_init(git_index_entry
**entry_out
, git_index
*index
, const char *rel_path
, int stage
)
313 git_index_entry
*entry
;
314 char full_path
[GIT_PATH_MAX
];
319 if (index
->repository
== NULL
)
320 return git__throw(GIT_EBAREINDEX
, "Failed to initialize entry. Repository is bare");
322 git_path_join(full_path
, index
->repository
->path_workdir
, rel_path
);
324 if (p_lstat(full_path
, &st
) < 0)
325 return git__throw(GIT_ENOTFOUND
, "Failed to initialize entry. '%s' cannot be opened", full_path
);
327 if (stage
< 0 || stage
> 3)
328 return git__throw(GIT_ERROR
, "Failed to initialize entry. Invalid stage %i", stage
);
330 /* write the blob to disk and get the oid */
331 if ((error
= git_blob_create_fromfile(&oid
, index
->repository
, rel_path
)) < GIT_SUCCESS
)
332 return git__rethrow(error
, "Failed to initialize index entry");
334 entry
= git__malloc(sizeof(git_index_entry
));
337 memset(entry
, 0x0, sizeof(git_index_entry
));
339 entry
->ctime
.seconds
= (git_time_t
)st
.st_ctime
;
340 entry
->mtime
.seconds
= (git_time_t
)st
.st_mtime
;
341 /* entry.mtime.nanoseconds = st.st_mtimensec; */
342 /* entry.ctime.nanoseconds = st.st_ctimensec; */
343 entry
->dev
= st
.st_rdev
;
344 entry
->ino
= st
.st_ino
;
345 entry
->mode
= index_create_mode(st
.st_mode
);
346 entry
->uid
= st
.st_uid
;
347 entry
->gid
= st
.st_gid
;
348 entry
->file_size
= st
.st_size
;
351 entry
->flags
|= (stage
<< GIT_IDXENTRY_STAGESHIFT
);
352 entry
->path
= git__strdup(rel_path
);
353 if (entry
->path
== NULL
) {
362 static git_index_entry
*index_entry_dup(const git_index_entry
*source_entry
)
364 git_index_entry
*entry
;
366 entry
= git__malloc(sizeof(git_index_entry
));
370 memcpy(entry
, source_entry
, sizeof(git_index_entry
));
372 /* duplicate the path string so we own it */
373 entry
->path
= git__strdup(entry
->path
);
380 static void index_entry_free(git_index_entry
*entry
)
388 static int index_insert(git_index
*index
, git_index_entry
*entry
, int replace
)
392 git_index_entry
**entry_array
;
394 assert(index
&& entry
);
396 if (entry
->path
== NULL
)
397 return git__throw(GIT_EMISSINGOBJDATA
, "Failed to insert into index. Entry has no path");
399 /* make sure that the path length flag is correct */
400 path_length
= strlen(entry
->path
);
402 entry
->flags
&= ~GIT_IDXENTRY_NAMEMASK
;
404 if (path_length
< GIT_IDXENTRY_NAMEMASK
)
405 entry
->flags
|= path_length
& GIT_IDXENTRY_NAMEMASK
;
407 entry
->flags
|= GIT_IDXENTRY_NAMEMASK
;;
410 * replacing is not requested: just insert entry at the end;
411 * the index is no longer sorted
414 if (git_vector_insert(&index
->entries
, entry
) < GIT_SUCCESS
)
420 /* look if an entry with this path already exists */
421 position
= git_index_find(index
, entry
->path
);
424 * if no entry exists add the entry at the end;
425 * the index is no longer sorted
427 if (position
== GIT_ENOTFOUND
) {
428 if (git_vector_insert(&index
->entries
, entry
) < GIT_SUCCESS
)
434 /* exists, replace it */
435 entry_array
= (git_index_entry
**) index
->entries
.contents
;
436 free(entry_array
[position
]->path
);
437 free(entry_array
[position
]);
438 entry_array
[position
] = entry
;
443 static int index_add(git_index
*index
, const char *path
, int stage
, int replace
)
445 git_index_entry
*entry
= NULL
;
448 ret
= index_entry_init(&entry
, index
, path
, stage
);
452 ret
= index_insert(index
, entry
, replace
);
458 index_entry_free(entry
);
459 return git__rethrow(ret
, "Failed to append to index");
462 int git_index_add(git_index
*index
, const char *path
, int stage
)
464 return index_add(index
, path
, stage
, 1);
467 int git_index_append(git_index
*index
, const char *path
, int stage
)
469 return index_add(index
, path
, stage
, 0);
472 static int index_add2(git_index
*index
, const git_index_entry
*source_entry
,
475 git_index_entry
*entry
= NULL
;
478 entry
= index_entry_dup(source_entry
);
484 ret
= index_insert(index
, entry
, replace
);
490 index_entry_free(entry
);
491 return git__rethrow(ret
, "Failed to append to index");
494 int git_index_add2(git_index
*index
, const git_index_entry
*source_entry
)
496 return index_add2(index
, source_entry
, 1);
499 int git_index_append2(git_index
*index
, const git_index_entry
*source_entry
)
501 return index_add2(index
, source_entry
, 1);
504 int git_index_remove(git_index
*index
, int position
)
506 git_vector_sort(&index
->entries
);
507 return git_vector_remove(&index
->entries
, (unsigned int)position
);
510 int git_index_find(git_index
*index
, const char *path
)
512 return git_vector_bsearch2(&index
->entries
, index_srch
, path
);
515 void git_index_uniq(git_index
*index
)
517 git_vector_uniq(&index
->entries
);
520 const git_index_entry_unmerged
*git_index_get_unmerged_bypath(git_index
*index
, const char *path
)
523 assert(index
&& path
);
525 if (!index
->unmerged
.length
)
528 if ((pos
= git_vector_bsearch2(&index
->unmerged
, unmerged_srch
, path
)) < GIT_SUCCESS
)
531 return git_vector_get(&index
->unmerged
, pos
);
534 const git_index_entry_unmerged
*git_index_get_unmerged_byindex(git_index
*index
, unsigned int n
)
537 return git_vector_get(&index
->unmerged
, n
);
541 static int read_tree_internal(git_index_tree
**out
,
542 const char **buffer_in
, const char *buffer_end
, git_index_tree
*parent
)
544 git_index_tree
*tree
;
545 const char *name_start
, *buffer
;
547 int error
= GIT_SUCCESS
;
549 if ((tree
= git__malloc(sizeof(git_index_tree
))) == NULL
)
552 memset(tree
, 0x0, sizeof(git_index_tree
));
553 tree
->parent
= parent
;
555 buffer
= name_start
= *buffer_in
;
557 if ((buffer
= memchr(buffer
, '\0', buffer_end
- buffer
)) == NULL
) {
558 error
= GIT_EOBJCORRUPTED
;
562 /* NUL-terminated tree name */
563 tree
->name
= git__strdup(name_start
);
564 if (tree
->name
== NULL
) {
569 if (++buffer
>= buffer_end
) {
570 error
= GIT_EOBJCORRUPTED
;
574 /* Blank-terminated ASCII decimal number of entries in this tree */
575 if (git__strtol32(&count
, buffer
, &buffer
, 10) < GIT_SUCCESS
|| count
< -1) {
576 error
= GIT_EOBJCORRUPTED
;
580 /* Invalidated TREE. Free the tree but report success */
582 /* FIXME: return buffer_end or the end position for
583 * this single tree entry */
584 *buffer_in
= buffer_end
;
586 free_tree(tree
); /* Needs to be done manually */
590 tree
->entries
= count
;
592 if (*buffer
!= ' ' || ++buffer
>= buffer_end
) {
593 error
= GIT_EOBJCORRUPTED
;
597 /* Number of children of the tree, newline-terminated */
598 if (git__strtol32(&count
, buffer
, &buffer
, 10) < GIT_SUCCESS
||
600 error
= GIT_EOBJCORRUPTED
;
604 tree
->children_count
= count
;
606 if (*buffer
!= '\n' || ++buffer
>= buffer_end
) {
607 error
= GIT_EOBJCORRUPTED
;
611 /* 160-bit SHA-1 for this tree and it's children */
612 if (buffer
+ GIT_OID_RAWSZ
> buffer_end
) {
613 error
= GIT_EOBJCORRUPTED
;
617 git_oid_fromraw(&tree
->oid
, (const unsigned char *)buffer
);
618 buffer
+= GIT_OID_RAWSZ
;
620 /* Parse children: */
621 if (tree
->children_count
> 0) {
625 tree
->children
= git__malloc(tree
->children_count
* sizeof(git_index_tree
*));
626 if (tree
->children
== NULL
)
629 for (i
= 0; i
< tree
->children_count
; ++i
) {
630 err
= read_tree_internal(&tree
->children
[i
], &buffer
, buffer_end
, tree
);
632 if (err
< GIT_SUCCESS
)
646 static int read_tree(git_index
*index
, const char *buffer
, size_t buffer_size
)
648 const char *buffer_end
= buffer
+ buffer_size
;
651 error
= read_tree_internal(&index
->tree
, &buffer
, buffer_end
, NULL
);
653 if (buffer
< buffer_end
)
654 return GIT_EOBJCORRUPTED
;
659 static int read_unmerged(git_index
*index
, const char *buffer
, size_t size
)
665 git_vector_init(&index
->unmerged
, 16, unmerged_cmp
);
668 git_index_entry_unmerged
*lost
;
670 len
= strlen(buffer
) + 1;
672 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
674 if ((lost
= git__malloc(sizeof(git_index_entry_unmerged
))) == NULL
)
677 if (git_vector_insert(&index
->unmerged
, lost
) < GIT_SUCCESS
)
678 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
680 lost
->path
= git__strdup(buffer
);
687 for (i
= 0; i
< 3; i
++) {
690 if (git__strtol32(&tmp
, buffer
, &endptr
, 8) < GIT_SUCCESS
||
691 !endptr
|| endptr
== buffer
|| *endptr
|| (unsigned)tmp
> UINT_MAX
)
696 len
= (endptr
+ 1) - buffer
;
698 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
704 for (i
= 0; i
< 3; i
++) {
708 return git__throw(GIT_ERROR
, "Failed to read unmerged entries");
709 git_oid_fromraw(&lost
->oid
[i
], (const unsigned char *) buffer
);
718 static size_t read_entry(git_index_entry
*dest
, const void *buffer
, size_t buffer_size
)
720 size_t path_length
, entry_size
;
722 const char *path_ptr
;
723 const struct entry_short
*source
= buffer
;
725 if (INDEX_FOOTER_SIZE
+ minimal_entry_size
> buffer_size
)
728 memset(dest
, 0x0, sizeof(git_index_entry
));
730 dest
->ctime
.seconds
= (git_time_t
)ntohl(source
->ctime
.seconds
);
731 dest
->ctime
.nanoseconds
= ntohl(source
->ctime
.nanoseconds
);
732 dest
->mtime
.seconds
= (git_time_t
)ntohl(source
->mtime
.seconds
);
733 dest
->mtime
.nanoseconds
= ntohl(source
->mtime
.nanoseconds
);
734 dest
->dev
= ntohl(source
->dev
);
735 dest
->ino
= ntohl(source
->ino
);
736 dest
->mode
= ntohl(source
->mode
);
737 dest
->uid
= ntohl(source
->uid
);
738 dest
->gid
= ntohl(source
->gid
);
739 dest
->file_size
= ntohl(source
->file_size
);
740 git_oid_cpy(&dest
->oid
, &source
->oid
);
741 dest
->flags
= ntohs(source
->flags
);
743 if (dest
->flags
& GIT_IDXENTRY_EXTENDED
) {
744 const struct entry_long
*source_l
= (const struct entry_long
*)source
;
745 path_ptr
= source_l
->path
;
747 flags_raw
= ntohs(source_l
->flags_extended
);
748 memcpy(&dest
->flags_extended
, &flags_raw
, 2);
750 path_ptr
= source
->path
;
752 path_length
= dest
->flags
& GIT_IDXENTRY_NAMEMASK
;
754 /* if this is a very long string, we must find its
755 * real length without overflowing */
756 if (path_length
== 0xFFF) {
757 const char *path_end
;
759 path_end
= memchr(path_ptr
, '\0', buffer_size
);
760 if (path_end
== NULL
)
763 path_length
= path_end
- path_ptr
;
766 if (dest
->flags
& GIT_IDXENTRY_EXTENDED
)
767 entry_size
= long_entry_size(path_length
);
769 entry_size
= short_entry_size(path_length
);
771 if (INDEX_FOOTER_SIZE
+ entry_size
> buffer_size
)
774 dest
->path
= git__strdup(path_ptr
);
780 static int read_header(struct index_header
*dest
, const void *buffer
)
782 const struct index_header
*source
= buffer
;
784 dest
->signature
= ntohl(source
->signature
);
785 if (dest
->signature
!= INDEX_HEADER_SIG
)
786 return GIT_EOBJCORRUPTED
;
788 dest
->version
= ntohl(source
->version
);
789 if (dest
->version
!= INDEX_VERSION_NUMBER_EXT
&&
790 dest
->version
!= INDEX_VERSION_NUMBER
)
791 return GIT_EOBJCORRUPTED
;
793 dest
->entry_count
= ntohl(source
->entry_count
);
797 static size_t read_extension(git_index
*index
, const char *buffer
, size_t buffer_size
)
799 const struct index_extension
*source
;
800 struct index_extension dest
;
803 source
= (const struct index_extension
*)(buffer
);
805 memcpy(dest
.signature
, source
->signature
, 4);
806 dest
.extension_size
= ntohl(source
->extension_size
);
808 total_size
= dest
.extension_size
+ sizeof(struct index_extension
);
810 if (buffer_size
- total_size
< INDEX_FOOTER_SIZE
)
813 /* optional extension */
814 if (dest
.signature
[0] >= 'A' && dest
.signature
[0] <= 'Z') {
816 if (memcmp(dest
.signature
, INDEX_EXT_TREECACHE_SIG
, 4) == 0) {
817 if (read_tree(index
, buffer
+ 8, dest
.extension_size
) < GIT_SUCCESS
)
819 } else if (memcmp(dest
.signature
, INDEX_EXT_UNMERGED_SIG
, 4) == 0) {
820 if (read_unmerged(index
, buffer
+ 8, dest
.extension_size
) < GIT_SUCCESS
)
823 /* else, unsupported extension. We cannot parse this, but we can skip
824 * it by returning `total_size */
826 /* we cannot handle non-ignorable extensions;
827 * in fact they aren't even defined in the standard */
834 static int parse_index(git_index
*index
, const char *buffer
, size_t buffer_size
)
837 struct index_header header
;
838 git_oid checksum_calculated
, checksum_expected
;
840 #define seek_forward(_increase) { \
841 if (_increase >= buffer_size) \
842 return git__throw(GIT_EOBJCORRUPTED, "Failed to seek forward. Buffer size exceeded"); \
843 buffer += _increase; \
844 buffer_size -= _increase;\
847 if (buffer_size
< INDEX_HEADER_SIZE
+ INDEX_FOOTER_SIZE
)
848 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Buffer too small");
850 /* Precalculate the SHA1 of the files's contents -- we'll match it to
851 * the provided SHA1 in the footer */
852 git_hash_buf(&checksum_calculated
, buffer
, buffer_size
- INDEX_FOOTER_SIZE
);
855 if (read_header(&header
, buffer
) < GIT_SUCCESS
)
856 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Header is corrupted");
858 seek_forward(INDEX_HEADER_SIZE
);
860 git_vector_clear(&index
->entries
);
862 /* Parse all the entries */
863 for (i
= 0; i
< header
.entry_count
&& buffer_size
> INDEX_FOOTER_SIZE
; ++i
) {
865 git_index_entry
*entry
;
867 entry
= git__malloc(sizeof(git_index_entry
));
871 entry_size
= read_entry(entry
, buffer
, buffer_size
);
873 /* 0 bytes read means an object corruption */
875 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Entry size is zero");
877 if (git_vector_insert(&index
->entries
, entry
) < GIT_SUCCESS
)
880 seek_forward(entry_size
);
883 if (i
!= header
.entry_count
)
884 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Header entries changed while parsing");
886 /* There's still space for some extensions! */
887 while (buffer_size
> INDEX_FOOTER_SIZE
) {
888 size_t extension_size
;
890 extension_size
= read_extension(index
, buffer
, buffer_size
);
892 /* see if we have read any bytes from the extension */
893 if (extension_size
== 0)
894 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Extension size is zero");
896 seek_forward(extension_size
);
899 if (buffer_size
!= INDEX_FOOTER_SIZE
)
900 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Buffer size does not match index footer size");
902 /* 160-bit SHA-1 over the content of the index file before this checksum. */
903 git_oid_fromraw(&checksum_expected
, (const unsigned char *)buffer
);
905 if (git_oid_cmp(&checksum_calculated
, &checksum_expected
) != 0)
906 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse index. Calculated checksum does not match expected checksum");
910 /* force sorting in the vector: the entries are
911 * assured to be sorted on the index */
912 index
->entries
.sorted
= 1;
916 static int is_index_extended(git_index
*index
)
918 unsigned int i
, extended
;
922 for (i
= 0; i
< index
->entries
.length
; ++i
) {
923 git_index_entry
*entry
;
924 entry
= git_vector_get(&index
->entries
, i
);
925 entry
->flags
&= ~GIT_IDXENTRY_EXTENDED
;
926 if (entry
->flags_extended
& GIT_IDXENTRY_EXTENDED_FLAGS
) {
928 entry
->flags
|= GIT_IDXENTRY_EXTENDED
;
934 static int write_disk_entry(git_filebuf
*file
, git_index_entry
*entry
)
936 struct entry_short
*ondisk
;
937 size_t path_len
, disk_size
;
940 path_len
= strlen(entry
->path
);
942 if (entry
->flags
& GIT_IDXENTRY_EXTENDED
)
943 disk_size
= long_entry_size(path_len
);
945 disk_size
= short_entry_size(path_len
);
947 if (git_filebuf_reserve(file
, (void **)&ondisk
, disk_size
) < GIT_SUCCESS
)
950 memset(ondisk
, 0x0, disk_size
);
953 * Yes, we have to truncate.
955 * The on-disk format for Index entries clearly defines
956 * the time and size fields to be 4 bytes each -- so even if
957 * we store these values with 8 bytes on-memory, they must
958 * be truncated to 4 bytes before writing to disk.
960 * In 2038 I will be either too dead or too rich to care about this
962 ondisk
->ctime
.seconds
= htonl((uint32_t)entry
->ctime
.seconds
);
963 ondisk
->mtime
.seconds
= htonl((uint32_t)entry
->mtime
.seconds
);
964 ondisk
->ctime
.nanoseconds
= htonl(entry
->ctime
.nanoseconds
);
965 ondisk
->mtime
.nanoseconds
= htonl(entry
->mtime
.nanoseconds
);
966 ondisk
->dev
= htonl(entry
->dev
);
967 ondisk
->ino
= htonl(entry
->ino
);
968 ondisk
->mode
= htonl(entry
->mode
);
969 ondisk
->uid
= htonl(entry
->uid
);
970 ondisk
->gid
= htonl(entry
->gid
);
971 ondisk
->file_size
= htonl((uint32_t)entry
->file_size
);
973 git_oid_cpy(&ondisk
->oid
, &entry
->oid
);
975 ondisk
->flags
= htons(entry
->flags
);
977 if (entry
->flags
& GIT_IDXENTRY_EXTENDED
) {
978 struct entry_long
*ondisk_ext
;
979 ondisk_ext
= (struct entry_long
*)ondisk
;
980 ondisk_ext
->flags_extended
= htons(entry
->flags_extended
);
981 path
= ondisk_ext
->path
;
986 memcpy(path
, entry
->path
, path_len
);
991 static int write_entries(git_index
*index
, git_filebuf
*file
)
995 for (i
= 0; i
< index
->entries
.length
; ++i
) {
996 git_index_entry
*entry
;
997 entry
= git_vector_get(&index
->entries
, i
);
998 if (write_disk_entry(file
, entry
) < GIT_SUCCESS
)
1005 static int write_index(git_index
*index
, git_filebuf
*file
)
1007 int error
= GIT_SUCCESS
;
1010 struct index_header header
;
1014 assert(index
&& file
);
1016 is_extended
= is_index_extended(index
);
1018 header
.signature
= htonl(INDEX_HEADER_SIG
);
1019 header
.version
= htonl(is_extended
? INDEX_VERSION_NUMBER_EXT
: INDEX_VERSION_NUMBER
);
1020 header
.entry_count
= htonl(index
->entries
.length
);
1022 git_filebuf_write(file
, &header
, sizeof(struct index_header
));
1024 error
= write_entries(index
, file
);
1025 if (error
< GIT_SUCCESS
)
1026 return git__rethrow(error
, "Failed to write index");
1028 /* TODO: write extensions (tree cache) */
1030 /* get out the hash for all the contents we've appended to the file */
1031 git_filebuf_hash(&hash_final
, file
);
1033 /* write it at the end of the file */
1034 git_filebuf_write(file
, hash_final
.id
, GIT_OID_RAWSZ
);
1036 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write index");
1039 int git_index_entry_stage(const git_index_entry
*entry
)
1041 return (entry
->flags
& GIT_IDXENTRY_STAGEMASK
) >> GIT_IDXENTRY_STAGESHIFT
;