index.c 95.2 KB
Newer Older
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
3
 *
Vicent Marti committed
4 5
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
6 7
 */

8 9
#include "index.h"

10 11
#include <stddef.h>

12
#include "repository.h"
13
#include "tree.h"
14
#include "tree-cache.h"
15
#include "hash.h"
16 17
#include "iterator.h"
#include "pathspec.h"
18
#include "ignore.h"
19
#include "blob.h"
20
#include "idxmap.h"
21
#include "diff.h"
David Turner committed
22
#include "varint.h"
23
#include "path.h"
24

25
#include "git2/odb.h"
26
#include "git2/oid.h"
27
#include "git2/blob.h"
28
#include "git2/config.h"
29
#include "git2/sys/index.h"
30

31 32 33 34
static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
				  unsigned int flags,
				  git_index_matched_path_cb cb, void *payload);

35 36
static const size_t INDEX_HEADER_SIZE = 12;

David Turner committed
37 38
static const unsigned int INDEX_VERSION_NUMBER_DEFAULT = 2;
static const unsigned int INDEX_VERSION_NUMBER_LB = 2;
39
static const unsigned int INDEX_VERSION_NUMBER_EXT = 3;
David Turner committed
40 41
static const unsigned int INDEX_VERSION_NUMBER_COMP = 4;
static const unsigned int INDEX_VERSION_NUMBER_UB = 4;
42 43 44

static const unsigned int INDEX_HEADER_SIG = 0x44495243;
static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};
45
static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'};
Edward Thomson committed
46
static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'};
47

48 49
#define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx)))

50 51 52 53 54 55 56 57 58 59 60
struct index_header {
	uint32_t signature;
	uint32_t version;
	uint32_t entry_count;
};

struct index_extension {
	char signature[4];
	uint32_t extension_size;
};

61 62 63 64 65
struct entry_time {
	uint32_t seconds;
	uint32_t nanoseconds;
};

66
struct entry_common {
67 68
	struct entry_time ctime;
	struct entry_time mtime;
69 70 71 72 73 74 75 76
	uint32_t dev;
	uint32_t ino;
	uint32_t mode;
	uint32_t uid;
	uint32_t gid;
	uint32_t file_size;
};

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#define entry_short(oid_size)                        \
	struct {                                     \
		struct entry_common common;          \
		unsigned char oid[oid_size];         \
		uint16_t flags;                      \
		char path[1]; /* arbitrary length */ \
	}

#define entry_long(oid_size)                         \
	struct {                                     \
		struct entry_common common;          \
		unsigned char oid[oid_size];         \
		uint16_t flags;                      \
		uint16_t flags_extended;             \
		char path[1]; /* arbitrary length */ \
	}

typedef entry_short(GIT_OID_SHA1_SIZE) index_entry_short_sha1;
typedef entry_long(GIT_OID_SHA1_SIZE) index_entry_long_sha1;

#ifdef GIT_EXPERIMENTAL_SHA256
typedef entry_short(GIT_OID_SHA256_SIZE) index_entry_short_sha256;
typedef entry_long(GIT_OID_SHA256_SIZE) index_entry_long_sha256;
#endif

#undef entry_short
#undef entry_long
104

Edward Thomson committed
105 106
struct entry_srch_key {
	const char *path;
107
	size_t pathlen;
Edward Thomson committed
108 109 110
	int stage;
};

111 112 113 114 115 116 117 118 119 120 121 122
struct entry_internal {
	git_index_entry entry;
	size_t pathlen;
	char path[GIT_FLEX_ARRAY];
};

struct reuc_entry_internal {
	git_index_reuc_entry entry;
	size_t pathlen;
	char path[GIT_FLEX_ARRAY];
};

123 124
bool git_index__enforce_unsaved_safety = false;

125
/* local declarations */
126
static int read_extension(size_t *read_len, git_index *index, size_t checksum_size, const char *buffer, size_t buffer_size);
127 128
static int read_header(struct index_header *dest, const void *buffer);

129
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
130
static bool is_index_extended(git_index *index);
131
static int write_index(unsigned char checksum[GIT_HASH_MAX_SIZE], size_t *checksum_size, git_index *index, git_filebuf *file);
132

133
static void index_entry_free(git_index_entry *entry);
Edward Thomson committed
134 135
static void index_entry_reuc_free(git_index_reuc_entry *reuc);

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
GIT_INLINE(int) index_map_set(git_idxmap *map, git_index_entry *e, bool ignore_case)
{
	if (ignore_case)
		return git_idxmap_icase_set((git_idxmap_icase *) map, e, e);
	else
		return git_idxmap_set(map, e, e);
}

GIT_INLINE(int) index_map_delete(git_idxmap *map, git_index_entry *e, bool ignore_case)
{
	if (ignore_case)
		return git_idxmap_icase_delete((git_idxmap_icase *) map, e);
	else
		return git_idxmap_delete(map, e);
}

152 153 154 155 156 157 158 159
GIT_INLINE(int) index_map_resize(git_idxmap *map, size_t count, bool ignore_case)
{
	if (ignore_case)
		return git_idxmap_icase_resize((git_idxmap_icase *) map, count);
	else
		return git_idxmap_resize(map, count);
}

160
int git_index_entry_srch(const void *key, const void *array_member)
161
{
Edward Thomson committed
162
	const struct entry_srch_key *srch_key = key;
163
	const struct entry_internal *entry = array_member;
164 165
	int cmp;
	size_t len1, len2, len;
166

167 168
	len1 = srch_key->pathlen;
	len2 = entry->pathlen;
169
	len = len1 < len2 ? len1 : len2;
Edward Thomson committed
170

171 172 173 174 175 176 177
	cmp = memcmp(srch_key->path, entry->path, len);
	if (cmp)
		return cmp;
	if (len1 < len2)
		return -1;
	if (len1 > len2)
		return 1;
Edward Thomson committed
178

179
	if (srch_key->stage != GIT_INDEX_STAGE_ANY)
180
		return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
181 182

	return 0;
183 184
}

185
int git_index_entry_isrch(const void *key, const void *array_member)
186
{
Edward Thomson committed
187
	const struct entry_srch_key *srch_key = key;
188
	const struct entry_internal *entry = array_member;
189 190
	int cmp;
	size_t len1, len2, len;
Edward Thomson committed
191

192 193
	len1 = srch_key->pathlen;
	len2 = entry->pathlen;
194
	len = len1 < len2 ? len1 : len2;
Edward Thomson committed
195

196
	cmp = strncasecmp(srch_key->path, entry->path, len);
Edward Thomson committed
197

198 199 200 201 202 203 204 205
	if (cmp)
		return cmp;
	if (len1 < len2)
		return -1;
	if (len1 > len2)
		return 1;

	if (srch_key->stage != GIT_INDEX_STAGE_ANY)
206
		return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
207 208

	return 0;
Edward Thomson committed
209 210
}

211
static int index_entry_srch_path(const void *path, const void *array_member)
Edward Thomson committed
212
{
213 214
	const git_index_entry *entry = array_member;

Edward Thomson committed
215 216 217
	return strcmp((const char *)path, entry->path);
}

218
static int index_entry_isrch_path(const void *path, const void *array_member)
Edward Thomson committed
219 220 221 222
{
	const git_index_entry *entry = array_member;

	return strcasecmp((const char *)path, entry->path);
223 224
}

225
int git_index_entry_cmp(const void *a, const void *b)
226
{
Edward Thomson committed
227
	int diff;
228 229
	const git_index_entry *entry_a = a;
	const git_index_entry *entry_b = b;
230

Edward Thomson committed
231 232 233
	diff = strcmp(entry_a->path, entry_b->path);

	if (diff == 0)
234
		diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
Edward Thomson committed
235 236

	return diff;
237 238
}

239
int git_index_entry_icmp(const void *a, const void *b)
240
{
Edward Thomson committed
241
	int diff;
242 243 244
	const git_index_entry *entry_a = a;
	const git_index_entry *entry_b = b;

Edward Thomson committed
245 246 247
	diff = strcasecmp(entry_a->path, entry_b->path);

	if (diff == 0)
248
		diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
Edward Thomson committed
249 250 251 252

	return diff;
}

Edward Thomson committed
253 254 255 256
static int conflict_name_cmp(const void *a, const void *b)
{
	const git_index_name_entry *name_a = a;
	const git_index_name_entry *name_b = b;
257

Edward Thomson committed
258 259
	if (name_a->ancestor && !name_b->ancestor)
		return 1;
260

Edward Thomson committed
261 262
	if (!name_a->ancestor && name_b->ancestor)
		return -1;
263

Edward Thomson committed
264 265
	if (name_a->ancestor)
		return strcmp(name_a->ancestor, name_b->ancestor);
266

Edward Thomson committed
267 268
	if (!name_a->ours || !name_b->ours)
		return 0;
269

Edward Thomson committed
270 271 272
	return strcmp(name_a->ours, name_b->ours);
}

Vicent Marti committed
273 274 275
/**
 * TODO: enable this when resolving case insensitive conflicts
 */
276
#if 0
Edward Thomson committed
277 278 279 280
static int conflict_name_icmp(const void *a, const void *b)
{
	const git_index_name_entry *name_a = a;
	const git_index_name_entry *name_b = b;
281

Edward Thomson committed
282 283
	if (name_a->ancestor && !name_b->ancestor)
		return 1;
284

Edward Thomson committed
285 286
	if (!name_a->ancestor && name_b->ancestor)
		return -1;
287

Edward Thomson committed
288 289
	if (name_a->ancestor)
		return strcasecmp(name_a->ancestor, name_b->ancestor);
290

Edward Thomson committed
291 292
	if (!name_a->ours || !name_b->ours)
		return 0;
293

Edward Thomson committed
294 295
	return strcasecmp(name_a->ours, name_b->ours);
}
296
#endif
Edward Thomson committed
297

Edward Thomson committed
298 299 300 301 302
static int reuc_srch(const void *key, const void *array_member)
{
	const git_index_reuc_entry *reuc = array_member;

	return strcmp(key, reuc->path);
303 304
}

Edward Thomson committed
305
static int reuc_isrch(const void *key, const void *array_member)
306
{
Edward Thomson committed
307
	const git_index_reuc_entry *reuc = array_member;
308

Edward Thomson committed
309
	return strcasecmp(key, reuc->path);
310 311
}

Edward Thomson committed
312
static int reuc_cmp(const void *a, const void *b)
313
{
Edward Thomson committed
314 315
	const git_index_reuc_entry *info_a = a;
	const git_index_reuc_entry *info_b = b;
316 317 318

	return strcmp(info_a->path, info_b->path);
}
319

Edward Thomson committed
320 321 322 323 324 325 326 327
static int reuc_icmp(const void *a, const void *b)
{
	const git_index_reuc_entry *info_a = a;
	const git_index_reuc_entry *info_b = b;

	return strcasecmp(info_a->path, info_b->path);
}

328 329 330 331 332 333 334
static void index_entry_reuc_free(git_index_reuc_entry *reuc)
{
	git__free(reuc);
}

static void index_entry_free(git_index_entry *entry)
{
335 336 337
	if (!entry)
		return;

338
	memset(&entry->id, 0, sizeof(entry->id));
339 340 341
	git__free(entry);
}

342
unsigned int git_index__create_mode(unsigned int mode)
343 344 345
{
	if (S_ISLNK(mode))
		return S_IFLNK;
346

347 348
	if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR))
		return (S_IFLNK | S_IFDIR);
349

350
	return S_IFREG | GIT_PERMS_CANONICAL(mode);
351 352
}

353 354 355 356 357 358 359 360 361
static unsigned int index_merge_mode(
	git_index *index, git_index_entry *existing, unsigned int mode)
{
	if (index->no_symlinks && S_ISREG(mode) &&
		existing && S_ISLNK(existing->mode))
		return existing->mode;

	if (index->distrust_filemode && S_ISREG(mode))
		return (existing && S_ISREG(existing->mode)) ?
362
			existing->mode : git_index__create_mode(0666);
363

364
	return git_index__create_mode(mode);
365 366
}

367 368 369 370 371 372 373 374 375 376 377 378 379
GIT_INLINE(int) index_find_in_entries(
	size_t *out, git_vector *entries, git_vector_cmp entry_srch,
	const char *path, size_t path_len, int stage)
{
	struct entry_srch_key srch_key;
	srch_key.path = path;
	srch_key.pathlen = !path_len ? strlen(path) : path_len;
	srch_key.stage = stage;
	return git_vector_bsearch2(out, entries, entry_srch, &srch_key);
}

GIT_INLINE(int) index_find(
	size_t *out, git_index *index,
380
	const char *path, size_t path_len, int stage)
381
{
382
	git_vector_sort(&index->entries);
383 384 385 386 387

	return index_find_in_entries(
		out, &index->entries, index->entries_search, path, path_len, stage);
}

388
void git_index__set_ignore_case(git_index *index, bool ignore_case)
389
{
390 391
	index->ignore_case = ignore_case;

392 393 394 395 396 397 398 399 400 401 402
	if (ignore_case) {
		index->entries_cmp_path    = git__strcasecmp_cb;
		index->entries_search      = git_index_entry_isrch;
		index->entries_search_path = index_entry_isrch_path;
		index->reuc_search         = reuc_isrch;
	} else {
		index->entries_cmp_path    = git__strcmp_cb;
		index->entries_search      = git_index_entry_srch;
		index->entries_search_path = index_entry_srch_path;
		index->reuc_search         = reuc_srch;
	}
403

404 405
	git_vector_set_cmp(&index->entries,
		ignore_case ? git_index_entry_icmp : git_index_entry_cmp);
406
	git_vector_sort(&index->entries);
Edward Thomson committed
407

408
	git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
Edward Thomson committed
409
	git_vector_sort(&index->reuc);
410 411
}

412 413 414 415
int git_index__open(
	git_index **index_out,
	const char *index_path,
	git_oid_t oid_type)
416 417
{
	git_index *index;
418
	int error = -1;
419

Edward Thomson committed
420
	GIT_ASSERT_ARG(index_out);
421

422
	index = git__calloc(1, sizeof(git_index));
423
	GIT_ERROR_CHECK_ALLOC(index);
424

425 426
	index->oid_type = oid_type;

427 428
	if (git_pool_init(&index->tree_pool, 1) < 0)
		goto fail;
429

430 431
	if (index_path != NULL) {
		index->index_file_path = git__strdup(index_path);
432 433
		if (!index->index_file_path)
			goto fail;
434 435

		/* Check if index file is stored on disk already */
436
		if (git_fs_path_exists(index->index_file_path) == true)
437 438
			index->on_disk = 1;
	}
439

440
	if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
441 442 443 444
	    git_idxmap_new(&index->entries_map) < 0 ||
	    git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
	    git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
	    git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
445
		goto fail;
446

447 448 449
	index->entries_cmp_path = git__strcmp_cb;
	index->entries_search = git_index_entry_srch;
	index->entries_search_path = index_entry_srch_path;
Edward Thomson committed
450
	index->reuc_search = reuc_srch;
David Turner committed
451
	index->version = INDEX_VERSION_NUMBER_DEFAULT;
452

453 454
	if (index_path != NULL && (error = git_index_read(index, true)) < 0)
		goto fail;
455

Vicent Marti committed
456
	*index_out = index;
457
	GIT_REFCOUNT_INC(index);
458

459
	return 0;
460 461

fail:
462
	git_pool_clear(&index->tree_pool);
463 464
	git_index_free(index);
	return error;
465 466
}

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
#ifdef GIT_EXPERIMENTAL_SHA256
int git_index_open(git_index **index_out, const char *index_path, git_oid_t oid_type)
{
	return git_index__open(index_out, index_path, oid_type);
}
#else
int git_index_open(git_index **index_out, const char *index_path)
{
	return git_index__open(index_out, index_path, GIT_OID_SHA1);
}
#endif

int git_index__new(git_index **out, git_oid_t oid_type)
{
	return git_index__open(out, NULL, oid_type);
}

#ifdef GIT_EXPERIMENTAL_SHA256
int git_index_new(git_index **out, git_oid_t oid_type)
{
	return git_index__new(out, oid_type);
}
#else
490 491
int git_index_new(git_index **out)
{
492
	return git_index__new(out, GIT_OID_SHA1);
493
}
494
#endif
495

496
static void index_free(git_index *index)
497
{
498 499 500
	/* index iterators increment the refcount of the index, so if we
	 * get here then there should be no outstanding iterators.
	 */
501
	if (git_atomic32_get(&index->readers))
Edward Thomson committed
502
		return;
503

504
	git_index_clear(index);
505
	git_idxmap_free(index->entries_map);
506
	git_vector_free(&index->entries);
Edward Thomson committed
507
	git_vector_free(&index->names);
Edward Thomson committed
508
	git_vector_free(&index->reuc);
509
	git_vector_free(&index->deleted);
510

511
	git__free(index->index_file_path);
512

513
	git__memzero(index, sizeof(*index));
514
	git__free(index);
515 516
}

517 518
void git_index_free(git_index *index)
{
519
	if (index == NULL)
520 521
		return;

522
	GIT_REFCOUNT_DEC(index, index_free);
523 524
}

525 526
/* call with locked index */
static void index_free_deleted(git_index *index)
527
{
528
	int readers = (int)git_atomic32_get(&index->readers);
529
	size_t i;
530

531
	if (readers > 0 || !index->deleted.length)
532 533
		return;

534
	for (i = 0; i < index->deleted.length; ++i) {
535
		git_index_entry *ie = git_atomic_swap(index->deleted.contents[i], NULL);
536 537
		index_entry_free(ie);
	}
538 539 540 541

	git_vector_clear(&index->deleted);
}

542 543
/* call with locked index */
static int index_remove_entry(git_index *index, size_t pos)
544 545 546 547
{
	int error = 0;
	git_index_entry *entry = git_vector_get(&index->entries, pos);

548
	if (entry != NULL) {
549
		git_tree_cache_invalidate_path(index->tree, entry->path);
550
		index_map_delete(index->entries_map, entry, index->ignore_case);
551
	}
552 553 554 555

	error = git_vector_remove(&index->entries, pos);

	if (!error) {
556
		if (git_atomic32_get(&index->readers) > 0) {
557
			error = git_vector_insert(&index->deleted, entry);
558
		} else {
559
			index_entry_free(entry);
560
		}
561 562

		index->dirty = 1;
563 564 565
	}

	return error;
566
}
567

568
int git_index_clear(git_index *index)
569
{
570 571
	int error = 0;

Edward Thomson committed
572
	GIT_ASSERT_ARG(index);
573

574
	index->dirty = 1;
575
	index->tree = NULL;
576
	git_pool_clear(&index->tree_pool);
577

578
	git_idxmap_clear(index->entries_map);
579
	while (!error && index->entries.length > 0)
580
		error = index_remove_entry(index, index->entries.length - 1);
581 582 583 584

	if (error)
		goto done;

585 586
	index_free_deleted(index);

587 588 589
	if ((error = git_index_name_clear(index)) < 0 ||
		(error = git_index_reuc_clear(index)) < 0)
	    goto done;
nulltoken committed
590

591
	git_futils_filestamp_set(&index->stamp, NULL);
592

593
done:
594
	return error;
595 596
}

597 598
static int create_index_error(int error, const char *msg)
{
599
	git_error_set_str(GIT_ERROR_INDEX, msg);
600 601 602
	return error;
}

Russell Belfer committed
603
int git_index_set_caps(git_index *index, int caps)
604
{
Linquize committed
605
	unsigned int old_ignore_case;
606

Edward Thomson committed
607
	GIT_ASSERT_ARG(index);
608

609 610
	old_ignore_case = index->ignore_case;

611
	if (caps == GIT_INDEX_CAPABILITY_FROM_OWNER) {
612
		git_repository *repo = INDEX_OWNER(index);
613 614
		int val;

615 616
		if (!repo)
			return create_index_error(
617
				-1, "cannot access repository to set index caps");
618

619
		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_IGNORECASE))
620
			index->ignore_case = (val != 0);
621
		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FILEMODE))
622
			index->distrust_filemode = (val == 0);
623
		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_SYMLINKS))
624
			index->no_symlinks = (val == 0);
625 626
	}
	else {
627 628 629
		index->ignore_case = ((caps & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0);
		index->distrust_filemode = ((caps & GIT_INDEX_CAPABILITY_NO_FILEMODE) != 0);
		index->no_symlinks = ((caps & GIT_INDEX_CAPABILITY_NO_SYMLINKS) != 0);
630 631
	}

632
	if (old_ignore_case != index->ignore_case) {
Linquize committed
633
		git_index__set_ignore_case(index, (bool)index->ignore_case);
634 635
	}

636 637 638
	return 0;
}

Russell Belfer committed
639
int git_index_caps(const git_index *index)
640
{
641 642 643
	return ((index->ignore_case ? GIT_INDEX_CAPABILITY_IGNORE_CASE : 0) |
			(index->distrust_filemode ? GIT_INDEX_CAPABILITY_NO_FILEMODE : 0) |
			(index->no_symlinks ? GIT_INDEX_CAPABILITY_NO_SYMLINKS : 0));
644 645
}

646
#ifndef GIT_DEPRECATE_HARD
647 648
const git_oid *git_index_checksum(git_index *index)
{
649
	return (git_oid *)index->checksum;
650
}
651
#endif
652 653 654 655 656 657

/**
 * Returns 1 for changed, 0 for not changed and <0 for errors
 */
static int compare_checksum(git_index *index)
{
658
	int fd;
659
	ssize_t bytes_read;
660 661
	unsigned char checksum[GIT_HASH_MAX_SIZE];
	size_t checksum_size = git_oid_size(index->oid_type);
662 663 664 665

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

666
	if (p_lseek(fd, (0 - (ssize_t)checksum_size), SEEK_END) < 0) {
667
		p_close(fd);
668
		git_error_set(GIT_ERROR_OS, "failed to seek to end of file");
669 670 671
		return -1;
	}

672
	bytes_read = p_read(fd, checksum, checksum_size);
673 674
	p_close(fd);

675
	if (bytes_read < (ssize_t)checksum_size)
676 677
		return -1;

678
	return !!memcmp(checksum, index->checksum, checksum_size);
679 680
}

681
int git_index_read(git_index *index, int force)
682
{
683
	int error = 0, updated;
684
	git_str buffer = GIT_STR_INIT;
685
	git_futils_filestamp stamp = index->stamp;
686

687 688
	if (!index->index_file_path)
		return create_index_error(-1,
689
			"failed to read index: The index is in-memory only");
690

691
	index->on_disk = git_fs_path_exists(index->index_file_path);
692 693

	if (!index->on_disk) {
694 695 696 697
		if (force && (error = git_index_clear(index)) < 0)
			return error;

		index->dirty = 0;
698
		return 0;
699 700
	}

701 702
	if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) ||
	    ((updated = compare_checksum(index)) < 0)) {
703 704
		git_error_set(
			GIT_ERROR_INDEX,
705
			"failed to read index: '%s' no longer exists",
706
			index->index_file_path);
707
		return updated;
708
	}
709

710 711
	if (!updated && !force)
		return 0;
712 713

	error = git_futils_readbuffer(&buffer, index->index_file_path);
714 715
	if (error < 0)
		return error;
716

717 718 719
	index->tree = NULL;
	git_pool_clear(&index->tree_pool);

720 721 722 723
	error = git_index_clear(index);

	if (!error)
		error = parse_index(index, buffer.ptr, buffer.size);
724

725
	if (!error) {
726
		git_futils_filestamp_set(&index->stamp, &stamp);
727 728
		index->dirty = 0;
	}
729

730
	git_str_dispose(&buffer);
731 732 733
	return error;
}

734 735
int git_index_read_safely(git_index *index)
{
736
	if (git_index__enforce_unsaved_safety && index->dirty) {
737
		git_error_set(GIT_ERROR_INDEX,
738
			"the index has unsaved changes that would be overwritten by this operation");
739
		return GIT_EINDEXDIRTY;
740 741 742 743 744
	}

	return git_index_read(index, false);
}

745
static bool is_racy_entry(git_index *index, const git_index_entry *entry)
746 747 748 749 750
{
	/* Git special-cases submodules in the check */
	if (S_ISGITLINK(entry->mode))
		return false;

751
	return git_index_entry_newer_than_index(entry, index);
752 753
}

754 755 756 757
/*
 * Force the next diff to take a look at those entries which have the
 * same timestamp as the current index.
 */
758
static int truncate_racily_clean(git_index *index)
759 760
{
	size_t i;
761
	int error;
762
	git_index_entry *entry;
763
	git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
764 765 766
	git_diff *diff = NULL;
	git_vector paths = GIT_VECTOR_INIT;
	git_diff_delta *delta;
767 768 769 770

	/* Nothing to do if there's no repo to talk about */
	if (!INDEX_OWNER(index))
		return 0;
771

772 773 774 775 776
	/* If there's no workdir, we can't know where to even check */
	if (!git_repository_workdir(INDEX_OWNER(index)))
		return 0;

	diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
777
	git_vector_foreach(&index->entries, i, entry) {
778
		if ((entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE) == 0 &&
779
			is_racy_entry(index, entry))
780 781
			git_vector_insert(&paths, (char *)entry->path);
	}
782

783 784
	if (paths.length == 0)
		goto done;
785

786 787
	diff_opts.pathspec.count = paths.length;
	diff_opts.pathspec.strings = (char **)paths.contents;
788

789 790
	if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
		return error;
791

792 793 794 795 796 797
	git_vector_foreach(&diff->deltas, i, delta) {
		entry = (git_index_entry *)git_index_get_bypath(index, delta->old_file.path, 0);

		/* Ensure that we have a stage 0 for this file (ie, it's not a
		 * conflict), otherwise smudging it is quite pointless.
		 */
798
		if (entry) {
799
			entry->file_size = 0;
800 801
			index->dirty = 1;
		}
802
	}
803

804 805 806
done:
	git_diff_free(diff);
	git_vector_free(&paths);
807
	return 0;
808 809
}

David Turner committed
810 811
unsigned git_index_version(git_index *index)
{
Edward Thomson committed
812
	GIT_ASSERT_ARG(index);
David Turner committed
813 814 815 816 817 818

	return index->version;
}

int git_index_set_version(git_index *index, unsigned int version)
{
Edward Thomson committed
819
	GIT_ASSERT_ARG(index);
David Turner committed
820 821 822

	if (version < INDEX_VERSION_NUMBER_LB ||
	    version > INDEX_VERSION_NUMBER_UB) {
823
		git_error_set(GIT_ERROR_INDEX, "invalid version number");
David Turner committed
824 825 826 827 828 829 830 831
		return -1;
	}

	index->version = version;

	return 0;
}

832 833
int git_index_write(git_index *index)
{
834
	git_indexwriter writer = GIT_INDEXWRITER_INIT;
835
	int error;
836

837 838
	truncate_racily_clean(index);

839 840 841
	if ((error = git_indexwriter_init(&writer, index)) == 0 &&
		(error = git_indexwriter_commit(&writer)) == 0)
		index->dirty = 0;
842

843
	git_indexwriter_cleanup(&writer);
844

845
	return error;
846
}
847

Edward Thomson committed
848
const char *git_index_path(const git_index *index)
849
{
Edward Thomson committed
850
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
851 852
	return index->index_file_path;
}
853

854 855 856 857
int git_index_write_tree(git_oid *oid, git_index *index)
{
	git_repository *repo;

Edward Thomson committed
858 859
	GIT_ASSERT_ARG(oid);
	GIT_ASSERT_ARG(index);
860

861
	repo = INDEX_OWNER(index);
862

863 864
	if (repo == NULL)
		return create_index_error(-1, "Failed to write tree. "
865
		  "the index file is not backed up by an existing repository");
866 867 868 869

	return git_tree__write_index(oid, index, repo);
}

870 871
int git_index_write_tree_to(
	git_oid *oid, git_index *index, git_repository *repo)
872
{
Edward Thomson committed
873 874 875 876
	GIT_ASSERT_ARG(oid);
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(repo);

877 878 879
	return git_tree__write_index(oid, index, repo);
}

880
size_t git_index_entrycount(const git_index *index)
881
{
Edward Thomson committed
882 883
	GIT_ASSERT_ARG(index);

884
	return index->entries.length;
885 886
}

887 888
const git_index_entry *git_index_get_byindex(
	git_index *index, size_t n)
889
{
Edward Thomson committed
890 891
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);

892
	git_vector_sort(&index->entries);
Edward Thomson committed
893
	return git_vector_get(&index->entries, n);
894 895
}

896 897
const git_index_entry *git_index_get_bypath(
	git_index *index, const char *path, int stage)
898
{
899
	git_index_entry key = {{ 0 }};
900
	git_index_entry *value;
Edward Thomson committed
901

Edward Thomson committed
902
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
Edward Thomson committed
903

904
	key.path = path;
905
	GIT_INDEX_ENTRY_STAGE_SET(&key, stage);
906

907 908 909 910
	if (index->ignore_case)
		value = git_idxmap_icase_get((git_idxmap_icase *) index->entries_map, &key);
	else
		value = git_idxmap_get(index->entries_map, &key);
Edward Thomson committed
911

912 913 914 915
	if (!value) {
	    git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path);
	    return NULL;
	}
916

917
	return value;
918 919
}

920 921
void git_index_entry__init_from_stat(
	git_index_entry *entry, struct stat *st, bool trust_mode)
922
{
923 924
	entry->ctime.seconds = (int32_t)st->st_ctime;
	entry->mtime.seconds = (int32_t)st->st_mtime;
925
#if defined(GIT_USE_NSEC)
926 927
	entry->mtime.nanoseconds = st->st_mtime_nsec;
	entry->ctime.nanoseconds = st->st_ctime_nsec;
928
#endif
929 930
	entry->dev  = st->st_rdev;
	entry->ino  = st->st_ino;
931
	entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
932
		git_index__create_mode(0666) : git_index__create_mode(st->st_mode);
933 934
	entry->uid  = st->st_uid;
	entry->gid  = st->st_gid;
935
	entry->file_size = (uint32_t)st->st_size;
936 937
}

938 939 940 941
static void index_entry_adjust_namemask(
		git_index_entry *entry,
		size_t path_length)
{
942
	entry->flags &= ~GIT_INDEX_ENTRY_NAMEMASK;
943

944 945
	if (path_length < GIT_INDEX_ENTRY_NAMEMASK)
		entry->flags |= path_length & GIT_INDEX_ENTRY_NAMEMASK;
946
	else
947
		entry->flags |= GIT_INDEX_ENTRY_NAMEMASK;
948 949
}

950 951 952 953 954 955
/* When `from_workdir` is true, we will validate the paths to avoid placing
 * paths that are invalid for the working directory on the current filesystem
 * (eg, on Windows, we will disallow `GIT~1`, `AUX`, `COM1`, etc).  This
 * function will *always* prevent `.git` and directory traversal `../` from
 * being added to the index.
 */
956 957 958
static int index_entry_create(
	git_index_entry **out,
	git_repository *repo,
959
	const char *path,
960
	struct stat *st,
961
	bool from_workdir)
962
{
963
	size_t pathlen = strlen(path), alloclen;
964
	struct entry_internal *entry;
965
	unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
966
	uint16_t mode = 0;
967

968 969 970 971 972 973
	/* always reject placing `.git` in the index and directory traversal.
	 * when requested, disallow platform-specific filenames and upgrade to
	 * the platform-specific `.git` tests (eg, `git~1`, etc).
	 */
	if (from_workdir)
		path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
974 975
	if (st)
		mode = st->st_mode;
976

977
	if (!git_path_is_valid(repo, path, mode, path_valid_flags)) {
978
		git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path);
979
		return -1;
980
	}
981

982 983
	GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen);
	GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
984
	entry = git__calloc(1, alloclen);
985
	GIT_ERROR_CHECK_ALLOC(entry);
986 987 988 989 990

	entry->pathlen = pathlen;
	memcpy(entry->path, path, pathlen);
	entry->entry.path = entry->path;

991 992
	*out = (git_index_entry *)entry;
	return 0;
993 994
}

995
static int index_entry_init(
996 997 998
	git_index_entry **entry_out,
	git_index *index,
	const char *rel_path)
999
{
1000
	int error = 0;
1001
	git_index_entry *entry = NULL;
1002
	git_str path = GIT_STR_INIT;
1003 1004
	struct stat st;
	git_oid oid;
1005
	git_repository *repo;
1006

1007 1008
	if (INDEX_OWNER(index) == NULL)
		return create_index_error(-1,
1009
			"could not initialize index entry. "
1010 1011
			"Index is not backed up by an existing repository.");

1012 1013 1014 1015 1016 1017 1018 1019 1020
	/*
	 * FIXME: this is duplicated with the work in
	 * git_blob__create_from_paths. It should accept an optional stat
	 * structure so we can pass in the one we have to do here.
	 */
	repo = INDEX_OWNER(index);
	if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
		return GIT_EBAREREPO;

1021
	if (git_repository_workdir_path(&path, repo, rel_path) < 0)
1022 1023
		return -1;

1024
	error = git_fs_path_lstat(path.ptr, &st);
1025
	git_str_dispose(&path);
1026 1027 1028 1029 1030

	if (error < 0)
		return error;

	if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0)
1031 1032
		return -1;

1033 1034 1035
	/* write the blob to disk and get the oid and stat info */
	error = git_blob__create_from_paths(
		&oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true);
1036

1037 1038 1039 1040
	if (error < 0) {
		index_entry_free(entry);
		return error;
	}
1041

1042
	entry->id = oid;
1043
	git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
1044

1045
	*entry_out = (git_index_entry *)entry;
1046
	return 0;
1047 1048
}

1049 1050
static git_index_reuc_entry *reuc_entry_alloc(const char *path)
{
1051
	size_t pathlen = strlen(path),
1052 1053
		structlen = sizeof(struct reuc_entry_internal),
		alloclen;
1054 1055
	struct reuc_entry_internal *entry;

1056 1057
	if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) ||
		GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1))
1058 1059
		return NULL;

1060
	entry = git__calloc(1, alloclen);
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
	if (!entry)
		return NULL;

	entry->pathlen = pathlen;
	memcpy(entry->path, path, pathlen);
	entry->entry.path = entry->path;

	return (git_index_reuc_entry *)entry;
}

Edward Thomson committed
1071 1072
static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
	const char *path,
Edward Thomson committed
1073 1074 1075
	int ancestor_mode, const git_oid *ancestor_oid,
	int our_mode, const git_oid *our_oid,
	int their_mode, const git_oid *their_oid)
Edward Thomson committed
1076 1077 1078
{
	git_index_reuc_entry *reuc = NULL;

Edward Thomson committed
1079 1080
	GIT_ASSERT_ARG(reuc_out);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
1081

1082
	*reuc_out = reuc = reuc_entry_alloc(path);
1083
	GIT_ERROR_CHECK_ALLOC(reuc);
Edward Thomson committed
1084

1085
	if ((reuc->mode[0] = ancestor_mode) > 0) {
Edward Thomson committed
1086
		GIT_ASSERT(ancestor_oid);
1087
		git_oid_cpy(&reuc->oid[0], ancestor_oid);
1088
	}
Edward Thomson committed
1089

1090
	if ((reuc->mode[1] = our_mode) > 0) {
Edward Thomson committed
1091
		GIT_ASSERT(our_oid);
1092
		git_oid_cpy(&reuc->oid[1], our_oid);
1093
	}
Edward Thomson committed
1094

1095
	if ((reuc->mode[2] = their_mode) > 0) {
Edward Thomson committed
1096
		GIT_ASSERT(their_oid);
1097
		git_oid_cpy(&reuc->oid[2], their_oid);
1098
	}
Edward Thomson committed
1099 1100 1101 1102

	return 0;
}

1103 1104
static void index_entry_cpy(
	git_index_entry *tgt,
1105
	const git_index_entry *src)
1106
{
1107
	const char *tgt_path = tgt->path;
1108
	memcpy(tgt, src, sizeof(*tgt));
1109
	tgt->path = tgt_path;
1110 1111
}

1112 1113
static int index_entry_dup(
	git_index_entry **out,
1114
	git_index *index,
1115
	const git_index_entry *src)
1116
{
1117
	if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
1118
		return -1;
1119

1120 1121 1122
	index_entry_cpy(*out, src);
	return 0;
}
1123

1124 1125 1126 1127 1128 1129 1130
static void index_entry_cpy_nocache(
	git_index_entry *tgt,
	const git_index_entry *src)
{
	git_oid_cpy(&tgt->id, &src->id);
	tgt->mode = src->mode;
	tgt->flags = src->flags;
1131
	tgt->flags_extended = (src->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS);
1132 1133 1134 1135 1136 1137 1138
}

static int index_entry_dup_nocache(
	git_index_entry **out,
	git_index *index,
	const git_index_entry *src)
{
1139
	if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
1140
		return -1;
1141

1142
	index_entry_cpy_nocache(*out, src);
1143
	return 0;
1144 1145
}

1146
static int has_file_name(git_index *index,
1147
	 const git_index_entry *entry, size_t pos, int ok_to_replace)
1148
{
1149
	size_t len = strlen(entry->path);
1150
	int stage = GIT_INDEX_ENTRY_STAGE(entry);
1151
	const char *name = entry->path;
1152

1153
	while (pos < index->entries.length) {
1154
		struct entry_internal *p = index->entries.contents[pos++];
1155

1156
		if (len >= p->pathlen)
1157
			break;
1158
		if (memcmp(name, p->path, len))
1159
			break;
1160
		if (GIT_INDEX_ENTRY_STAGE(&p->entry) != stage)
1161
			continue;
1162
		if (p->path[len] != '/')
1163 1164
			continue;
		if (!ok_to_replace)
1165
			return -1;
1166

1167
		if (index_remove_entry(index, --pos) < 0)
1168
			break;
1169
	}
1170
	return 0;
1171 1172 1173 1174 1175 1176 1177 1178 1179
}

/*
 * Do we have another file with a pathname that is a proper
 * subset of the name we're trying to add?
 */
static int has_dir_name(git_index *index,
		const git_index_entry *entry, int ok_to_replace)
{
1180
	int stage = GIT_INDEX_ENTRY_STAGE(entry);
1181 1182
	const char *name = entry->path;
	const char *slash = name + strlen(name);
1183 1184

	for (;;) {
1185
		size_t len, pos;
1186 1187 1188 1189

		for (;;) {
			if (*--slash == '/')
				break;
1190
			if (slash <= entry->path)
1191
				return 0;
1192 1193 1194
		}
		len = slash - name;

1195
		if (!index_find(&pos, index, name, len, stage)) {
1196
			if (!ok_to_replace)
1197
				return -1;
1198

1199
			if (index_remove_entry(index, pos) < 0)
1200
				break;
1201
			continue;
1202 1203 1204 1205 1206 1207 1208
		}

		/*
		 * Trivial optimization: if we find an entry that
		 * already matches the sub-directory, then we know
		 * we're ok, and we can exit.
		 */
1209 1210
		for (; pos < index->entries.length; ++pos) {
			struct entry_internal *p = index->entries.contents[pos];
1211

1212 1213
			if (p->pathlen <= len ||
			    p->path[len] != '/' ||
1214
			    memcmp(p->path, name, len))
1215
				break; /* not our subdirectory */
1216

1217
			if (GIT_INDEX_ENTRY_STAGE(&p->entry) == stage)
1218
				return 0;
1219 1220
		}
	}
1221

1222
	return 0;
1223
}
1224

1225
static int check_file_directory_collision(git_index *index,
1226 1227
		git_index_entry *entry, size_t pos, int ok_to_replace)
{
1228 1229
	if (has_file_name(index, entry, pos, ok_to_replace) < 0 ||
	    has_dir_name(index, entry, ok_to_replace) < 0) {
1230
		git_error_set(GIT_ERROR_INDEX,
1231
			"'%s' appears as both a file and a directory", entry->path);
1232 1233 1234 1235 1236
		return -1;
	}

	return 0;
}
1237

1238
static int canonicalize_directory_path(
1239 1240 1241
	git_index *index,
	git_index_entry *entry,
	git_index_entry *existing)
1242 1243 1244 1245 1246 1247 1248 1249 1250
{
	const git_index_entry *match, *best = NULL;
	char *search, *sep;
	size_t pos, search_len, best_len;

	if (!index->ignore_case)
		return 0;

	/* item already exists in the index, simply re-use the existing case */
1251 1252
	if (existing) {
		memcpy((char *)entry->path, existing->path, strlen(existing->path));
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
		return 0;
	}

	/* nothing to do */
	if (strchr(entry->path, '/') == NULL)
		return 0;

	if ((search = git__strdup(entry->path)) == NULL)
		return -1;

	/* starting at the parent directory and descending to the root, find the
	 * common parent directory.
	 */
	while (!best && (sep = strrchr(search, '/'))) {
		sep[1] = '\0';

		search_len = strlen(search);

		git_vector_bsearch2(
			&pos, &index->entries, index->entries_search_path, search);

		while ((match = git_vector_get(&index->entries, pos))) {
1275
			if (GIT_INDEX_ENTRY_STAGE(match) != 0) {
1276
				/* conflicts do not contribute to canonical paths */
1277
			} else if (strncmp(search, match->path, search_len) == 0) {
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
				/* prefer an exact match to the input filename */
				best = match;
				best_len = search_len;
				break;
			} else if (strncasecmp(search, match->path, search_len) == 0) {
				/* continue walking, there may be a path with an exact
				 * (case sensitive) match later in the index, but use this
				 * as the best match until that happens.
				 */
				if (!best) {
					best = match;
					best_len = search_len;
				}
			} else {
				break;
			}

			pos++;
		}

		sep[0] = '\0';
	}

	if (best)
		memcpy((char *)entry->path, best->path, best_len);

	git__free(search);
	return 0;
}

1308 1309 1310 1311
static int index_no_dups(void **old, void *new)
{
	const git_index_entry *entry = new;
	GIT_UNUSED(old);
1312
	git_error_set(GIT_ERROR_INDEX, "'%s' appears multiple times at stage %d",
1313
		entry->path, GIT_INDEX_ENTRY_STAGE(entry));
1314 1315 1316
	return GIT_EEXISTS;
}

1317
static void index_existing_and_best(
1318
	git_index_entry **existing,
1319
	size_t *existing_position,
1320
	git_index_entry **best,
1321 1322 1323
	git_index *index,
	const git_index_entry *entry)
{
1324
	git_index_entry *e;
1325 1326 1327 1328
	size_t pos;
	int error;

	error = index_find(&pos,
1329
		index, entry->path, 0, GIT_INDEX_ENTRY_STAGE(entry));
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341

	if (error == 0) {
		*existing = index->entries.contents[pos];
		*existing_position = pos;
		*best = index->entries.contents[pos];
		return;
	}

	*existing = NULL;
	*existing_position = 0;
	*best = NULL;

1342
	if (GIT_INDEX_ENTRY_STAGE(entry) == 0) {
1343 1344 1345 1346 1347 1348 1349 1350 1351
		for (; pos < index->entries.length; pos++) {
			int (*strcomp)(const char *a, const char *b) =
				index->ignore_case ? git__strcasecmp : git__strcmp;

			e = index->entries.contents[pos];

			if (strcomp(entry->path, e->path) != 0)
				break;

1352
			if (GIT_INDEX_ENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) {
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
				*best = e;
				continue;
			} else {
				*best = e;
				break;
			}
		}
	}
}

1363 1364 1365 1366
/* index_insert takes ownership of the new entry - if it can't insert
 * it, then it will return an error **and also free the entry**.  When
 * it replaces an existing entry, it will update the entry_ptr with the
 * actual entry in the index (and free the passed in one).
1367
 *
1368 1369 1370
 * trust_path is whether we use the given path, or whether (on case
 * insensitive systems only) we try to canonicalize the given path to
 * be within an existing directory.
1371
 *
1372
 * trust_mode is whether we trust the mode in entry_ptr.
1373 1374
 *
 * trust_id is whether we trust the id or it should be validated.
1375 1376
 */
static int index_insert(
1377 1378 1379 1380
	git_index *index,
	git_index_entry **entry_ptr,
	int replace,
	bool trust_path,
1381 1382
	bool trust_mode,
	bool trust_id)
1383
{
1384
	git_index_entry *existing, *best, *entry;
1385 1386
	size_t path_length, position;
	int error;
1387

Edward Thomson committed
1388 1389
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(entry_ptr);
1390 1391

	entry = *entry_ptr;
1392

1393
	/* Make sure that the path length flag is correct */
1394
	path_length = ((struct entry_internal *)entry)->pathlen;
1395
	index_entry_adjust_namemask(entry, path_length);
1396

1397
	/* This entry is now up-to-date and should not be checked for raciness */
1398
	entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
1399

1400 1401
	git_vector_sort(&index->entries);

1402 1403
	/*
	 * Look if an entry with this path already exists, either staged, or (if
1404 1405 1406 1407
	 * this entry is a regular staged item) as the "ours" side of a conflict.
	 */
	index_existing_and_best(&existing, &position, &best, index, entry);

1408
	/* Update the file mode */
1409 1410 1411
	entry->mode = trust_mode ?
		git_index__create_mode(entry->mode) :
		index_merge_mode(index, best, entry->mode);
1412

1413 1414 1415
	/* Canonicalize the directory name */
	if (!trust_path && (error = canonicalize_directory_path(index, entry, best)) < 0)
		goto out;
1416

1417 1418 1419
	/* Ensure that the given id exists (unless it's a submodule) */
	if (!trust_id && INDEX_OWNER(index) &&
	    (entry->mode & GIT_FILEMODE_COMMIT) != GIT_FILEMODE_COMMIT) {
1420 1421

		if (!git_object__is_valid(INDEX_OWNER(index), &entry->id,
1422
					  git_object__type_from_filemode(entry->mode))) {
1423
			error = -1;
1424 1425
			goto out;
		}
1426 1427
	}

1428 1429 1430
	/* Look for tree / blob name collisions, removing conflicts if requested */
	if ((error = check_file_directory_collision(index, entry, position, replace)) < 0)
		goto out;
1431

1432 1433
	/*
	 * If we are replacing an existing item, overwrite the existing entry
1434 1435
	 * and return it in place of the passed in one.
	 */
1436
	if (existing) {
1437 1438 1439 1440 1441 1442 1443
		if (replace) {
			index_entry_cpy(existing, entry);

			if (trust_path)
				memcpy((char *)existing->path, entry->path, strlen(entry->path));
		}

1444
		index_entry_free(entry);
1445 1446 1447 1448
		*entry_ptr = existing;
	} else {
		/*
		 * If replace is not requested or no existing entry exists, insert
1449 1450
		 * at the sorted position.  (Since we re-sort after each insert to
		 * check for dups, this is actually cheaper in the long run.)
1451
		 */
1452 1453
		if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0 ||
		    (error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0)
1454
			goto out;
1455
	}
1456

1457 1458 1459
	index->dirty = 1;

out:
1460 1461 1462 1463
	if (error < 0) {
		index_entry_free(*entry_ptr);
		*entry_ptr = NULL;
	}
1464

1465
	return error;
1466 1467
}

Edward Thomson committed
1468
static int index_conflict_to_reuc(git_index *index, const char *path)
1469
{
1470
	const git_index_entry *conflict_entries[3];
Edward Thomson committed
1471
	int ancestor_mode, our_mode, their_mode;
Edward Thomson committed
1472
	git_oid const *ancestor_oid, *our_oid, *their_oid;
1473
	int ret;
1474

Edward Thomson committed
1475 1476
	if ((ret = git_index_conflict_get(&conflict_entries[0],
		&conflict_entries[1], &conflict_entries[2], index, path)) < 0)
1477
		return ret;
1478

Edward Thomson committed
1479 1480 1481
	ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode;
	our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode;
	their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode;
1482

1483 1484 1485
	ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->id;
	our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->id;
	their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->id;
Edward Thomson committed
1486 1487 1488 1489 1490 1491

	if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid,
		our_mode, our_oid, their_mode, their_oid)) >= 0)
		ret = git_index_conflict_remove(index, path);

	return ret;
1492 1493
}

1494
GIT_INLINE(bool) is_file_or_link(const int filemode)
1495 1496 1497
{
	return (filemode == GIT_FILEMODE_BLOB ||
		filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
1498 1499 1500 1501 1502 1503
		filemode == GIT_FILEMODE_LINK);
}

GIT_INLINE(bool) valid_filemode(const int filemode)
{
	return (is_file_or_link(filemode) || filemode == GIT_FILEMODE_COMMIT);
1504 1505
}

1506
int git_index_add_from_buffer(
1507
    git_index *index, const git_index_entry *source_entry,
1508 1509 1510 1511 1512 1513
    const void *buffer, size_t len)
{
	git_index_entry *entry = NULL;
	int error = 0;
	git_oid id;

Edward Thomson committed
1514 1515
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(source_entry && source_entry->path);
1516 1517 1518

	if (INDEX_OWNER(index) == NULL)
		return create_index_error(-1,
1519
			"could not initialize index entry. "
1520 1521
			"Index is not backed up by an existing repository.");

1522
	if (!is_file_or_link(source_entry->mode)) {
1523
		git_error_set(GIT_ERROR_INDEX, "invalid filemode");
1524 1525 1526
		return -1;
	}

1527 1528 1529 1530 1531
	if (len > UINT32_MAX) {
		git_error_set(GIT_ERROR_INDEX, "buffer is too large");
		return -1;
	}

1532
	if (index_entry_dup(&entry, index, source_entry) < 0)
1533 1534
		return -1;

1535
	error = git_blob_create_from_buffer(&id, INDEX_OWNER(index), buffer, len);
1536 1537 1538 1539 1540 1541
	if (error < 0) {
		index_entry_free(entry);
		return error;
	}

	git_oid_cpy(&entry->id, &id);
1542
	entry->file_size = (uint32_t)len;
1543

1544
	if ((error = index_insert(index, &entry, 1, true, true, true)) < 0)
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
		return error;

	/* Adding implies conflict was resolved, move conflict entries to REUC */
	if ((error = index_conflict_to_reuc(index, entry->path)) < 0 && error != GIT_ENOTFOUND)
		return error;

	git_tree_cache_invalidate_path(index->tree, entry->path);
	return 0;
}

1555 1556 1557
static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path)
{
	git_repository *sub;
1558
	git_str abspath = GIT_STR_INIT;
1559 1560 1561 1562 1563 1564
	git_repository *repo = INDEX_OWNER(index);
	git_reference *head;
	git_index_entry *entry;
	struct stat st;
	int error;

1565
	if ((error = git_repository_workdir_path(&abspath, repo, path)) < 0)
1566 1567 1568
		return error;

	if ((error = p_stat(abspath.ptr, &st)) < 0) {
1569
		git_error_set(GIT_ERROR_OS, "failed to stat repository dir");
1570 1571 1572
		return -1;
	}

1573 1574 1575
	if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0)
		return -1;

1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
	git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);

	if ((error = git_repository_open(&sub, abspath.ptr)) < 0)
		return error;

	if ((error = git_repository_head(&head, sub)) < 0)
		return error;

	git_oid_cpy(&entry->id, git_reference_target(head));
	entry->mode = GIT_FILEMODE_COMMIT;

	git_reference_free(head);
	git_repository_free(sub);
1589
	git_str_dispose(&abspath);
1590 1591 1592 1593

	*out = entry;
	return 0;
}
1594

1595
int git_index_add_bypath(git_index *index, const char *path)
1596
{
Edward Thomson committed
1597 1598 1599
	git_index_entry *entry = NULL;
	int ret;

Edward Thomson committed
1600 1601
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
1602

1603
	if ((ret = index_entry_init(&entry, index, path)) == 0)
1604
		ret = index_insert(index, &entry, 1, false, false, true);
1605 1606 1607 1608 1609 1610 1611

	/* If we were given a directory, let's see if it's a submodule */
	if (ret < 0 && ret != GIT_EDIRECTORY)
		return ret;

	if (ret == GIT_EDIRECTORY) {
		git_submodule *sm;
1612
		git_error *last_error;
1613

1614
		git_error_save(&last_error);
1615 1616

		ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
1617 1618 1619 1620
		if (ret == GIT_ENOTFOUND) {
			git_error_restore(last_error);
			return GIT_EDIRECTORY;
		}
1621

1622
		git_error_free(last_error);
1623 1624 1625 1626 1627 1628 1629 1630 1631

		/*
		 * EEXISTS means that there is a repository at that path, but it's not known
		 * as a submodule. We add its HEAD as an entry and don't register it.
		 */
		if (ret == GIT_EEXISTS) {
			if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
				return ret;

1632
			if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0)
1633 1634 1635 1636 1637 1638 1639 1640
				return ret;
		} else if (ret < 0) {
			return ret;
		} else {
			ret = git_submodule_add_to_index(sm, false);
			git_submodule_free(sm);
			return ret;
		}
1641
	}
Edward Thomson committed
1642 1643 1644

	/* Adding implies conflict was resolved, move conflict entries to REUC */
	if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
1645
		return ret;
Edward Thomson committed
1646 1647 1648

	git_tree_cache_invalidate_path(index->tree, entry->path);
	return 0;
1649 1650
}

1651 1652 1653 1654
int git_index_remove_bypath(git_index *index, const char *path)
{
	int ret;

Edward Thomson committed
1655 1656
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1657 1658 1659 1660 1661 1662 1663

	if (((ret = git_index_remove(index, path, 0)) < 0 &&
		ret != GIT_ENOTFOUND) ||
		((ret = index_conflict_to_reuc(index, path)) < 0 &&
		ret != GIT_ENOTFOUND))
		return ret;

1664
	if (ret == GIT_ENOTFOUND)
1665
		git_error_clear();
1666

1667 1668 1669
	return 0;
}

1670 1671 1672
int git_index__fill(git_index *index, const git_vector *source_entries)
{
	const git_index_entry *source_entry = NULL;
1673
	int error = 0;
1674 1675
	size_t i;

Edward Thomson committed
1676
	GIT_ASSERT_ARG(index);
1677

1678 1679 1680
	if (!source_entries->length)
		return 0;

1681
	if (git_vector_size_hint(&index->entries, source_entries->length) < 0 ||
1682 1683
	    index_map_resize(index->entries_map, (size_t)(source_entries->length * 1.3),
			     index->ignore_case) < 0)
1684
		return -1;
1685

1686 1687 1688
	git_vector_foreach(source_entries, i, source_entry) {
		git_index_entry *entry = NULL;

1689
		if ((error = index_entry_dup(&entry, index, source_entry)) < 0)
1690 1691
			break;

1692
		index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen);
1693
		entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
1694
		entry->mode = git_index__create_mode(entry->mode);
1695

1696
		if ((error = git_vector_insert(&index->entries, entry)) < 0)
1697 1698
			break;

1699
		if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0)
1700
			break;
1701 1702

		index->dirty = 1;
1703 1704
	}

1705
	if (!error)
1706 1707
		git_vector_sort(&index->entries);

1708
	return error;
1709 1710
}

1711

Edward Thomson committed
1712
int git_index_add(git_index *index, const git_index_entry *source_entry)
1713 1714 1715 1716
{
	git_index_entry *entry = NULL;
	int ret;

Edward Thomson committed
1717 1718
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(source_entry && source_entry->path);
1719

1720
	if (!valid_filemode(source_entry->mode)) {
1721
		git_error_set(GIT_ERROR_INDEX, "invalid entry mode");
1722 1723 1724
		return -1;
	}

1725
	if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
1726
		(ret = index_insert(index, &entry, 1, true, true, false)) < 0)
1727
		return ret;
1728

1729
	git_tree_cache_invalidate_path(index->tree, entry->path);
1730
	return 0;
1731 1732
}

Edward Thomson committed
1733
int git_index_remove(git_index *index, const char *path, int stage)
1734
{
1735
	int error;
1736
	size_t position;
1737
	git_index_entry remove_key = {{ 0 }};
1738

1739
	remove_key.path = path;
1740
	GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage);
1741

1742
	index_map_delete(index->entries_map, &remove_key, index->ignore_case);
1743

1744
	if (index_find(&position, index, path, 0, stage) < 0) {
1745 1746
		git_error_set(
			GIT_ERROR_INDEX, "index does not contain %s at stage %d", path, stage);
1747 1748 1749
		error = GIT_ENOTFOUND;
	} else {
		error = index_remove_entry(index, position);
1750
	}
Edward Thomson committed
1751

1752
	return error;
1753
}
1754

1755 1756
int git_index_remove_directory(git_index *index, const char *dir, int stage)
{
1757
	git_str pfx = GIT_STR_INIT;
1758 1759 1760 1761
	int error = 0;
	size_t pos;
	git_index_entry *entry;

1762
	if (!(error = git_str_sets(&pfx, dir)) &&
1763
		!(error = git_fs_path_to_dir(&pfx)))
1764
		index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY);
1765

1766
	while (!error) {
1767 1768 1769 1770
		entry = git_vector_get(&index->entries, pos);
		if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
			break;

1771
		if (GIT_INDEX_ENTRY_STAGE(entry) != stage) {
1772 1773 1774 1775
			++pos;
			continue;
		}

1776
		error = index_remove_entry(index, pos);
1777

1778
		/* removed entry at 'pos' so we don't need to increment */
1779 1780
	}

1781
	git_str_dispose(&pfx);
1782 1783 1784 1785

	return error;
}

1786 1787 1788 1789 1790 1791
int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix)
{
	int error = 0;
	size_t pos;
	const git_index_entry *entry;

1792
	index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY);
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
	entry = git_vector_get(&index->entries, pos);
	if (!entry || git__prefixcmp(entry->path, prefix) != 0)
		error = GIT_ENOTFOUND;

	if (!error && at_pos)
		*at_pos = pos;

	return error;
}

1803
int git_index__find_pos(
1804 1805
	size_t *out, git_index *index, const char *path, size_t path_len, int stage)
{
Edward Thomson committed
1806 1807
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1808
	return index_find(out, index, path, path_len, stage);
Edward Thomson committed
1809 1810
}

1811
int git_index_find(size_t *at_pos, git_index *index, const char *path)
1812
{
1813
	size_t pos;
Edward Thomson committed
1814

Edward Thomson committed
1815 1816
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
1817

1818 1819
	if (git_vector_bsearch2(
			&pos, &index->entries, index->entries_search_path, path) < 0) {
1820
		git_error_set(GIT_ERROR_INDEX, "index does not contain %s", path);
1821
		return GIT_ENOTFOUND;
1822
	}
Edward Thomson committed
1823 1824

	/* Since our binary search only looked at path, we may be in the
1825 1826
	 * middle of a list of stages.
	 */
1827 1828
	for (; pos > 0; --pos) {
		const git_index_entry *prev = git_vector_get(&index->entries, pos - 1);
Edward Thomson committed
1829 1830 1831 1832 1833

		if (index->entries_cmp_path(prev->path, path) != 0)
			break;
	}

1834 1835 1836 1837
	if (at_pos)
		*at_pos = pos;

	return 0;
1838 1839
}

Edward Thomson committed
1840 1841 1842 1843 1844 1845
int git_index_conflict_add(git_index *index,
	const git_index_entry *ancestor_entry,
	const git_index_entry *our_entry,
	const git_index_entry *their_entry)
{
	git_index_entry *entries[3] = { 0 };
1846
	unsigned short i;
Edward Thomson committed
1847 1848
	int ret = 0;

Edward Thomson committed
1849
	GIT_ASSERT_ARG(index);
Edward Thomson committed
1850

1851 1852 1853 1854 1855 1856
	if ((ancestor_entry &&
			(ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0) ||
		(our_entry &&
			(ret = index_entry_dup(&entries[1], index, our_entry)) < 0) ||
		(their_entry &&
			(ret = index_entry_dup(&entries[2], index, their_entry)) < 0))
1857
		goto on_error;
Edward Thomson committed
1858

1859 1860 1861
	/* Validate entries */
	for (i = 0; i < 3; i++) {
		if (entries[i] && !valid_filemode(entries[i]->mode)) {
1862
			git_error_set(GIT_ERROR_INDEX, "invalid filemode for stage %d entry",
1863
				i + 1);
abyss7 committed
1864 1865
			ret = -1;
			goto on_error;
1866 1867 1868
		}
	}

1869 1870 1871 1872 1873 1874 1875 1876 1877
	/* Remove existing index entries for each path */
	for (i = 0; i < 3; i++) {
		if (entries[i] == NULL)
			continue;

		if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) {
			if (ret != GIT_ENOTFOUND)
				goto on_error;

1878
			git_error_clear();
1879 1880 1881 1882 1883
			ret = 0;
		}
	}

	/* Add the conflict entries */
Edward Thomson committed
1884 1885 1886 1887 1888
	for (i = 0; i < 3; i++) {
		if (entries[i] == NULL)
			continue;

		/* Make sure stage is correct */
1889
		GIT_INDEX_ENTRY_STAGE_SET(entries[i], i + 1);
Edward Thomson committed
1890

1891
		if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0)
Edward Thomson committed
1892
			goto on_error;
1893 1894

		entries[i] = NULL; /* don't free if later entry fails */
Edward Thomson committed
1895 1896
	}

nulltoken committed
1897
	return 0;
Edward Thomson committed
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907

on_error:
	for (i = 0; i < 3; i++) {
		if (entries[i] != NULL)
			index_entry_free(entries[i]);
	}

	return ret;
}

1908 1909 1910 1911 1912 1913
static int index_conflict__get_byindex(
	const git_index_entry **ancestor_out,
	const git_index_entry **our_out,
	const git_index_entry **their_out,
	git_index *index,
	size_t n)
Edward Thomson committed
1914
{
1915 1916 1917 1918
	const git_index_entry *conflict_entry;
	const char *path = NULL;
	size_t count;
	int stage, len = 0;
Edward Thomson committed
1919

Edward Thomson committed
1920 1921 1922 1923
	GIT_ASSERT_ARG(ancestor_out);
	GIT_ASSERT_ARG(our_out);
	GIT_ASSERT_ARG(their_out);
	GIT_ASSERT_ARG(index);
1924

Edward Thomson committed
1925 1926 1927 1928
	*ancestor_out = NULL;
	*our_out = NULL;
	*their_out = NULL;

1929 1930
	for (count = git_index_entrycount(index); n < count; ++n) {
		conflict_entry = git_vector_get(&index->entries, n);
Edward Thomson committed
1931

1932
		if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
Edward Thomson committed
1933 1934
			break;

1935
		stage = GIT_INDEX_ENTRY_STAGE(conflict_entry);
1936
		path = conflict_entry->path;
1937

Edward Thomson committed
1938 1939 1940
		switch (stage) {
		case 3:
			*their_out = conflict_entry;
1941
			len++;
Edward Thomson committed
1942 1943 1944
			break;
		case 2:
			*our_out = conflict_entry;
1945
			len++;
Edward Thomson committed
1946 1947 1948
			break;
		case 1:
			*ancestor_out = conflict_entry;
1949
			len++;
Edward Thomson committed
1950 1951 1952 1953 1954 1955
			break;
		default:
			break;
		};
	}

1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
	return len;
}

int git_index_conflict_get(
	const git_index_entry **ancestor_out,
	const git_index_entry **our_out,
	const git_index_entry **their_out,
	git_index *index,
	const char *path)
{
	size_t pos;
	int len = 0;

Edward Thomson committed
1969 1970 1971 1972 1973
	GIT_ASSERT_ARG(ancestor_out);
	GIT_ASSERT_ARG(our_out);
	GIT_ASSERT_ARG(their_out);
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988

	*ancestor_out = NULL;
	*our_out = NULL;
	*their_out = NULL;

	if (git_index_find(&pos, index, path) < 0)
		return GIT_ENOTFOUND;

	if ((len = index_conflict__get_byindex(
		ancestor_out, our_out, their_out, index, pos)) < 0)
		return len;
	else if (len == 0)
		return GIT_ENOTFOUND;

	return 0;
Edward Thomson committed
1989 1990
}

1991
static int index_conflict_remove(git_index *index, const char *path)
Edward Thomson committed
1992
{
1993
	size_t pos = 0;
Edward Thomson committed
1994
	git_index_entry *conflict_entry;
1995
	int error = 0;
Edward Thomson committed
1996

1997
	if (path != NULL && git_index_find(&pos, index, path) < 0)
1998
		return GIT_ENOTFOUND;
Edward Thomson committed
1999

2000
	while ((conflict_entry = git_vector_get(&index->entries, pos)) != NULL) {
Edward Thomson committed
2001

2002 2003
		if (path != NULL &&
			index->entries_cmp_path(conflict_entry->path, path) != 0)
Edward Thomson committed
2004 2005
			break;

2006
		if (GIT_INDEX_ENTRY_STAGE(conflict_entry) == 0) {
Edward Thomson committed
2007 2008 2009 2010
			pos++;
			continue;
		}

2011
		if ((error = index_remove_entry(index, pos)) < 0)
2012
			break;
Edward Thomson committed
2013 2014
	}

2015
	return error;
Edward Thomson committed
2016 2017
}

2018
int git_index_conflict_remove(git_index *index, const char *path)
Edward Thomson committed
2019
{
Edward Thomson committed
2020 2021
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
2022
	return index_conflict_remove(index, path);
Edward Thomson committed
2023 2024
}

2025
int git_index_conflict_cleanup(git_index *index)
Edward Thomson committed
2026
{
Edward Thomson committed
2027
	GIT_ASSERT_ARG(index);
2028
	return index_conflict_remove(index, NULL);
Edward Thomson committed
2029 2030
}

2031
int git_index_has_conflicts(const git_index *index)
2032
{
2033
	size_t i;
2034 2035
	git_index_entry *entry;

Edward Thomson committed
2036
	GIT_ASSERT_ARG(index);
2037 2038

	git_vector_foreach(&index->entries, i, entry) {
2039
		if (GIT_INDEX_ENTRY_STAGE(entry) > 0)
2040 2041 2042 2043 2044 2045
			return 1;
	}

	return 0;
}

2046 2047 2048 2049 2050 2051 2052
int git_index_iterator_new(
	git_index_iterator **iterator_out,
	git_index *index)
{
	git_index_iterator *it;
	int error;

Edward Thomson committed
2053 2054
	GIT_ASSERT_ARG(iterator_out);
	GIT_ASSERT_ARG(index);
2055 2056

	it = git__calloc(1, sizeof(git_index_iterator));
2057
	GIT_ERROR_CHECK_ALLOC(it);
2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073

	if ((error = git_index_snapshot_new(&it->snap, index)) < 0) {
		git__free(it);
		return error;
	}

	it->index = index;

	*iterator_out = it;
	return 0;
}

int git_index_iterator_next(
	const git_index_entry **out,
	git_index_iterator *it)
{
Edward Thomson committed
2074 2075
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(it);
2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092

	if (it->cur >= git_vector_length(&it->snap))
		return GIT_ITEROVER;

	*out = (git_index_entry *)git_vector_get(&it->snap, it->cur++);
	return 0;
}

void git_index_iterator_free(git_index_iterator *it)
{
	if (it == NULL)
		return;

	git_index_snapshot_release(&it->snap, it->index);
	git__free(it);
}

2093 2094 2095 2096 2097 2098
int git_index_conflict_iterator_new(
	git_index_conflict_iterator **iterator_out,
	git_index *index)
{
	git_index_conflict_iterator *it = NULL;

Edward Thomson committed
2099 2100
	GIT_ASSERT_ARG(iterator_out);
	GIT_ASSERT_ARG(index);
2101 2102

	it = git__calloc(1, sizeof(git_index_conflict_iterator));
2103
	GIT_ERROR_CHECK_ALLOC(it);
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119

	it->index = index;

	*iterator_out = it;
	return 0;
}

int git_index_conflict_next(
	const git_index_entry **ancestor_out,
	const git_index_entry **our_out,
	const git_index_entry **their_out,
	git_index_conflict_iterator *iterator)
{
	const git_index_entry *entry;
	int len;

Edward Thomson committed
2120 2121 2122 2123
	GIT_ASSERT_ARG(ancestor_out);
	GIT_ASSERT_ARG(our_out);
	GIT_ASSERT_ARG(their_out);
	GIT_ASSERT_ARG(iterator);
2124 2125 2126 2127 2128 2129 2130 2131

	*ancestor_out = NULL;
	*our_out = NULL;
	*their_out = NULL;

	while (iterator->cur < iterator->index->entries.length) {
		entry = git_index_get_byindex(iterator->index, iterator->cur);

2132
		if (git_index_entry_is_conflict(entry)) {
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158
			if ((len = index_conflict__get_byindex(
				ancestor_out,
				our_out,
				their_out,
				iterator->index,
				iterator->cur)) < 0)
				return len;

			iterator->cur += len;
			return 0;
		}

		iterator->cur++;
	}

	return GIT_ITEROVER;
}

void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
{
	if (iterator == NULL)
		return;

	git__free(iterator);
}

2159
size_t git_index_name_entrycount(git_index *index)
Edward Thomson committed
2160
{
Edward Thomson committed
2161
	GIT_ASSERT_ARG(index);
2162
	return index->names.length;
Edward Thomson committed
2163 2164 2165 2166 2167
}

const git_index_name_entry *git_index_name_get_byindex(
	git_index *index, size_t n)
{
Edward Thomson committed
2168
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
nulltoken committed
2169

Edward Thomson committed
2170 2171 2172 2173
	git_vector_sort(&index->names);
	return git_vector_get(&index->names, n);
}

2174 2175 2176 2177 2178 2179 2180 2181 2182 2183
static void index_name_entry_free(git_index_name_entry *ne)
{
	if (!ne)
		return;
	git__free(ne->ancestor);
	git__free(ne->ours);
	git__free(ne->theirs);
	git__free(ne);
}

Edward Thomson committed
2184 2185 2186 2187 2188
int git_index_name_add(git_index *index,
	const char *ancestor, const char *ours, const char *theirs)
{
	git_index_name_entry *conflict_name;

Edward Thomson committed
2189
	GIT_ASSERT_ARG((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
Edward Thomson committed
2190 2191

	conflict_name = git__calloc(1, sizeof(git_index_name_entry));
2192
	GIT_ERROR_CHECK_ALLOC(conflict_name);
nulltoken committed
2193

2194 2195 2196 2197 2198 2199 2200
	if ((ancestor && !(conflict_name->ancestor = git__strdup(ancestor))) ||
		(ours     && !(conflict_name->ours     = git__strdup(ours))) ||
		(theirs   && !(conflict_name->theirs   = git__strdup(theirs))) ||
		git_vector_insert(&index->names, conflict_name) < 0)
	{
		index_name_entry_free(conflict_name);
		return -1;
Edward Thomson committed
2201
	}
nulltoken committed
2202

2203
	index->dirty = 1;
2204
	return 0;
Edward Thomson committed
2205 2206
}

2207
int git_index_name_clear(git_index *index)
Edward Thomson committed
2208 2209 2210 2211
{
	size_t i;
	git_index_name_entry *conflict_name;

Edward Thomson committed
2212
	GIT_ASSERT_ARG(index);
nulltoken committed
2213

2214 2215
	git_vector_foreach(&index->names, i, conflict_name)
		index_name_entry_free(conflict_name);
nulltoken committed
2216

Edward Thomson committed
2217
	git_vector_clear(&index->names);
2218 2219

	index->dirty = 1;
2220 2221

	return 0;
Edward Thomson committed
2222 2223
}

2224
size_t git_index_reuc_entrycount(git_index *index)
Edward Thomson committed
2225
{
Edward Thomson committed
2226
	GIT_ASSERT_ARG(index);
2227
	return index->reuc.length;
Edward Thomson committed
2228 2229
}

2230 2231 2232 2233 2234 2235 2236
static int index_reuc_on_dup(void **old, void *new)
{
	index_entry_reuc_free(*old);
	*old = new;
	return GIT_EEXISTS;
}

Edward Thomson committed
2237 2238
static int index_reuc_insert(
	git_index *index,
2239
	git_index_reuc_entry *reuc)
Edward Thomson committed
2240
{
2241
	int res;
Edward Thomson committed
2242

Edward Thomson committed
2243 2244 2245
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(reuc && reuc->path != NULL);
	GIT_ASSERT(git_vector_is_sorted(&index->reuc));
Edward Thomson committed
2246

2247
	res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
2248 2249
	index->dirty = 1;

2250
	return res == GIT_EEXISTS ? 0 : res;
Edward Thomson committed
2251 2252 2253
}

int git_index_reuc_add(git_index *index, const char *path,
Edward Thomson committed
2254 2255 2256
	int ancestor_mode, const git_oid *ancestor_oid,
	int our_mode, const git_oid *our_oid,
	int their_mode, const git_oid *their_oid)
Edward Thomson committed
2257 2258 2259 2260
{
	git_index_reuc_entry *reuc = NULL;
	int error = 0;

Edward Thomson committed
2261 2262
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
2263

2264 2265
	if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
			ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
2266
		(error = index_reuc_insert(index, reuc)) < 0)
Edward Thomson committed
2267 2268 2269
		index_entry_reuc_free(reuc);

	return error;
2270
}
Edward Thomson committed
2271

2272
int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path)
2273
{
2274
	return git_vector_bsearch2(at_pos, &index->reuc, index->reuc_search, path);
2275 2276
}

Edward Thomson committed
2277
const git_index_reuc_entry *git_index_reuc_get_bypath(
2278
	git_index *index, const char *path)
2279
{
2280
	size_t pos;
Edward Thomson committed
2281 2282 2283

	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
	GIT_ASSERT_ARG_WITH_RETVAL(path, NULL);
2284

Edward Thomson committed
2285
	if (!index->reuc.length)
2286
		return NULL;
2287

Edward Thomson committed
2288
	GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL);
Edward Thomson committed
2289

2290
	if (git_index_reuc_find(&pos, index, path) < 0)
2291
		return NULL;
2292

Edward Thomson committed
2293
	return git_vector_get(&index->reuc, pos);
2294 2295
}

Edward Thomson committed
2296
const git_index_reuc_entry *git_index_reuc_get_byindex(
2297
	git_index *index, size_t n)
2298
{
Edward Thomson committed
2299 2300
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
	GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL);
Edward Thomson committed
2301 2302 2303 2304

	return git_vector_get(&index->reuc, n);
}

Ben Straub committed
2305
int git_index_reuc_remove(git_index *index, size_t position)
Edward Thomson committed
2306 2307 2308 2309
{
	int error;
	git_index_reuc_entry *reuc;

Edward Thomson committed
2310 2311
	GIT_ASSERT_ARG(index);
	GIT_ASSERT(git_vector_is_sorted(&index->reuc));
Edward Thomson committed
2312 2313

	reuc = git_vector_get(&index->reuc, position);
2314
	error = git_vector_remove(&index->reuc, position);
Edward Thomson committed
2315 2316 2317 2318

	if (!error)
		index_entry_reuc_free(reuc);

2319
	index->dirty = 1;
Edward Thomson committed
2320
	return error;
2321 2322
}

2323
int git_index_reuc_clear(git_index *index)
Edward Thomson committed
2324 2325 2326
{
	size_t i;

Edward Thomson committed
2327
	GIT_ASSERT_ARG(index);
Edward Thomson committed
2328

2329
	for (i = 0; i < index->reuc.length; ++i)
2330
		index_entry_reuc_free(git_atomic_swap(index->reuc.contents[i], NULL));
Edward Thomson committed
2331 2332

	git_vector_clear(&index->reuc);
2333 2334

	index->dirty = 1;
2335 2336

	return 0;
Edward Thomson committed
2337 2338
}

2339 2340
static int index_error_invalid(const char *message)
{
2341
	git_error_set(GIT_ERROR_INDEX, "invalid data in index - %s", message);
2342 2343 2344
	return -1;
}

Edward Thomson committed
2345
static int read_reuc(git_index *index, const char *buffer, size_t size)
2346
{
2347
	const char *endptr;
2348
	size_t oid_size = git_oid_size(index->oid_type);
2349
	size_t len;
2350 2351
	int i;

2352 2353 2354
	/* If called multiple times, the vector might already be initialized */
	if (index->reuc._alloc_size == 0 &&
		git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
2355
		return -1;
2356 2357

	while (size) {
Edward Thomson committed
2358
		git_index_reuc_entry *lost;
2359

2360
		len = p_strnlen(buffer, size) + 1;
2361
		if (size <= len)
Edward Thomson committed
2362
			return index_error_invalid("reading reuc entries");
2363

2364
		lost = reuc_entry_alloc(buffer);
2365
		GIT_ERROR_CHECK_ALLOC(lost);
2366 2367 2368 2369

		size -= len;
		buffer += len;

2370
		/* read 3 ASCII octal numbers for stage entries */
2371
		for (i = 0; i < 3; i++) {
2372
			int64_t tmp;
2373

2374
			if (git__strntol64(&tmp, buffer, size, &endptr, 8) < 0 ||
2375
				!endptr || endptr == buffer || *endptr ||
2376
				tmp < 0 || tmp > UINT32_MAX) {
2377
				index_entry_reuc_free(lost);
Edward Thomson committed
2378
				return index_error_invalid("reading reuc entry stage");
2379
			}
2380

2381
			lost->mode[i] = (uint32_t)tmp;
2382

2383
			len = (endptr + 1) - buffer;
2384 2385
			if (size <= len) {
				index_entry_reuc_free(lost);
Edward Thomson committed
2386
				return index_error_invalid("reading reuc entry stage");
2387
			}
2388

2389 2390 2391 2392
			size -= len;
			buffer += len;
		}

2393
		/* read up to 3 OIDs for stage entries */
2394 2395 2396
		for (i = 0; i < 3; i++) {
			if (!lost->mode[i])
				continue;
2397
			if (size < oid_size) {
2398
				index_entry_reuc_free(lost);
Edward Thomson committed
2399
				return index_error_invalid("reading reuc entry oid");
2400
			}
2401

2402
			if (git_oid__fromraw(&lost->oid[i], (const unsigned char *) buffer, index->oid_type) < 0)
Edward Thomson committed
2403 2404
				return -1;

2405 2406
			size -= oid_size;
			buffer += oid_size;
2407
		}
2408 2409 2410 2411

		/* entry was read successfully - insert into reuc vector */
		if (git_vector_insert(&index->reuc, lost) < 0)
			return -1;
2412 2413
	}

Edward Thomson committed
2414
	/* entries are guaranteed to be sorted on-disk */
2415
	git_vector_set_sorted(&index->reuc, true);
Edward Thomson committed
2416

2417
	return 0;
2418 2419
}

Edward Thomson committed
2420 2421 2422 2423

static int read_conflict_names(git_index *index, const char *buffer, size_t size)
{
	size_t len;
nulltoken committed
2424

Edward Thomson committed
2425 2426 2427 2428 2429 2430
	/* This gets called multiple times, the vector might already be initialized */
	if (index->names._alloc_size == 0 &&
		git_vector_init(&index->names, 16, conflict_name_cmp) < 0)
		return -1;

#define read_conflict_name(ptr) \
2431
	len = p_strnlen(buffer, size) + 1; \
2432 2433 2434 2435
	if (size < len) { \
		index_error_invalid("reading conflict name entries"); \
		goto out_err; \
	} \
Edward Thomson committed
2436 2437 2438 2439
	if (len == 1) \
		ptr = NULL; \
	else { \
		ptr = git__malloc(len); \
2440
		GIT_ERROR_CHECK_ALLOC(ptr); \
Edward Thomson committed
2441 2442 2443 2444 2445
		memcpy(ptr, buffer, len); \
	} \
	\
	buffer += len; \
	size -= len;
nulltoken committed
2446

Edward Thomson committed
2447 2448
	while (size) {
		git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry));
2449
		GIT_ERROR_CHECK_ALLOC(conflict_name);
Edward Thomson committed
2450 2451 2452 2453

		read_conflict_name(conflict_name->ancestor);
		read_conflict_name(conflict_name->ours);
		read_conflict_name(conflict_name->theirs);
nulltoken committed
2454

Edward Thomson committed
2455
		if (git_vector_insert(&index->names, conflict_name) < 0)
2456 2457 2458 2459 2460 2461 2462 2463 2464 2465
			goto out_err;

		continue;

out_err:
		git__free(conflict_name->ancestor);
		git__free(conflict_name->ours);
		git__free(conflict_name->theirs);
		git__free(conflict_name);
		return -1;
Edward Thomson committed
2466 2467 2468
	}

#undef read_conflict_name
nulltoken committed
2469

Edward Thomson committed
2470
	/* entries are guaranteed to be sorted on-disk */
2471
	git_vector_set_sorted(&index->names, true);
nulltoken committed
2472 2473

	return 0;
Edward Thomson committed
2474 2475
}

2476 2477 2478
GIT_INLINE(size_t) index_entry_path_offset(
	git_oid_t oid_type,
	uint32_t flags)
2479
{
2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
	if (oid_type == GIT_OID_SHA1)
		return (flags & GIT_INDEX_ENTRY_EXTENDED) ?
			offsetof(index_entry_long_sha1, path) :
			offsetof(index_entry_short_sha1, path);

#ifdef GIT_EXPERIMENTAL_SHA256
	else if (oid_type == GIT_OID_SHA256)
		return (flags & GIT_INDEX_ENTRY_EXTENDED) ?
			offsetof(index_entry_long_sha256, path) :
			offsetof(index_entry_short_sha256, path);
#endif

	git_error_set(GIT_ERROR_INTERNAL, "invalid oid type");
	return 0;
}

GIT_INLINE(size_t) index_entry_flags_offset(git_oid_t oid_type)
{
	if (oid_type == GIT_OID_SHA1)
		return offsetof(index_entry_long_sha1, flags_extended);

#ifdef GIT_EXPERIMENTAL_SHA256
	else if (oid_type == GIT_OID_SHA256)
		return offsetof(index_entry_long_sha256, flags_extended);
#endif

	git_error_set(GIT_ERROR_INTERNAL, "invalid oid type");
	return 0;
}

static size_t index_entry_size(
	size_t path_len,
	size_t varint_len,
	git_oid_t oid_type,
	uint32_t flags)
{
	size_t offset, size;

	if (!(offset = index_entry_path_offset(oid_type, flags)))
		return 0;

2521
	if (varint_len) {
2522 2523 2524 2525
		if (GIT_ADD_SIZET_OVERFLOW(&size, offset, path_len) ||
		    GIT_ADD_SIZET_OVERFLOW(&size, size, 1) ||
		    GIT_ADD_SIZET_OVERFLOW(&size, size, varint_len))
			return 0;
2526
	} else {
2527 2528 2529 2530 2531
		if (GIT_ADD_SIZET_OVERFLOW(&size, offset, path_len) ||
		    GIT_ADD_SIZET_OVERFLOW(&size, size, 8))
			return 0;

		size &= ~7;
2532
	}
2533 2534

	return size;
2535 2536
}

2537
static int read_entry(
2538
	git_index_entry **out,
2539
	size_t *out_size,
2540
	git_index *index,
2541
	size_t checksum_size,
2542
	const void *buffer,
David Turner committed
2543
	size_t buffer_size,
2544
	const char *last)
2545
{
2546
	size_t path_length, path_offset, entry_size;
2547
	const char *path_ptr;
2548 2549 2550 2551 2552
	struct entry_common *source_common;
	index_entry_short_sha1 source_sha1;
#ifdef GIT_EXPERIMENTAL_SHA256
	index_entry_short_sha256 source_sha256;
#endif
2553
	git_index_entry entry = {{0}};
David Turner committed
2554 2555
	bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP;
	char *tmp_path = NULL;
2556 2557

	size_t minimal_entry_size = index_entry_path_offset(index->oid_type, 0);
2558

2559
	if (checksum_size + minimal_entry_size > buffer_size)
2560
		return -1;
2561

2562
	/* buffer is not guaranteed to be aligned */
2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
	switch (index->oid_type) {
	case GIT_OID_SHA1:
		source_common = &source_sha1.common;
		memcpy(&source_sha1, buffer, sizeof(source_sha1));
		break;
#ifdef GIT_EXPERIMENTAL_SHA256
	case GIT_OID_SHA256:
		source_common = &source_sha256.common;
		memcpy(&source_sha256, buffer, sizeof(source_sha256));
		break;
#endif
	default:
		GIT_ASSERT(!"invalid oid type");
	}

	entry.ctime.seconds = (git_time_t)ntohl(source_common->ctime.seconds);
	entry.ctime.nanoseconds = ntohl(source_common->ctime.nanoseconds);
	entry.mtime.seconds = (git_time_t)ntohl(source_common->mtime.seconds);
	entry.mtime.nanoseconds = ntohl(source_common->mtime.nanoseconds);
	entry.dev = ntohl(source_common->dev);
	entry.ino = ntohl(source_common->ino);
	entry.mode = ntohl(source_common->mode);
	entry.uid = ntohl(source_common->uid);
	entry.gid = ntohl(source_common->gid);
	entry.file_size = ntohl(source_common->file_size);

	switch (index->oid_type) {
	case GIT_OID_SHA1:
		if (git_oid__fromraw(&entry.id, source_sha1.oid,
		                     GIT_OID_SHA1) < 0)
			return -1;
		entry.flags = ntohs(source_sha1.flags);
		break;
#ifdef GIT_EXPERIMENTAL_SHA256
	case GIT_OID_SHA256:
		if (git_oid__fromraw(&entry.id, source_sha256.oid,
		                     GIT_OID_SHA256) < 0)
			return -1;
		entry.flags = ntohs(source_sha256.flags);
		break;
#endif
	default:
		GIT_ASSERT(!"invalid oid type");
	}

	if (!(path_offset = index_entry_path_offset(index->oid_type, entry.flags)))
2609 2610
		return -1;

2611

2612
	if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) {
2613 2614
		uint16_t flags_raw;
		size_t flags_offset;
2615

2616 2617 2618 2619
		if (!(flags_offset = index_entry_flags_offset(index->oid_type)))
			return -1;

		memcpy(&flags_raw, (const char *)buffer + flags_offset, sizeof(flags_raw));
2620 2621 2622
		flags_raw = ntohs(flags_raw);

		memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw));
2623 2624 2625 2626
		path_ptr = (const char *)buffer + path_offset;
	} else {
		path_ptr = (const char *)buffer + path_offset;
	}
2627

David Turner committed
2628
	if (!compressed) {
2629
		path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK;
2630

David Turner committed
2631 2632 2633 2634
		/* if this is a very long string, we must find its
		 * real length without overflowing */
		if (path_length == 0xFFF) {
			const char *path_end;
2635

David Turner committed
2636 2637
			path_end = memchr(path_ptr, '\0', buffer_size);
			if (path_end == NULL)
2638
				return index_error_invalid("invalid path name");
2639

David Turner committed
2640 2641
			path_length = path_end - path_ptr;
		}
2642

2643
		entry_size = index_entry_size(path_length, 0, index->oid_type, entry.flags);
David Turner committed
2644 2645
		entry.path = (char *)path_ptr;
	} else {
2646 2647 2648 2649 2650 2651 2652
		size_t varint_len, last_len, prefix_len, suffix_len, path_len;
		uintmax_t strip_len;

		strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len);
		last_len = strlen(last);

		if (varint_len == 0 || last_len < strip_len)
David Turner committed
2653 2654
			return index_error_invalid("incorrect prefix length");

2655
		prefix_len = last_len - (size_t)strip_len;
2656 2657
		suffix_len = strlen(path_ptr + varint_len);

2658 2659
		GIT_ERROR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
		GIT_ERROR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
2660 2661 2662 2663

		if (path_len > GIT_PATH_MAX)
			return index_error_invalid("unreasonable path length");

2664
		tmp_path = git__malloc(path_len);
2665
		GIT_ERROR_CHECK_ALLOC(tmp_path);
2666 2667 2668

		memcpy(tmp_path, last, prefix_len);
		memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1);
2669 2670

		entry_size = index_entry_size(suffix_len, varint_len, index->oid_type, entry.flags);
David Turner committed
2671 2672 2673
		entry.path = tmp_path;
	}

2674 2675 2676
	if (entry_size == 0)
		return -1;

2677 2678
	if (checksum_size + entry_size > buffer_size) {
		git_error_set(GIT_ERROR_INTERNAL, "invalid index checksum");
2679
		return -1;
2680
	}
2681

David Turner committed
2682 2683
	if (index_entry_dup(out, index, &entry) < 0) {
		git__free(tmp_path);
2684
		return -1;
David Turner committed
2685
	}
2686

David Turner committed
2687
	git__free(tmp_path);
2688 2689
	*out_size = entry_size;
	return 0;
2690 2691 2692 2693
}

static int read_header(struct index_header *dest, const void *buffer)
{
2694
	const struct index_header *source = buffer;
2695

2696 2697
	dest->signature = ntohl(source->signature);
	if (dest->signature != INDEX_HEADER_SIG)
2698
		return index_error_invalid("incorrect header signature");
2699 2700

	dest->version = ntohl(source->version);
David Turner committed
2701 2702
	if (dest->version < INDEX_VERSION_NUMBER_LB ||
		dest->version > INDEX_VERSION_NUMBER_UB)
2703
		return index_error_invalid("incorrect header version");
2704 2705

	dest->entry_count = ntohl(source->entry_count);
2706
	return 0;
2707 2708
}

2709
static int read_extension(size_t *read_len, git_index *index, size_t checksum_size, const char *buffer, size_t buffer_size)
2710 2711 2712 2713
{
	struct index_extension dest;
	size_t total_size;

2714 2715 2716
	/* buffer is not guaranteed to be aligned */
	memcpy(&dest, buffer, sizeof(struct index_extension));
	dest.extension_size = ntohl(dest.extension_size);
2717 2718 2719

	total_size = dest.extension_size + sizeof(struct index_extension);

2720 2721
	if (dest.extension_size > total_size ||
		buffer_size < total_size ||
2722
		buffer_size - total_size < checksum_size) {
2723 2724 2725
		index_error_invalid("extension is truncated");
		return -1;
	}
2726 2727 2728 2729 2730

	/* optional extension */
	if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
		/* tree cache */
		if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
2731
			if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, index->oid_type, &index->tree_pool) < 0)
2732
				return -1;
2733
		} else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
Edward Thomson committed
2734
			if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
2735
				return -1;
Edward Thomson committed
2736 2737
		} else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
			if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
2738
				return -1;
2739
		}
2740 2741
		/* else, unsupported extension. We cannot parse this, but we can skip
		 * it by returning `total_size */
2742 2743 2744
	} else {
		/* we cannot handle non-ignorable extensions;
		 * in fact they aren't even defined in the standard */
2745 2746
		git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature);
		return -1;
2747 2748
	}

2749 2750 2751
	*read_len = total_size;

	return 0;
2752 2753
}

2754
static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
2755
{
2756
	int error = 0;
2757
	unsigned int i;
2758
	struct index_header header = { 0 };
2759 2760
	unsigned char checksum[GIT_HASH_MAX_SIZE];
	size_t checksum_size = git_hash_size(git_oid_algorithm(index->oid_type));
2761
	const char *last = NULL;
David Turner committed
2762
	const char *empty = "";
2763 2764

#define seek_forward(_increase) { \
2765 2766 2767
	if (_increase >= buffer_size) { \
		error = index_error_invalid("ran out of data while parsing"); \
		goto done; } \
2768 2769 2770 2771
	buffer += _increase; \
	buffer_size -= _increase;\
}

2772
	if (buffer_size < INDEX_HEADER_SIZE + checksum_size)
2773
		return index_error_invalid("insufficient buffer space");
2774

2775 2776 2777 2778 2779 2780
	/*
	 * Precalculate the hash of the files's contents -- we'll match
	 * it to the provided checksum in the footer.
	 */
	git_hash_buf(checksum, buffer, buffer_size - checksum_size,
		git_oid_algorithm(index->oid_type));
2781 2782

	/* Parse header */
2783 2784
	if ((error = read_header(&header, buffer)) < 0)
		return error;
2785

David Turner committed
2786 2787
	index->version = header.version;
	if (index->version >= INDEX_VERSION_NUMBER_COMP)
2788
		last = empty;
David Turner committed
2789

2790 2791
	seek_forward(INDEX_HEADER_SIZE);

Edward Thomson committed
2792
	GIT_ASSERT(!index->entries.length);
2793

2794
	if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0)
2795
		return error;
2796

2797
	/* Parse all the entries */
2798
	for (i = 0; i < header.entry_count && buffer_size > checksum_size; ++i) {
2799
		git_index_entry *entry = NULL;
2800
		size_t entry_size;
2801

2802
		if ((error = read_entry(&entry, &entry_size, index, checksum_size, buffer, buffer_size, last)) < 0) {
2803 2804 2805
			error = index_error_invalid("invalid entry");
			goto done;
		}
2806

2807 2808
		if ((error = git_vector_insert(&index->entries, entry)) < 0) {
			index_entry_free(entry);
2809
			goto done;
2810
		}
2811

2812
		if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) {
2813 2814 2815
			index_entry_free(entry);
			goto done;
		}
2816
		error = 0;
2817

2818 2819 2820
		if (index->version >= INDEX_VERSION_NUMBER_COMP)
			last = entry->path;

2821 2822 2823
		seek_forward(entry_size);
	}

2824 2825 2826 2827
	if (i != header.entry_count) {
		error = index_error_invalid("header entries changed while parsing");
		goto done;
	}
2828

2829
	/* There's still space for some extensions! */
2830
	while (buffer_size > checksum_size) {
2831 2832
		size_t extension_size;

2833
		if ((error = read_extension(&extension_size, index, checksum_size, buffer, buffer_size)) < 0) {
2834 2835
			goto done;
		}
2836 2837 2838 2839

		seek_forward(extension_size);
	}

2840
	if (buffer_size != checksum_size) {
2841 2842 2843 2844
		error = index_error_invalid(
			"buffer size does not match index footer size");
		goto done;
	}
2845

2846 2847 2848 2849
	/*
	 * SHA-1 or SHA-256 (depending on the repository's object format)
	 * over the content of the index file before this checksum.
	 */
2850
	if (memcmp(checksum, buffer, checksum_size) != 0) {
2851 2852 2853 2854
		error = index_error_invalid(
			"calculated checksum does not match expected");
		goto done;
	}
2855

2856
	memcpy(index->checksum, checksum, checksum_size);
2857

2858 2859
#undef seek_forward

2860 2861 2862 2863
	/* Entries are stored case-sensitively on disk, so re-sort now if
	 * in-memory index is supposed to be case-insensitive
	 */
	git_vector_set_sorted(&index->entries, !index->ignore_case);
2864
	git_vector_sort(&index->entries);
2865

2866
	index->dirty = 0;
2867 2868
done:
	return error;
2869 2870
}

2871
static bool is_index_extended(git_index *index)
Vicent Marti committed
2872
{
2873
	size_t i, extended;
2874
	git_index_entry *entry;
Vicent Marti committed
2875 2876 2877

	extended = 0;

2878
	git_vector_foreach(&index->entries, i, entry) {
2879 2880
		entry->flags &= ~GIT_INDEX_ENTRY_EXTENDED;
		if (entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS) {
Vicent Marti committed
2881
			extended++;
2882
			entry->flags |= GIT_INDEX_ENTRY_EXTENDED;
Vicent Marti committed
2883 2884
		}
	}
2885

2886
	return (extended > 0);
Vicent Marti committed
2887 2888
}

2889 2890 2891 2892 2893
static int write_disk_entry(
	git_index *index,
	git_filebuf *file,
	git_index_entry *entry,
	const char *last)
2894
{
2895
	void *mem = NULL;
2896 2897
	struct entry_common *ondisk_common;
	size_t path_len, path_offset, disk_size;
2898
	int varint_len = 0;
2899
	char *path;
David Turner committed
2900 2901
	const char *path_start = entry->path;
	size_t same_len = 0;
2902

2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
	index_entry_short_sha1 ondisk_sha1;
	index_entry_long_sha1 ondisk_ext_sha1;
#ifdef GIT_EXPERIMENTAL_SHA256
	index_entry_short_sha256 ondisk_sha256;
	index_entry_long_sha256 ondisk_ext_sha256;
#endif

	switch (index->oid_type) {
	case GIT_OID_SHA1:
		ondisk_common = &ondisk_sha1.common;
		break;
#ifdef GIT_EXPERIMENTAL_SHA256
	case GIT_OID_SHA256:
		ondisk_common = &ondisk_sha256.common;
		break;
#endif
	default:
		GIT_ASSERT(!"invalid oid type");
	}

2923
	path_len = ((struct entry_internal *)entry)->pathlen;
2924

David Turner committed
2925
	if (last) {
2926
		const char *last_c = last;
David Turner committed
2927 2928 2929 2930 2931 2932 2933 2934 2935

		while (*path_start == *last_c) {
			if (!*path_start || !*last_c)
				break;
			++path_start;
			++last_c;
			++same_len;
		}
		path_len -= same_len;
2936
		varint_len = git_encode_varint(NULL, 0, strlen(last) - same_len);
David Turner committed
2937 2938
	}

2939
	disk_size = index_entry_size(path_len, varint_len, index->oid_type, entry->flags);
2940

2941
	if (!disk_size || git_filebuf_reserve(file, &mem, disk_size) < 0)
2942
		return -1;
2943

2944
	memset(mem, 0x0, disk_size);
2945

2946 2947 2948 2949 2950 2951 2952 2953 2954 2955
	/**
	 * Yes, we have to truncate.
	 *
	 * The on-disk format for Index entries clearly defines
	 * the time and size fields to be 4 bytes each -- so even if
	 * we store these values with 8 bytes on-memory, they must
	 * be truncated to 4 bytes before writing to disk.
	 *
	 * In 2038 I will be either too dead or too rich to care about this
	 */
2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982
	ondisk_common->ctime.seconds = htonl((uint32_t)entry->ctime.seconds);
	ondisk_common->mtime.seconds = htonl((uint32_t)entry->mtime.seconds);
	ondisk_common->ctime.nanoseconds = htonl(entry->ctime.nanoseconds);
	ondisk_common->mtime.nanoseconds = htonl(entry->mtime.nanoseconds);
	ondisk_common->dev = htonl(entry->dev);
	ondisk_common->ino = htonl(entry->ino);
	ondisk_common->mode = htonl(entry->mode);
	ondisk_common->uid = htonl(entry->uid);
	ondisk_common->gid = htonl(entry->gid);
	ondisk_common->file_size = htonl((uint32_t)entry->file_size);

	switch (index->oid_type) {
	case GIT_OID_SHA1:
		git_oid_raw_cpy(ondisk_sha1.oid, entry->id.id, GIT_OID_SHA1_SIZE);
		ondisk_sha1.flags = htons(entry->flags);
		break;
#ifdef GIT_EXPERIMENTAL_SHA256
	case GIT_OID_SHA256:
		git_oid_raw_cpy(ondisk_sha256.oid, entry->id.id, GIT_OID_SHA256_SIZE);
		ondisk_sha256.flags = htons(entry->flags);
		break;
#endif
	default:
		GIT_ASSERT(!"invalid oid type");
	}

	path_offset = index_entry_path_offset(index->oid_type, entry->flags);
2983

2984
	if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) {
2985 2986
		struct entry_common *ondisk_ext;
		uint16_t flags_extended = htons(entry->flags_extended &
2987
			GIT_INDEX_ENTRY_EXTENDED_FLAGS);
2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008

		switch (index->oid_type) {
		case GIT_OID_SHA1:
			memcpy(&ondisk_ext_sha1, &ondisk_sha1,
				sizeof(index_entry_short_sha1));
			ondisk_ext_sha1.flags_extended = flags_extended;
			ondisk_ext = &ondisk_ext_sha1.common;
			break;
#ifdef GIT_EXPERIMENTAL_SHA256
		case GIT_OID_SHA256:
			memcpy(&ondisk_ext_sha256, &ondisk_sha256,
				sizeof(index_entry_short_sha256));
			ondisk_ext_sha256.flags_extended = flags_extended;
			ondisk_ext = &ondisk_ext_sha256.common;
			break;
#endif
		default:
			GIT_ASSERT(!"invalid oid type");
		}

		memcpy(mem, ondisk_ext, path_offset);
3009
	} else {
3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021
		switch (index->oid_type) {
		case GIT_OID_SHA1:
			memcpy(mem, &ondisk_sha1, path_offset);
			break;
#ifdef GIT_EXPERIMENTAL_SHA256
		case GIT_OID_SHA256:
			memcpy(mem, &ondisk_sha256, path_offset);
			break;
#endif
		default:
			GIT_ASSERT(!"invalid oid type");
		}
3022
	}
3023

3024 3025 3026
	path = (char *)mem + path_offset;
	disk_size -= path_offset;

David Turner committed
3027
	if (last) {
3028
		varint_len = git_encode_varint((unsigned char *) path,
3029
					  disk_size, strlen(last) - same_len);
Edward Thomson committed
3030 3031
		GIT_ASSERT(varint_len > 0);

3032 3033 3034 3035 3036 3037 3038
		path += varint_len;
		disk_size -= varint_len;

		/*
		 * If using path compression, we are not allowed
		 * to have additional trailing NULs.
		 */
Edward Thomson committed
3039
		GIT_ASSERT(disk_size == path_len + 1);
3040 3041 3042 3043 3044 3045
	} else {
		/*
		 * If no path compression is used, we do have
		 * NULs as padding. As such, simply assert that
		 * we have enough space left to write the path.
		 */
Edward Thomson committed
3046
		GIT_ASSERT(disk_size > path_len);
David Turner committed
3047
	}
3048 3049

	memcpy(path, path_start, path_len + 1);
3050

3051
	return 0;
3052 3053
}

3054
static int write_entries(git_index *index, git_filebuf *file)
3055
{
3056
	int error = 0;
3057
	size_t i;
3058
	git_vector case_sorted = GIT_VECTOR_INIT, *entries = NULL;
3059
	git_index_entry *entry;
3060
	const char *last = NULL;
3061 3062 3063 3064

	/* If index->entries is sorted case-insensitively, then we need
	 * to re-sort it case-sensitively before writing */
	if (index->ignore_case) {
3065
		if ((error = git_vector_dup(&case_sorted, &index->entries, git_index_entry_cmp)) < 0)
3066
			goto done;
3067

3068
		git_vector_sort(&case_sorted);
3069 3070 3071
		entries = &case_sorted;
	} else {
		entries = &index->entries;
3072 3073
	}

David Turner committed
3074
	if (index->version >= INDEX_VERSION_NUMBER_COMP)
3075
		last = "";
David Turner committed
3076

3077
	git_vector_foreach(entries, i, entry) {
3078
		if ((error = write_disk_entry(index, file, entry, last)) < 0)
3079
			break;
3080 3081 3082
		if (index->version >= INDEX_VERSION_NUMBER_COMP)
			last = entry->path;
	}
3083

3084 3085
done:
	git_vector_free(&case_sorted);
3086
	return error;
3087 3088
}

3089
static int write_extension(git_filebuf *file, struct index_extension *header, git_str *data)
Edward Thomson committed
3090 3091 3092 3093 3094 3095 3096
{
	struct index_extension ondisk;

	memset(&ondisk, 0x0, sizeof(struct index_extension));
	memcpy(&ondisk, header, 4);
	ondisk.extension_size = htonl(header->extension_size);

3097 3098
	git_filebuf_write(file, &ondisk, sizeof(struct index_extension));
	return git_filebuf_write(file, data->ptr, data->size);
Edward Thomson committed
3099 3100
}

3101
static int create_name_extension_data(git_str *name_buf, git_index_name_entry *conflict_name)
Edward Thomson committed
3102 3103 3104 3105
{
	int error = 0;

	if (conflict_name->ancestor == NULL)
3106
		error = git_str_put(name_buf, "\0", 1);
Edward Thomson committed
3107
	else
3108
		error = git_str_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1);
nulltoken committed
3109

Edward Thomson committed
3110 3111 3112 3113
	if (error != 0)
		goto on_error;

	if (conflict_name->ours == NULL)
3114
		error = git_str_put(name_buf, "\0", 1);
Edward Thomson committed
3115
	else
3116
		error = git_str_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1);
Edward Thomson committed
3117 3118 3119 3120 3121

	if (error != 0)
		goto on_error;

	if (conflict_name->theirs == NULL)
3122
		error = git_str_put(name_buf, "\0", 1);
Edward Thomson committed
3123
	else
3124
		error = git_str_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1);
Edward Thomson committed
3125 3126 3127 3128 3129 3130 3131

on_error:
	return error;
}

static int write_name_extension(git_index *index, git_filebuf *file)
{
3132
	git_str name_buf = GIT_STR_INIT;
Edward Thomson committed
3133 3134 3135 3136 3137
	git_vector *out = &index->names;
	git_index_name_entry *conflict_name;
	struct index_extension extension;
	size_t i;
	int error = 0;
nulltoken committed
3138

Edward Thomson committed
3139 3140 3141 3142
	git_vector_foreach(out, i, conflict_name) {
		if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0)
			goto done;
	}
nulltoken committed
3143

Edward Thomson committed
3144 3145 3146
	memset(&extension, 0x0, sizeof(struct index_extension));
	memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4);
	extension.extension_size = (uint32_t)name_buf.size;
nulltoken committed
3147

Edward Thomson committed
3148
	error = write_extension(file, &extension, &name_buf);
nulltoken committed
3149

3150
	git_str_dispose(&name_buf);
nulltoken committed
3151

Edward Thomson committed
3152 3153 3154 3155
done:
	return error;
}

3156
static int create_reuc_extension_data(git_str *reuc_buf, git_index *index, git_index_reuc_entry *reuc)
Edward Thomson committed
3157
{
3158
	size_t oid_size = git_oid_size(index->oid_type);
Edward Thomson committed
3159 3160 3161
	int i;
	int error = 0;

3162
	if ((error = git_str_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0)
Edward Thomson committed
3163 3164 3165
		return error;

	for (i = 0; i < 3; i++) {
3166 3167
		if ((error = git_str_printf(reuc_buf, "%o", reuc->mode[i])) < 0 ||
			(error = git_str_put(reuc_buf, "\0", 1)) < 0)
Edward Thomson committed
3168 3169 3170 3171
			return error;
	}

	for (i = 0; i < 3; i++) {
3172
		if (reuc->mode[i] && (error = git_str_put(reuc_buf, (char *)&reuc->oid[i].id, oid_size)) < 0)
Edward Thomson committed
3173 3174 3175 3176 3177 3178 3179 3180
			return error;
	}

	return 0;
}

static int write_reuc_extension(git_index *index, git_filebuf *file)
{
3181
	git_str reuc_buf = GIT_STR_INIT;
Edward Thomson committed
3182 3183 3184
	git_vector *out = &index->reuc;
	git_index_reuc_entry *reuc;
	struct index_extension extension;
3185
	size_t i;
Edward Thomson committed
3186 3187 3188
	int error = 0;

	git_vector_foreach(out, i, reuc) {
3189
		if ((error = create_reuc_extension_data(&reuc_buf, index, reuc)) < 0)
Edward Thomson committed
3190 3191 3192 3193 3194
			goto done;
	}

	memset(&extension, 0x0, sizeof(struct index_extension));
	memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4);
3195
	extension.extension_size = (uint32_t)reuc_buf.size;
Edward Thomson committed
3196 3197 3198

	error = write_extension(file, &extension, &reuc_buf);

3199
	git_str_dispose(&reuc_buf);
Edward Thomson committed
3200 3201 3202 3203 3204

done:
	return error;
}

3205 3206 3207
static int write_tree_extension(git_index *index, git_filebuf *file)
{
	struct index_extension extension;
3208
	git_str buf = GIT_STR_INIT;
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222
	int error;

	if (index->tree == NULL)
		return 0;

	if ((error = git_tree_cache_write(&buf, index->tree)) < 0)
		return error;

	memset(&extension, 0x0, sizeof(struct index_extension));
	memcpy(&extension.signature, INDEX_EXT_TREECACHE_SIG, 4);
	extension.extension_size = (uint32_t)buf.size;

	error = write_extension(file, &extension, &buf);

3223
	git_str_dispose(&buf);
3224 3225 3226 3227

	return error;
}

3228 3229 3230 3231 3232 3233
static void clear_uptodate(git_index *index)
{
	git_index_entry *entry;
	size_t i;

	git_vector_foreach(&index->entries, i, entry)
3234
		entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE;
3235 3236
}

3237
static int write_index(
3238
	unsigned char checksum[GIT_HASH_MAX_SIZE],
3239 3240 3241
	size_t *checksum_size,
	git_index *index,
	git_filebuf *file)
3242 3243
{
	struct index_header header;
3244
	bool is_extended;
Ben Straub committed
3245
	uint32_t index_version_number;
3246

Edward Thomson committed
3247 3248
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(file);
3249

3250 3251 3252
	GIT_ASSERT(index->oid_type);

	*checksum_size = git_hash_size(git_oid_algorithm(index->oid_type));
3253

David Turner committed
3254 3255 3256 3257 3258 3259
	if (index->version <= INDEX_VERSION_NUMBER_EXT)  {
		is_extended = is_index_extended(index);
		index_version_number = is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER_LB;
	} else {
		index_version_number = index->version;
	}
Vicent Marti committed
3260

3261
	header.signature = htonl(INDEX_HEADER_SIG);
Ben Straub committed
3262
	header.version = htonl(index_version_number);
3263
	header.entry_count = htonl((uint32_t)index->entries.length);
3264

3265 3266
	if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0)
		return -1;
3267

3268 3269
	if (write_entries(index, file) < 0)
		return -1;
3270

3271 3272 3273
	/* write the tree cache extension */
	if (index->tree != NULL && write_tree_extension(index, file) < 0)
		return -1;
Edward Thomson committed
3274

Edward Thomson committed
3275 3276 3277
	/* write the rename conflict extension */
	if (index->names.length > 0 && write_name_extension(index, file) < 0)
		return -1;
nulltoken committed
3278

Edward Thomson committed
3279 3280 3281
	/* write the reuc extension */
	if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0)
		return -1;
3282

3283
	/* get out the hash for all the contents we've appended to the file */
3284
	git_filebuf_hash(checksum, file);
3285 3286

	/* write it at the end of the file */
3287
	if (git_filebuf_write(file, checksum, *checksum_size) < 0)
3288 3289 3290 3291 3292 3293
		return -1;

	/* file entries are no longer up to date */
	clear_uptodate(index);

	return 0;
3294
}
3295 3296 3297

int git_index_entry_stage(const git_index_entry *entry)
{
3298
	return GIT_INDEX_ENTRY_STAGE(entry);
3299
}
3300

3301 3302
int git_index_entry_is_conflict(const git_index_entry *entry)
{
3303
	return (GIT_INDEX_ENTRY_STAGE(entry) > 0);
3304 3305
}

3306
typedef struct read_tree_data {
3307
	git_index *index;
3308
	git_vector *old_entries;
3309
	git_vector *new_entries;
3310
	git_vector_cmp entry_cmp;
3311
	git_tree_cache *tree;
3312 3313
} read_tree_data;

3314 3315
static int read_tree_cb(
	const char *root, const git_tree_entry *tentry, void *payload)
3316
{
3317 3318
	read_tree_data *data = payload;
	git_index_entry *entry = NULL, *old_entry;
3319
	git_str path = GIT_STR_INIT;
3320
	size_t pos;
3321

Vicent Martí committed
3322
	if (git_tree_entry__is_tree(tentry))
3323
		return 0;
3324

3325
	if (git_str_joinpath(&path, root, tentry->filename) < 0)
3326
		return -1;
3327

3328
	if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0)
3329
		return -1;
3330 3331

	entry->mode = tentry->attr;
3332
	git_oid_cpy(&entry->id, git_tree_entry_id(tentry));
3333

3334
	/* look for corresponding old entry and copy data to new entry */
3335
	if (data->old_entries != NULL &&
3336
		!index_find_in_entries(
3337 3338 3339 3340 3341
			&pos, data->old_entries, data->entry_cmp, path.ptr, 0, 0) &&
		(old_entry = git_vector_get(data->old_entries, pos)) != NULL &&
		entry->mode == old_entry->mode &&
		git_oid_equal(&entry->id, &old_entry->id))
	{
3342
		index_entry_cpy(entry, old_entry);
3343
		entry->flags_extended = 0;
3344 3345
	}

3346
	index_entry_adjust_namemask(entry, path.size);
3347
	git_str_dispose(&path);
3348

3349
	if (git_vector_insert(data->new_entries, entry) < 0) {
3350
		index_entry_free(entry);
3351 3352 3353 3354
		return -1;
	}

	return 0;
3355 3356
}

Ben Straub committed
3357
int git_index_read_tree(git_index *index, const git_tree *tree)
3358
{
3359 3360
	int error = 0;
	git_vector entries = GIT_VECTOR_INIT;
3361
	git_idxmap *entries_map;
3362
	read_tree_data data;
3363 3364 3365
	size_t i;
	git_index_entry *e;

3366
	if (git_idxmap_new(&entries_map) < 0)
3367
		return -1;
3368

3369
	git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
3370

3371
	data.index = index;
3372 3373
	data.old_entries = &index->entries;
	data.new_entries = &entries;
3374
	data.entry_cmp   = index->entries_search;
3375

3376 3377 3378
	index->tree = NULL;
	git_pool_clear(&index->tree_pool);

3379
	git_vector_sort(&index->entries);
3380

3381 3382
	if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0)
		goto cleanup;
3383

3384
	if ((error = index_map_resize(entries_map, entries.length, index->ignore_case)) < 0)
3385
		goto cleanup;
3386

3387
	git_vector_foreach(&entries, i, e) {
3388
		if ((error = index_map_set(entries_map, e, index->ignore_case)) < 0) {
3389
			git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map");
3390
			return error;
3391
		}
3392 3393
	}

3394 3395 3396 3397
	error = 0;

	git_vector_sort(&entries);

3398
	if ((error = git_index_clear(index)) < 0) {
3399 3400 3401
		/* well, this isn't good */;
	} else {
		git_vector_swap(&entries, &index->entries);
3402
		entries_map = git_atomic_swap(index->entries_map, entries_map);
3403 3404
	}

3405 3406
	index->dirty = 1;

3407
cleanup:
3408
	git_vector_free(&entries);
3409
	git_idxmap_free(entries_map);
3410 3411 3412
	if (error < 0)
		return error;

3413
	error = git_tree_cache_read_tree(&index->tree, tree, index->oid_type, &index->tree_pool);
3414 3415

	return error;
3416
}
3417

3418
static int git_index_read_iterator(
3419
	git_index *index,
3420 3421
	git_iterator *new_iterator,
	size_t new_length_hint)
3422 3423 3424
{
	git_vector new_entries = GIT_VECTOR_INIT,
		remove_entries = GIT_VECTOR_INIT;
3425
	git_idxmap *new_entries_map = NULL;
3426
	git_iterator *index_iterator = NULL;
3427
	git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
3428 3429 3430 3431 3432
	const git_index_entry *old_entry, *new_entry;
	git_index_entry *entry;
	size_t i;
	int error;

Edward Thomson committed
3433
	GIT_ASSERT((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
3434 3435

	if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 ||
3436 3437
	    (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
	    (error = git_idxmap_new(&new_entries_map)) < 0)
3438 3439
		goto done;

3440 3441
	if (new_length_hint && (error = index_map_resize(new_entries_map, new_length_hint,
							 index->ignore_case)) < 0)
3442
		goto done;
3443

3444 3445
	opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_CONFLICTS;
3446

3447 3448 3449
	if ((error = git_iterator_for_index(&index_iterator,
			git_index_owner(index), index, &opts)) < 0 ||
		((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
3450
			error != GIT_ITEROVER) ||
3451
		((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
3452 3453 3454 3455
			error != GIT_ITEROVER))
		goto done;

	while (true) {
3456 3457 3458 3459
		git_index_entry
			*dup_entry = NULL,
			*add_entry = NULL,
			*remove_entry = NULL;
3460 3461
		int diff;

3462 3463
		error = 0;

3464 3465 3466 3467 3468 3469 3470 3471 3472 3473
		if (old_entry && new_entry)
			diff = git_index_entry_cmp(old_entry, new_entry);
		else if (!old_entry && new_entry)
			diff = 1;
		else if (old_entry && !new_entry)
			diff = -1;
		else
			break;

		if (diff < 0) {
3474
			remove_entry = (git_index_entry *)old_entry;
3475
		} else if (diff > 0) {
3476
			dup_entry = (git_index_entry *)new_entry;
3477 3478 3479 3480
		} else {
			/* Path and stage are equal, if the OID is equal, keep it to
			 * keep the stat cache data.
			 */
3481 3482
			if (git_oid_equal(&old_entry->id, &new_entry->id) &&
				old_entry->mode == new_entry->mode) {
3483
				add_entry = (git_index_entry *)old_entry;
3484
			} else {
3485
				dup_entry = (git_index_entry *)new_entry;
3486
				remove_entry = (git_index_entry *)old_entry;
3487 3488 3489
			}
		}

3490 3491 3492
		if (dup_entry) {
			if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0)
				goto done;
3493 3494 3495

			index_entry_adjust_namemask(add_entry,
				((struct entry_internal *)add_entry)->pathlen);
3496 3497
		}

3498 3499 3500 3501 3502 3503
		/* invalidate this path in the tree cache if this is new (to
		 * invalidate the parent trees)
		 */
		if (dup_entry && !remove_entry && index->tree)
			git_tree_cache_invalidate_path(index->tree, dup_entry->path);

3504 3505
		if (add_entry) {
			if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
3506 3507
				error = index_map_set(new_entries_map, add_entry,
						      index->ignore_case);
3508 3509
		}

3510
		if (remove_entry && error >= 0)
3511 3512 3513
			error = git_vector_insert(&remove_entries, remove_entry);

		if (error < 0) {
3514
			git_error_set(GIT_ERROR_INDEX, "failed to insert entry");
3515
			goto done;
3516 3517
		}

3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530
		if (diff <= 0) {
			if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 &&
				error != GIT_ITEROVER)
				goto done;
		}

		if (diff >= 0) {
			if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 &&
				error != GIT_ITEROVER)
				goto done;
		}
	}

3531 3532 3533
	if ((error = git_index_name_clear(index)) < 0 ||
		(error = git_index_reuc_clear(index)) < 0)
	    goto done;
3534 3535

	git_vector_swap(&new_entries, &index->entries);
3536
	new_entries_map = git_atomic_swap(index->entries_map, new_entries_map);
3537 3538 3539 3540 3541 3542 3543 3544

	git_vector_foreach(&remove_entries, i, entry) {
		if (index->tree)
			git_tree_cache_invalidate_path(index->tree, entry->path);

		index_entry_free(entry);
	}

3545 3546
	clear_uptodate(index);

3547
	index->dirty = 1;
3548 3549 3550
	error = 0;

done:
3551
	git_idxmap_free(new_entries_map);
3552 3553 3554
	git_vector_free(&new_entries);
	git_vector_free(&remove_entries);
	git_iterator_free(index_iterator);
3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565
	return error;
}

int git_index_read_index(
	git_index *index,
	const git_index *new_index)
{
	git_iterator *new_iterator = NULL;
	git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
	int error;

3566 3567
	opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_CONFLICTS;
3568 3569

	if ((error = git_iterator_for_index(&new_iterator,
3570 3571 3572
		git_index_owner(new_index), (git_index *)new_index, &opts)) < 0 ||
		(error = git_index_read_iterator(index, new_iterator,
		new_index->entries.length)) < 0)
3573 3574 3575
		goto done;

done:
3576 3577 3578 3579
	git_iterator_free(new_iterator);
	return error;
}

3580 3581 3582 3583
git_repository *git_index_owner(const git_index *index)
{
	return INDEX_OWNER(index);
}
3584

3585 3586 3587 3588
enum {
	INDEX_ACTION_NONE = 0,
	INDEX_ACTION_UPDATE = 1,
	INDEX_ACTION_REMOVE = 2,
3589
	INDEX_ACTION_ADDALL = 3
3590 3591
};

3592 3593 3594 3595 3596 3597 3598 3599 3600
int git_index_add_all(
	git_index *index,
	const git_strarray *paths,
	unsigned int flags,
	git_index_matched_path_cb cb,
	void *payload)
{
	int error;
	git_repository *repo;
3601
	git_pathspec ps;
3602 3603
	bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;

Edward Thomson committed
3604
	GIT_ASSERT_ARG(index);
3605 3606 3607 3608 3609

	repo = INDEX_OWNER(index);
	if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
		return error;

3610
	if ((error = git_pathspec__init(&ps, paths)) < 0)
3611 3612 3613 3614 3615 3616 3617 3618 3619
		return error;

	/* optionally check that pathspec doesn't mention any ignored files */
	if ((flags & GIT_INDEX_ADD_CHECK_PATHSPEC) != 0 &&
		(flags & GIT_INDEX_ADD_FORCE) == 0 &&
		(error = git_ignore__check_pathspec_for_exact_ignores(
			repo, &ps.pathspec, no_fnmatch)) < 0)
		goto cleanup;

3620
	error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload);
3621

3622
	if (error)
3623
		git_error_set_after_callback(error);
3624 3625

cleanup:
3626
	git_pathspec__clear(&ps);
3627 3628 3629 3630

	return error;
}

3631 3632 3633
struct foreach_diff_data {
	git_index *index;
	const git_pathspec *pathspec;
3634
	unsigned int flags;
3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662
	git_index_matched_path_cb cb;
	void *payload;
};

static int apply_each_file(const git_diff_delta *delta, float progress, void *payload)
{
	struct foreach_diff_data *data = payload;
	const char *match, *path;
	int error = 0;

	GIT_UNUSED(progress);

	path = delta->old_file.path;

	/* We only want those which match the pathspecs */
	if (!git_pathspec__match(
		    &data->pathspec->pathspec, path, false, (bool)data->index->ignore_case,
		    &match, NULL))
		return 0;

	if (data->cb)
		error = data->cb(path, match, data->payload);

	if (error > 0) /* skip this entry */
		return 0;
	if (error < 0) /* actual error */
		return error;

3663 3664
	/* If the workdir item does not exist, remove it from the index. */
	if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
3665 3666
		error = git_index_remove_bypath(data->index, path);
	else
3667
		error = git_index_add_bypath(data->index, delta->new_file.path);
3668 3669 3670 3671 3672

	return error;
}

static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
3673
				  unsigned int flags,
3674 3675 3676 3677 3678 3679
				  git_index_matched_path_cb cb, void *payload)
{
	int error;
	git_diff *diff;
	git_pathspec ps;
	git_repository *repo;
3680
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
3681 3682 3683
	struct foreach_diff_data data = {
		index,
		NULL,
3684
		flags,
3685 3686 3687 3688
		cb,
		payload,
	};

Edward Thomson committed
3689 3690
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
3691 3692 3693 3694 3695 3696 3697 3698 3699

	repo = INDEX_OWNER(index);

	if (!repo) {
		return create_index_error(-1,
			"cannot run update; the index is not backed up by a repository.");
	}

	/*
Dimitris Apostolou committed
3700
	 * We do the matching ourselves instead of passing the list to
3701 3702 3703 3704 3705 3706
	 * diff because we want to tell the callback which one
	 * matched, which we do not know if we ask diff to filter for us.
	 */
	if ((error = git_pathspec__init(&ps, paths)) < 0)
		return error;

3707
	opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
3708
	if (action == INDEX_ACTION_ADDALL) {
3709
		opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
3710
			GIT_DIFF_RECURSE_UNTRACKED_DIRS;
3711

3712
		if (flags == GIT_INDEX_ADD_FORCE)
3713 3714
			opts.flags |= GIT_DIFF_INCLUDE_IGNORED |
			              GIT_DIFF_RECURSE_IGNORED_DIRS;
3715 3716 3717
	}

	if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0)
3718 3719 3720
		goto cleanup;

	data.pathspec = &ps;
3721
	error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data);
3722 3723 3724
	git_diff_free(diff);

	if (error) /* make sure error is set if callback stopped iteration */
3725
		git_error_set_after_callback(error);
3726 3727 3728 3729 3730 3731

cleanup:
	git_pathspec__clear(&ps);
	return error;
}

3732 3733 3734 3735 3736 3737 3738 3739 3740
static int index_apply_to_all(
	git_index *index,
	int action,
	const git_strarray *paths,
	git_index_matched_path_cb cb,
	void *payload)
{
	int error = 0;
	size_t i;
3741
	git_pathspec ps;
3742
	const char *match;
3743
	git_str path = GIT_STR_INIT;
3744

Edward Thomson committed
3745
	GIT_ASSERT_ARG(index);
3746

3747
	if ((error = git_pathspec__init(&ps, paths)) < 0)
3748 3749 3750 3751 3752 3753 3754 3755
		return error;

	git_vector_sort(&index->entries);

	for (i = 0; !error && i < index->entries.length; ++i) {
		git_index_entry *entry = git_vector_get(&index->entries, i);

		/* check if path actually matches */
3756
		if (!git_pathspec__match(
Linquize committed
3757
				&ps.pathspec, entry->path, false, (bool)index->ignore_case,
3758
				&match, NULL))
3759 3760 3761 3762 3763 3764 3765 3766
			continue;

		/* issue notification callback if requested */
		if (cb && (error = cb(entry->path, match, payload)) != 0) {
			if (error > 0) { /* return > 0 means skip this one */
				error = 0;
				continue;
			}
3767
			if (error < 0)   /* return < 0 means abort */
3768 3769 3770
				break;
		}

3771
		/* index manipulation may alter entry, so don't depend on it */
3772
		if ((error = git_str_sets(&path, entry->path)) < 0)
3773 3774
			break;

3775 3776 3777 3778
		switch (action) {
		case INDEX_ACTION_NONE:
			break;
		case INDEX_ACTION_UPDATE:
3779
			error = git_index_add_bypath(index, path.ptr);
3780 3781

			if (error == GIT_ENOTFOUND) {
3782
				git_error_clear();
3783

3784
				error = git_index_remove_bypath(index, path.ptr);
3785 3786 3787 3788 3789 3790

				if (!error) /* back up foreach if we removed this */
					i--;
			}
			break;
		case INDEX_ACTION_REMOVE:
3791
			if (!(error = git_index_remove_bypath(index, path.ptr)))
3792 3793 3794
				i--; /* back up foreach if we removed this */
			break;
		default:
3795
			git_error_set(GIT_ERROR_INVALID, "unknown index action %d", action);
3796 3797 3798 3799 3800
			error = -1;
			break;
		}
	}

3801
	git_str_dispose(&path);
3802
	git_pathspec__clear(&ps);
3803 3804 3805 3806 3807 3808 3809 3810 3811 3812

	return error;
}

int git_index_remove_all(
	git_index *index,
	const git_strarray *pathspec,
	git_index_matched_path_cb cb,
	void *payload)
{
3813
	int error = index_apply_to_all(
3814
		index, INDEX_ACTION_REMOVE, pathspec, cb, payload);
3815 3816

	if (error) /* make sure error is set if callback stopped iteration */
3817
		git_error_set_after_callback(error);
3818 3819

	return error;
3820 3821 3822 3823 3824 3825 3826 3827
}

int git_index_update_all(
	git_index *index,
	const git_strarray *pathspec,
	git_index_matched_path_cb cb,
	void *payload)
{
3828
	int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload);
3829
	if (error) /* make sure error is set if callback stopped iteration */
3830
		git_error_set_after_callback(error);
3831 3832

	return error;
3833
}
3834

3835
int git_index_snapshot_new(git_vector *snap, git_index *index)
3836 3837 3838 3839
{
	int error;

	GIT_REFCOUNT_INC(index);
3840

3841
	git_atomic32_inc(&index->readers);
3842
	git_vector_sort(&index->entries);
3843

3844
	error = git_vector_dup(snap, &index->entries, index->entries._cmp);
3845 3846

	if (error < 0)
3847
		git_index_snapshot_release(snap, index);
3848 3849 3850 3851

	return error;
}

3852
void git_index_snapshot_release(git_vector *snap, git_index *index)
3853
{
3854 3855
	git_vector_free(snap);

3856
	git_atomic32_dec(&index->readers);
3857

3858
	git_index_free(index);
3859
}
3860 3861 3862 3863 3864 3865 3866

int git_index_snapshot_find(
	size_t *out, git_vector *entries, git_vector_cmp entry_srch,
	const char *path, size_t path_len, int stage)
{
	return index_find_in_entries(out, entries, entry_srch, path, path_len, stage);
}
3867 3868 3869 3870 3871

int git_indexwriter_init(
	git_indexwriter *writer,
	git_index *index)
{
3872
	int filebuf_hash, error;
3873

3874 3875
	GIT_REFCOUNT_INC(index);

3876 3877
	writer->index = index;

3878
	filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(index->oid_type));
3879 3880
	GIT_ASSERT(filebuf_hash);

3881 3882
	if (!index->index_file_path)
		return create_index_error(-1,
3883
			"failed to write index: The index is in-memory only");
3884

3885 3886 3887 3888
	if ((error = git_filebuf_open(&writer->file,
			index->index_file_path,
			git_filebuf_hash_flags(filebuf_hash),
			GIT_INDEX_FILE_MODE)) < 0) {
3889
		if (error == GIT_ELOCKED)
3890
			git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process");
3891 3892 3893 3894

		return error;
	}

3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914
	writer->should_write = 1;

	return 0;
}

int git_indexwriter_init_for_operation(
	git_indexwriter *writer,
	git_repository *repo,
	unsigned int *checkout_strategy)
{
	git_index *index;
	int error;

	if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
		(error = git_indexwriter_init(writer, index)) < 0)
		return error;

	writer->should_write = (*checkout_strategy & GIT_CHECKOUT_DONT_WRITE_INDEX) == 0;
	*checkout_strategy |= GIT_CHECKOUT_DONT_WRITE_INDEX;

3915 3916 3917 3918 3919
	return 0;
}

int git_indexwriter_commit(git_indexwriter *writer)
{
3920
	unsigned char checksum[GIT_HASH_MAX_SIZE];
3921
	size_t checksum_size;
3922 3923
	int error;

3924 3925 3926
	if (!writer->should_write)
		return 0;

3927
	git_vector_sort(&writer->index->entries);
3928 3929
	git_vector_sort(&writer->index->reuc);

3930
	if ((error = write_index(checksum, &checksum_size, writer->index, &writer->file)) < 0) {
3931 3932 3933 3934 3935 3936 3937 3938 3939
		git_indexwriter_cleanup(writer);
		return error;
	}

	if ((error = git_filebuf_commit(&writer->file)) < 0)
		return error;

	if ((error = git_futils_filestamp_check(
		&writer->index->stamp, writer->index->index_file_path)) < 0) {
3940
		git_error_set(GIT_ERROR_OS, "could not read index timestamp");
3941 3942 3943
		return -1;
	}

3944
	writer->index->dirty = 0;
3945
	writer->index->on_disk = 1;
3946
	memcpy(writer->index->checksum, checksum, checksum_size);
3947

3948 3949 3950
	git_index_free(writer->index);
	writer->index = NULL;

3951 3952 3953 3954 3955 3956
	return 0;
}

void git_indexwriter_cleanup(git_indexwriter *writer)
{
	git_filebuf_cleanup(&writer->file);
3957 3958 3959

	git_index_free(writer->index);
	writer->index = NULL;
3960
}
3961 3962 3963

/* Deprecated functions */

3964
#ifndef GIT_DEPRECATE_HARD
3965 3966 3967 3968 3969 3970
int git_index_add_frombuffer(
    git_index *index, const git_index_entry *source_entry,
    const void *buffer, size_t len)
{
	return git_index_add_from_buffer(index, source_entry, buffer, len);
}
3971
#endif