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.
33 #define entry_padding(type, len) (8 - ((offsetof(type, path) + (len)) & 0x7))
34 #define short_entry_padding(len) entry_padding(struct entry_short, len)
35 #define long_entry_padding(len) entry_padding(struct entry_long, len)
37 #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
38 #define short_entry_size(len) entry_size(struct entry_short, len)
39 #define long_entry_size(len) entry_size(struct entry_long, len)
41 #define minimal_entry_size (offsetof(struct entry_short, path))
43 static const char INDEX_HEADER_SIG
[] = {'D', 'I', 'R', 'C'};
44 static const char INDEX_EXT_TREECACHE_SIG
[] = {'T', 'R', 'E', 'E'};
46 static const size_t INDEX_FOOTER_SIZE
= GIT_OID_RAWSZ
;
47 static const size_t INDEX_HEADER_SIZE
= 12;
49 static const unsigned int INDEX_VERSION_NUMBER
= 2;
57 struct index_extension
{
59 uint32_t extension_size
;
73 char path
[1]; /* arbritrary length */
87 uint16_t flags_extended
;
88 char path
[1]; /* arbritrary length */
91 /* local declarations */
92 size_t git_index__parse_extension(git_index
*index
, const char *buffer
, size_t buffer_size
);
93 size_t git_index__parse_entry(git_index_entry
*dest
, const void *buffer
, size_t buffer_size
);
94 int git_index__parse_treecache(git_index
*index
, const char *buffer
, size_t buffer_size
);
95 int git_index__parse_header(struct index_header
*dest
, const void *buffer
);
96 int git_index__parse(git_index
*index
, const char *buffer
, size_t buffer_size
);
98 int git_index__remove_pos(git_index
*index
, unsigned int position
);
99 int git_index__append(git_index
*index
, const git_index_entry
*entry
);
101 void git_index_tree__free(git_index_tree
*tree
);
102 git_index_tree
*git_index_tree__parse(const char **, const char *, git_index_tree
*);
105 git_index
*git_index_alloc(const char *index_path
)
109 if (index_path
== NULL
)
112 index
= git__malloc(sizeof(git_index
));
116 memset(index
, 0x0, sizeof(git_index
));
118 index
->index_file_path
= git__strdup(index_path
);
119 if (index
->index_file_path
== NULL
) {
124 /* Check if index file is stored on disk already */
125 if (gitfo_exists(index
->index_file_path
) == 0)
131 void git_index_clear(git_index
*index
)
134 for (i
= 0; i
< index
->entry_count
; ++i
)
135 free(index
->entries
[i
].path
);
137 index
->entry_count
= 0;
138 index
->last_modified
= 0;
141 git_index_tree__free(index
->tree
);
145 void git_index_free(git_index
*index
)
147 free(index
->entries
);
148 index
->entries
= NULL
;
149 free(index
->index_file_path
);
154 int git_index_read(git_index
*index
)
159 if (index
->index_file_path
== NULL
)
162 if (!index
->on_disk
|| gitfo_exists(index
->index_file_path
) < 0) {
163 git_index_clear(index
);
168 if (gitfo_stat(index
->index_file_path
, &indexst
) < 0)
171 if (indexst
.st_mtime
!= index
->last_modified
) {
175 if (gitfo_read_file(&buffer
, index
->index_file_path
) < 0)
178 git_index_clear(index
);
179 error
= git_index__parse(index
, buffer
.data
, buffer
.len
);
182 index
->last_modified
= indexst
.st_mtime
;
184 gitfo_free_buf(&buffer
);
190 int git_index_write(git_index
*index
)
196 git_index__sort(index
);
198 if (git_filelock_init(&file
, index
->index_file_path
) < 0)
201 if (git_filelock_lock(&file
, 0) < 0)
204 if (git_index__write(index
, &file
) < 0) {
205 git_filelock_unlock(&file
);
209 if (git_filelock_commit(&file
) < 0)
212 if (gitfo_stat(index
->index_file_path
, &indexst
) == 0) {
213 index
->last_modified
= indexst
.st_mtime
;
220 int git_index_add(git_index
*index
, const char *filename
, int stage
)
222 git_index_entry entry
;
225 memset(&entry
, 0x0, sizeof(git_index_entry
));
227 path_length
= strlen(filename
);
229 if (path_length
< GIT_IDXENTRY_NAMEMASK
)
230 entry
.flags
|= path_length
;
232 entry
.flags
|= path_length
;
234 if (stage
< 0 || stage
> 3)
237 entry
.flags
|= (stage
<< GIT_IDXENTRY_STAGESHIFT
);
239 entry
.path
= git__strdup(filename
);
241 return git_index__append(index
, &entry
);
244 void git_index__sort(git_index
*index
)
246 git_index_entry pivot
;
252 for (i
= 1; i
< (int)index
->entry_count
; ++i
) {
254 memcpy(&pivot
, &index
->entries
[i
], sizeof(git_index_entry
));
257 while (j
>= 0 && strcmp(pivot
.path
, index
->entries
[j
].path
) < 0) {
258 memcpy(&index
->entries
[j
+ 1], &index
->entries
[j
], sizeof(git_index_entry
));
262 memcpy(&index
->entries
[j
+ 1], &pivot
, sizeof(git_index_entry
));
268 int git_index__append(git_index
*index
, const git_index_entry
*source_entry
)
270 git_index_entry
*offset
;
272 /* Resize the entries array */
273 if (index
->entry_count
+ 1 > index
->entries_size
) {
274 git_index_entry
*new_entries
;
277 new_size
= (unsigned int)(index
->entries_size
* 1.5f
);
278 if ((new_entries
= git__malloc(new_size
* sizeof(git_index_entry
))) == NULL
)
281 memcpy(new_entries
, index
->entries
, index
->entry_count
* sizeof(git_index_entry
));
282 free(index
->entries
);
284 index
->entries_size
= new_size
;
285 index
->entries
= new_entries
;
288 offset
= &index
->entries
[index
->entry_count
];
289 index
->entry_count
++;
291 memcpy(offset
, source_entry
, sizeof(git_index_entry
));
297 int git_index__remove_pos(git_index
*index
, unsigned int position
)
299 git_index_entry
*offset
;
302 offset
= &index
->entries
[position
];
303 index
->entry_count
--;
304 copy_size
= (index
->entry_count
- position
) * sizeof(git_index_entry
);
306 memcpy(offset
, offset
+ sizeof(git_index_entry
), copy_size
);
311 int git_index_find(git_index
*index
, const char *path
)
313 int low
= 0, high
= index
->entry_count
;
316 git_index__sort(index
);
319 int mid
= (low
+ high
) >> 1;
320 int cmp
= strcmp(path
, index
->entries
[mid
].path
);
327 while (mid
> 0 && strcmp(path
, index
->entries
[mid
- 1].path
) == 0)
336 return GIT_ENOTFOUND
; /* NOT FOUND */
339 void git_index_tree__free(git_index_tree
*tree
)
346 for (i
= 0; i
< tree
->children_count
; ++i
)
347 git_index_tree__free(tree
->children
[i
]);
350 free(tree
->children
);
354 git_index_tree
*git_index_tree__parse(
355 const char **buffer_in
, const char *buffer_end
, git_index_tree
*parent
)
357 git_index_tree
*tree
;
358 const char *name_start
, *buffer
;
360 if ((tree
= git__malloc(sizeof(git_index_tree
))) == NULL
)
363 memset(tree
, 0x0, sizeof(git_index_tree
));
364 tree
->parent
= parent
;
366 buffer
= name_start
= *buffer_in
;
368 if ((buffer
= memchr(buffer
, '\0', buffer_end
- buffer
)) == NULL
)
371 /* NUL-terminated tree name */
372 tree
->name
= git__strdup(name_start
);
373 if (++buffer
>= buffer_end
)
376 /* Blank-terminated ASCII decimal number of entries in this tree */
377 tree
->entries
= strtol(buffer
, (char **)&buffer
, 10);
378 if (*buffer
!= ' ' || ++buffer
>= buffer_end
)
381 /* Number of children of the tree, newline-terminated */
382 tree
->children_count
= strtol(buffer
, (char **)&buffer
, 10);
383 if (*buffer
!= '\n' || ++buffer
>= buffer_end
)
386 /* 160-bit SHA-1 for this tree and it's children */
387 if (buffer
+ GIT_OID_RAWSZ
> buffer_end
)
390 git_oid_mkraw(&tree
->oid
, (const unsigned char *)buffer
);
391 buffer
+= GIT_OID_RAWSZ
;
393 /* Parse children: */
394 if (tree
->children_count
> 0) {
397 tree
->children
= git__malloc(tree
->children_count
* sizeof(git_index_tree
*));
398 if (tree
->children
== NULL
)
401 for (i
= 0; i
< tree
->children_count
; ++i
) {
402 tree
->children
[i
] = git_index_tree__parse(&buffer
, buffer_end
, tree
);
404 if (tree
->children
[i
] == NULL
)
413 git_index_tree__free(tree
);
417 int git_index__parse_tree(git_index
*index
, const char *buffer
, size_t buffer_size
)
419 const char *buffer_end
= buffer
+ buffer_size
;
421 index
->tree
= git_index_tree__parse(&buffer
, buffer_end
, NULL
);
422 return (index
->tree
!= NULL
&& buffer
== buffer_end
) ? 0 : GIT_EOBJCORRUPTED
;
425 size_t git_index__parse_entry(git_index_entry
*dest
, const void *buffer
, size_t buffer_size
)
427 size_t path_length
, entry_size
;
429 const char *path_ptr
;
430 const struct entry_short
*source
;
432 if (INDEX_FOOTER_SIZE
+ minimal_entry_size
> buffer_size
)
435 source
= (const struct entry_short
*)(buffer
);
437 dest
->ctime
.seconds
= ntohl(source
->ctime
.seconds
);
438 dest
->ctime
.nanoseconds
= ntohl(source
->ctime
.nanoseconds
);
439 dest
->mtime
.seconds
= ntohl(source
->mtime
.seconds
);
440 dest
->mtime
.nanoseconds
= ntohl(source
->mtime
.nanoseconds
);
441 dest
->dev
= ntohl(source
->dev
);
442 dest
->ino
= ntohl(source
->ino
);
443 dest
->mode
= ntohl(source
->mode
);
444 dest
->uid
= ntohl(source
->uid
);
445 dest
->gid
= ntohl(source
->gid
);
446 dest
->file_size
= ntohl(source
->file_size
);
447 git_oid_cpy(&dest
->oid
, &source
->oid
);
448 dest
->flags
= ntohs(source
->flags
);
450 if (dest
->flags
& GIT_IDXENTRY_EXTENDED
) {
451 struct entry_long
*source_l
= (struct entry_long
*)source
;
452 path_ptr
= source_l
->path
;
454 flags_raw
= ntohs(source_l
->flags_extended
);
455 memcpy(&dest
->flags_extended
, &flags_raw
, 2);
457 path_ptr
= source
->path
;
459 path_length
= dest
->flags
& GIT_IDXENTRY_NAMEMASK
;
461 /* if this is a very long string, we must find its
462 * real length without overflowing */
463 if (path_length
== 0xFFF) {
464 const char *path_end
;
466 path_end
= memchr(path_ptr
, '\0', buffer_size
);
467 if (path_end
== NULL
)
470 path_length
= path_end
- path_ptr
;
473 if (dest
->flags
& GIT_IDXENTRY_EXTENDED
)
474 entry_size
= long_entry_size(path_length
);
476 entry_size
= short_entry_size(path_length
);
478 if (INDEX_FOOTER_SIZE
+ entry_size
> buffer_size
)
481 dest
->path
= git__strdup(path_ptr
);
486 int git_index__parse_header(struct index_header
*dest
, const void *buffer
)
488 const struct index_header
*source
;
489 source
= (const struct index_header
*)(buffer
);
491 dest
->signature
= source
->signature
;
492 if (memcmp(&dest
->signature
, INDEX_HEADER_SIG
, 4) != 0)
493 return GIT_EOBJCORRUPTED
;
495 dest
->version
= ntohl(source
->version
);
496 if (dest
->version
!= INDEX_VERSION_NUMBER
)
497 return GIT_EOBJCORRUPTED
;
499 dest
->entry_count
= ntohl(source
->entry_count
);
503 size_t git_index__parse_extension(git_index
*index
, const char *buffer
, size_t buffer_size
)
505 const struct index_extension
*source
;
506 struct index_extension dest
;
509 source
= (const struct index_extension
*)(buffer
);
511 memcpy(dest
.signature
, source
->signature
, 4);
512 dest
.extension_size
= ntohl(source
->extension_size
);
514 total_size
= dest
.extension_size
+ sizeof(struct index_extension
);
516 if (buffer_size
- total_size
< INDEX_FOOTER_SIZE
)
519 /* optional extension */
520 if (dest
.signature
[0] >= 'A' && dest
.signature
[0] <= 'Z') {
522 if (memcmp(dest
.signature
, INDEX_EXT_TREECACHE_SIG
, 4) == 0) {
524 if (git_index__parse_tree(index
, buffer
+ 8, dest
.extension_size
) < 0)
528 /* we cannot handle non-ignorable extensions;
529 * in fact they aren't even defined in the standard */
536 int git_index__parse(git_index
*index
, const char *buffer
, size_t buffer_size
)
539 struct index_header header
;
540 git_oid checksum_calculated
, checksum_expected
;
542 #define seek_forward(_increase) { \
543 if (_increase >= buffer_size) \
544 return GIT_EOBJCORRUPTED; \
545 buffer += _increase; \
546 buffer_size -= _increase;\
549 if (buffer_size
< INDEX_HEADER_SIZE
+ INDEX_FOOTER_SIZE
)
550 return GIT_EOBJCORRUPTED
;
552 /* Precalculate the SHA1 of the files's contents -- we'll match it to
553 * the provided SHA1 in the footer */
554 git_hash_buf(&checksum_calculated
, (const void *)buffer
, buffer_size
- INDEX_FOOTER_SIZE
);
557 if (git_index__parse_header(&header
, buffer
) < 0)
558 return GIT_EOBJCORRUPTED
;
560 seek_forward(INDEX_HEADER_SIZE
);
562 index
->entry_count
= header
.entry_count
;
564 /* If there is already a entires array, reuse it if it can hold all the
565 * entries. If not, free and reallocate */
566 if (index
->entry_count
> index
->entries_size
) {
567 free(index
->entries
);
568 index
->entries_size
= (uint32_t)(index
->entry_count
* 1.3f
);
569 index
->entries
= git__malloc(index
->entries_size
* sizeof(git_index_entry
));
572 /* Parse all the entries */
573 for (i
= 0; i
< index
->entry_count
&& buffer_size
> INDEX_FOOTER_SIZE
; ++i
) {
575 entry_size
= git_index__parse_entry(&index
->entries
[i
], buffer
, buffer_size
);
577 /* 0 bytes read means an object corruption */
579 return GIT_EOBJCORRUPTED
;
581 seek_forward(entry_size
);
584 /* There's still space for some extensions! */
585 while (buffer_size
> INDEX_FOOTER_SIZE
) {
586 size_t extension_size
;
588 extension_size
= git_index__parse_extension(index
, buffer
, buffer_size
);
590 /* see if we have read any bytes from the extension */
591 if (extension_size
== 0)
592 return GIT_EOBJCORRUPTED
;
594 seek_forward(extension_size
);
597 if (buffer_size
!= INDEX_FOOTER_SIZE
)
598 return GIT_EOBJCORRUPTED
;
600 /* 160-bit SHA-1 over the content of the index file before this checksum. */
601 git_oid_mkraw(&checksum_expected
, (const unsigned char *)buffer
);
603 if (git_oid_cmp(&checksum_calculated
, &checksum_expected
) != 0)
604 return GIT_EOBJCORRUPTED
;
611 int git_index__write(git_index
*index
, git_filelock
*file
)
613 static const char NULL_BYTES
[] = {0, 0, 0, 0, 0, 0, 0, 0};
618 git_hash_ctx
*digest
;
621 if (index
== NULL
|| file
== NULL
|| !file
->is_locked
)
624 if ((digest
= git_hash_new_ctx()) == NULL
)
627 #define WRITE_WORD(_word) {\
628 uint32_t network_word = htonl((_word));\
629 git_filelock_write(file, &network_word, 4);\
630 git_hash_update(digest, &network_word, 4);\
633 #define WRITE_SHORT(_shrt) {\
634 uint16_t network_shrt = htons((_shrt));\
635 git_filelock_write(file, &network_shrt, 2);\
636 git_hash_update(digest, &network_shrt, 2);\
639 #define WRITE_BYTES(_bytes, _n) {\
640 git_filelock_write(file, _bytes, _n);\
641 git_hash_update(digest, _bytes, _n);\
644 WRITE_BYTES(INDEX_HEADER_SIG
, 4);
646 WRITE_WORD(INDEX_VERSION_NUMBER
);
647 WRITE_WORD(index
->entry_count
);
649 for (i
= 0; i
< index
->entry_count
; ++i
) {
650 git_index_entry
*entry
;
651 size_t path_length
, padding
;
653 entry
= &index
->entries
[i
];
654 path_length
= strlen(entry
->path
);
656 WRITE_WORD(entry
->ctime
.seconds
);
657 WRITE_WORD(entry
->ctime
.nanoseconds
);
658 WRITE_WORD(entry
->mtime
.seconds
);
659 WRITE_WORD(entry
->mtime
.nanoseconds
);
660 WRITE_WORD(entry
->dev
);
661 WRITE_WORD(entry
->ino
);
662 WRITE_WORD(entry
->mode
);
663 WRITE_WORD(entry
->uid
);
664 WRITE_WORD(entry
->gid
);
665 WRITE_WORD(entry
->file_size
);
666 WRITE_BYTES(entry
->oid
.id
, GIT_OID_RAWSZ
);
667 WRITE_SHORT(entry
->flags
);
669 if (entry
->flags
& GIT_IDXENTRY_EXTENDED
) {
670 WRITE_SHORT(entry
->flags_extended
);
671 padding
= long_entry_padding(path_length
);
673 padding
= short_entry_padding(path_length
);
675 WRITE_BYTES(entry
->path
, path_length
);
676 WRITE_BYTES(NULL_BYTES
, padding
);
684 /* TODO: write extensions (tree cache) */
686 git_hash_final(&hash_final
, digest
);
687 git_filelock_write(file
, hash_final
.id
, GIT_OID_RAWSZ
);