Fix some "implicit declaration of function" warnings
[libgit2.git] / src / index.c
blobccf3e30f45fb7d2aee64647249617a2c211d0f2f
1 /*
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.
26 #include <stddef.h>
28 #include "common.h"
29 #include "index.h"
30 #include "hash.h"
31 #include "git/odb.h"
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;
51 struct index_header {
52 uint32_t signature;
53 uint32_t version;
54 uint32_t entry_count;
57 struct index_extension {
58 char signature[4];
59 uint32_t extension_size;
62 struct entry_short {
63 git_index_time ctime;
64 git_index_time mtime;
65 uint32_t dev;
66 uint32_t ino;
67 uint32_t mode;
68 uint32_t uid;
69 uint32_t gid;
70 uint32_t file_size;
71 git_oid oid;
72 uint16_t flags;
73 char path[1]; /* arbritrary length */
76 struct entry_long {
77 git_index_time ctime;
78 git_index_time mtime;
79 uint32_t dev;
80 uint32_t ino;
81 uint32_t mode;
82 uint32_t uid;
83 uint32_t gid;
84 uint32_t file_size;
85 git_oid oid;
86 uint16_t flags;
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)
107 git_index *index;
109 if (index_path == NULL)
110 return NULL;
112 index = git__malloc(sizeof(git_index));
113 if (index == NULL)
114 return NULL;
116 memset(index, 0x0, sizeof(git_index));
118 index->index_file_path = git__strdup(index_path);
119 if (index->index_file_path == NULL) {
120 free(index);
121 return NULL;
124 /* Check if index file is stored on disk already */
125 if (gitfo_exists(index->index_file_path) == 0)
126 index->on_disk = 1;
128 return index;
131 void git_index_clear(git_index *index)
133 unsigned int i;
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;
139 index->sorted = 1;
141 git_index_tree__free(index->tree);
142 index->tree = NULL;
145 void git_index_free(git_index *index)
147 free(index->entries);
148 index->entries = NULL;
149 free(index->index_file_path);
150 free(index);
154 int git_index_read(git_index *index)
156 struct stat indexst;
157 int error = 0;
159 if (index->index_file_path == NULL)
160 return GIT_ERROR;
162 if (!index->on_disk || gitfo_exists(index->index_file_path) < 0) {
163 git_index_clear(index);
164 index->on_disk = 0;
165 return 0;
168 if (gitfo_stat(index->index_file_path, &indexst) < 0)
169 return GIT_EOSERR;
171 if (indexst.st_mtime != index->last_modified) {
173 gitfo_buf buffer;
175 if (gitfo_read_file(&buffer, index->index_file_path) < 0)
176 return GIT_EOSERR;
178 git_index_clear(index);
179 error = git_index__parse(index, buffer.data, buffer.len);
181 if (error == 0)
182 index->last_modified = indexst.st_mtime;
184 gitfo_free_buf(&buffer);
187 return error;
190 int git_index_write(git_index *index)
192 git_filelock file;
193 struct stat indexst;
195 if (!index->sorted)
196 git_index__sort(index);
198 if (git_filelock_init(&file, index->index_file_path) < 0)
199 return GIT_EOSERR;
201 if (git_filelock_lock(&file, 0) < 0)
202 return GIT_EOSERR;
204 if (git_index__write(index, &file) < 0) {
205 git_filelock_unlock(&file);
206 return GIT_EOSERR;
209 if (git_filelock_commit(&file) < 0)
210 return GIT_EOSERR;
212 if (gitfo_stat(index->index_file_path, &indexst) == 0) {
213 index->last_modified = indexst.st_mtime;
214 index->on_disk = 1;
217 return 0;
220 int git_index_add(git_index *index, const char *filename, int stage)
222 git_index_entry entry;
223 size_t path_length;
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;
231 else
232 entry.flags |= path_length;
234 if (stage < 0 || stage > 3)
235 return GIT_ERROR;
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;
247 int i, j;
249 if (index->sorted)
250 return;
252 for (i = 1; i < (int)index->entry_count; ++i) {
254 memcpy(&pivot, &index->entries[i], sizeof(git_index_entry));
255 j = i - 1;
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));
259 j = j - 1;
262 memcpy(&index->entries[j + 1], &pivot, sizeof(git_index_entry));
265 index->sorted = 1;
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;
275 size_t new_size;
277 new_size = (unsigned int)(index->entries_size * 1.5f);
278 if ((new_entries = git__malloc(new_size * sizeof(git_index_entry))) == NULL)
279 return GIT_ENOMEM;
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));
292 index->sorted = 0;
294 return 0;
297 int git_index__remove_pos(git_index *index, unsigned int position)
299 git_index_entry *offset;
300 size_t copy_size;
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);
308 return 0;
311 int git_index_find(git_index *index, const char *path)
313 int low = 0, high = index->entry_count;
315 if (!index->sorted)
316 git_index__sort(index);
318 while (low < high) {
319 int mid = (low + high) >> 1;
320 int cmp = strcmp(path, index->entries[mid].path);
322 if (cmp < 0)
323 high = mid;
325 else if (cmp == 0) {
327 while (mid > 0 && strcmp(path, index->entries[mid - 1].path) == 0)
328 mid--;
330 return mid;
332 } else
333 low = mid + 1;
336 return GIT_ENOTFOUND; /* NOT FOUND */
339 void git_index_tree__free(git_index_tree *tree)
341 unsigned int i;
343 if (tree == NULL)
344 return;
346 for (i = 0; i < tree->children_count; ++i)
347 git_index_tree__free(tree->children[i]);
349 free(tree->name);
350 free(tree->children);
351 free(tree);
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)
361 return 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)
369 goto error_cleanup;
371 /* NUL-terminated tree name */
372 tree->name = git__strdup(name_start);
373 if (++buffer >= buffer_end)
374 goto error_cleanup;
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)
379 goto error_cleanup;
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)
384 goto error_cleanup;
386 /* 160-bit SHA-1 for this tree and it's children */
387 if (buffer + GIT_OID_RAWSZ > buffer_end)
388 goto error_cleanup;
390 git_oid_mkraw(&tree->oid, (const unsigned char *)buffer);
391 buffer += GIT_OID_RAWSZ;
393 /* Parse children: */
394 if (tree->children_count > 0) {
395 unsigned int i;
397 tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *));
398 if (tree->children == NULL)
399 goto error_cleanup;
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)
405 goto error_cleanup;
409 *buffer_in = buffer;
410 return tree;
412 error_cleanup:
413 git_index_tree__free(tree);
414 return NULL;
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;
428 uint16_t flags_raw;
429 const char *path_ptr;
430 const struct entry_short *source;
432 if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
433 return 0;
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);
456 } else
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)
468 return 0;
470 path_length = path_end - path_ptr;
473 if (dest->flags & GIT_IDXENTRY_EXTENDED)
474 entry_size = long_entry_size(path_length);
475 else
476 entry_size = short_entry_size(path_length);
478 if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
479 return 0;
481 dest->path = git__strdup(path_ptr);
483 return entry_size;
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);
500 return 0;
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;
507 size_t total_size;
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)
517 return 0;
519 /* optional extension */
520 if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
521 /* tree cache */
522 if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
524 if (git_index__parse_tree(index, buffer + 8, dest.extension_size) < 0)
525 return 0;
527 } else {
528 /* we cannot handle non-ignorable extensions;
529 * in fact they aren't even defined in the standard */
530 return 0;
533 return total_size;
536 int git_index__parse(git_index *index, const char *buffer, size_t buffer_size)
538 unsigned int i;
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);
556 /* Parse header */
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) {
574 size_t entry_size;
575 entry_size = git_index__parse_entry(&index->entries[i], buffer, buffer_size);
577 /* 0 bytes read means an object corruption */
578 if (entry_size == 0)
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;
606 #undef seek_forward
608 return 0;
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};
615 int error = 0;
616 unsigned int i;
618 git_hash_ctx *digest;
619 git_oid hash_final;
621 if (index == NULL || file == NULL || !file->is_locked)
622 return GIT_ERROR;
624 if ((digest = git_hash_new_ctx()) == NULL)
625 return GIT_ERROR;
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);
672 } else
673 padding = short_entry_padding(path_length);
675 WRITE_BYTES(entry->path, path_length);
676 WRITE_BYTES(NULL_BYTES, padding);
679 #undef WRITE_WORD
680 #undef WRITE_BYTES
681 #undef WRITE_SHORT
682 #undef WRITE_FLAGS
684 /* TODO: write extensions (tree cache) */
686 git_hash_final(&hash_final, digest);
687 git_filelock_write(file, hash_final.id, GIT_OID_RAWSZ);
689 return error;