index.c 90 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

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

30 31 32 33
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);

34 35 36 37 38
#define minimal_entry_size (offsetof(struct entry_short, path))

static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ;
static const size_t INDEX_HEADER_SIZE = 12;

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

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

50 51
#define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx)))

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

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

63 64 65 66 67
struct entry_time {
	uint32_t seconds;
	uint32_t nanoseconds;
};

68
struct entry_short {
69 70
	struct entry_time ctime;
	struct entry_time mtime;
71 72 73 74 75 76 77 78
	uint32_t dev;
	uint32_t ino;
	uint32_t mode;
	uint32_t uid;
	uint32_t gid;
	uint32_t file_size;
	git_oid oid;
	uint16_t flags;
schu committed
79
	char path[1]; /* arbitrary length */
80 81 82
};

struct entry_long {
83 84
	struct entry_time ctime;
	struct entry_time mtime;
85 86 87 88 89 90 91 92 93
	uint32_t dev;
	uint32_t ino;
	uint32_t mode;
	uint32_t uid;
	uint32_t gid;
	uint32_t file_size;
	git_oid oid;
	uint16_t flags;
	uint16_t flags_extended;
schu committed
94
	char path[1]; /* arbitrary length */
95 96
};

Edward Thomson committed
97 98
struct entry_srch_key {
	const char *path;
99
	size_t pathlen;
Edward Thomson committed
100 101 102
	int stage;
};

103 104 105 106 107 108 109 110 111 112 113 114
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];
};

115 116
bool git_index__enforce_unsaved_safety = false;

117
/* local declarations */
118
static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size);
119 120
static int read_header(struct index_header *dest, const void *buffer);

121
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
122
static bool is_index_extended(git_index *index);
123
static int write_index(git_oid *checksum, git_index *index, git_filebuf *file);
124

125
static void index_entry_free(git_index_entry *entry);
Edward Thomson committed
126 127
static void index_entry_reuc_free(git_index_reuc_entry *reuc);

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
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);
}

144 145 146 147 148 149 150 151
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);
}

152
int git_index_entry_srch(const void *key, const void *array_member)
153
{
Edward Thomson committed
154
	const struct entry_srch_key *srch_key = key;
155
	const struct entry_internal *entry = array_member;
156 157
	int cmp;
	size_t len1, len2, len;
158

159 160
	len1 = srch_key->pathlen;
	len2 = entry->pathlen;
161
	len = len1 < len2 ? len1 : len2;
Edward Thomson committed
162

163 164 165 166 167 168 169
	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
170

171
	if (srch_key->stage != GIT_INDEX_STAGE_ANY)
172
		return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
173 174

	return 0;
175 176
}

177
int git_index_entry_isrch(const void *key, const void *array_member)
178
{
Edward Thomson committed
179
	const struct entry_srch_key *srch_key = key;
180
	const struct entry_internal *entry = array_member;
181 182
	int cmp;
	size_t len1, len2, len;
Edward Thomson committed
183

184 185
	len1 = srch_key->pathlen;
	len2 = entry->pathlen;
186
	len = len1 < len2 ? len1 : len2;
Edward Thomson committed
187

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

190 191 192 193 194 195 196 197
	if (cmp)
		return cmp;
	if (len1 < len2)
		return -1;
	if (len1 > len2)
		return 1;

	if (srch_key->stage != GIT_INDEX_STAGE_ANY)
198
		return srch_key->stage - GIT_INDEX_ENTRY_STAGE(&entry->entry);
199 200

	return 0;
Edward Thomson committed
201 202
}

203
static int index_entry_srch_path(const void *path, const void *array_member)
Edward Thomson committed
204
{
205 206
	const git_index_entry *entry = array_member;

Edward Thomson committed
207 208 209
	return strcmp((const char *)path, entry->path);
}

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

	return strcasecmp((const char *)path, entry->path);
215 216
}

217
int git_index_entry_cmp(const void *a, const void *b)
218
{
Edward Thomson committed
219
	int diff;
220 221
	const git_index_entry *entry_a = a;
	const git_index_entry *entry_b = b;
222

Edward Thomson committed
223 224 225
	diff = strcmp(entry_a->path, entry_b->path);

	if (diff == 0)
226
		diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
Edward Thomson committed
227 228

	return diff;
229 230
}

231
int git_index_entry_icmp(const void *a, const void *b)
232
{
Edward Thomson committed
233
	int diff;
234 235 236
	const git_index_entry *entry_a = a;
	const git_index_entry *entry_b = b;

Edward Thomson committed
237 238 239
	diff = strcasecmp(entry_a->path, entry_b->path);

	if (diff == 0)
240
		diff = (GIT_INDEX_ENTRY_STAGE(entry_a) - GIT_INDEX_ENTRY_STAGE(entry_b));
Edward Thomson committed
241 242 243 244

	return diff;
}

Edward Thomson committed
245 246 247 248
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;
249

Edward Thomson committed
250 251
	if (name_a->ancestor && !name_b->ancestor)
		return 1;
252

Edward Thomson committed
253 254
	if (!name_a->ancestor && name_b->ancestor)
		return -1;
255

Edward Thomson committed
256 257
	if (name_a->ancestor)
		return strcmp(name_a->ancestor, name_b->ancestor);
258

Edward Thomson committed
259 260
	if (!name_a->ours || !name_b->ours)
		return 0;
261

Edward Thomson committed
262 263 264
	return strcmp(name_a->ours, name_b->ours);
}

Vicent Marti committed
265 266 267
/**
 * TODO: enable this when resolving case insensitive conflicts
 */
268
#if 0
Edward Thomson committed
269 270 271 272
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;
273

Edward Thomson committed
274 275
	if (name_a->ancestor && !name_b->ancestor)
		return 1;
276

Edward Thomson committed
277 278
	if (!name_a->ancestor && name_b->ancestor)
		return -1;
279

Edward Thomson committed
280 281
	if (name_a->ancestor)
		return strcasecmp(name_a->ancestor, name_b->ancestor);
282

Edward Thomson committed
283 284
	if (!name_a->ours || !name_b->ours)
		return 0;
285

Edward Thomson committed
286 287
	return strcasecmp(name_a->ours, name_b->ours);
}
288
#endif
Edward Thomson committed
289

Edward Thomson committed
290 291 292 293 294
static int reuc_srch(const void *key, const void *array_member)
{
	const git_index_reuc_entry *reuc = array_member;

	return strcmp(key, reuc->path);
295 296
}

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

Edward Thomson committed
301
	return strcasecmp(key, reuc->path);
302 303
}

Edward Thomson committed
304
static int reuc_cmp(const void *a, const void *b)
305
{
Edward Thomson committed
306 307
	const git_index_reuc_entry *info_a = a;
	const git_index_reuc_entry *info_b = b;
308 309 310

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

Edward Thomson committed
312 313 314 315 316 317 318 319
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);
}

320 321 322 323 324 325 326
static void index_entry_reuc_free(git_index_reuc_entry *reuc)
{
	git__free(reuc);
}

static void index_entry_free(git_index_entry *entry)
{
327 328 329
	if (!entry)
		return;

330
	memset(&entry->id, 0, sizeof(entry->id));
331 332 333
	git__free(entry);
}

334
unsigned int git_index__create_mode(unsigned int mode)
335 336 337
{
	if (S_ISLNK(mode))
		return S_IFLNK;
338

339 340
	if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR))
		return (S_IFLNK | S_IFDIR);
341

342
	return S_IFREG | GIT_PERMS_CANONICAL(mode);
343 344
}

345 346 347 348 349 350 351 352 353
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)) ?
354
			existing->mode : git_index__create_mode(0666);
355

356
	return git_index__create_mode(mode);
357 358
}

359 360 361 362 363 364 365 366 367 368 369 370 371
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,
372
	const char *path, size_t path_len, int stage)
373
{
374
	git_vector_sort(&index->entries);
375 376 377 378 379

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

380
void git_index__set_ignore_case(git_index *index, bool ignore_case)
381
{
382 383
	index->ignore_case = ignore_case;

384 385 386 387 388 389 390 391 392 393 394
	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;
	}
395

396 397
	git_vector_set_cmp(&index->entries,
		ignore_case ? git_index_entry_icmp : git_index_entry_cmp);
398
	git_vector_sort(&index->entries);
Edward Thomson committed
399

400
	git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
Edward Thomson committed
401
	git_vector_sort(&index->reuc);
402 403
}

404
int git_index_open(git_index **index_out, const char *index_path)
405 406
{
	git_index *index;
407
	int error = -1;
408

Edward Thomson committed
409
	GIT_ASSERT_ARG(index_out);
410

411
	index = git__calloc(1, sizeof(git_index));
412
	GIT_ERROR_CHECK_ALLOC(index);
413

414 415
	if (git_pool_init(&index->tree_pool, 1) < 0)
		goto fail;
416

417 418
	if (index_path != NULL) {
		index->index_file_path = git__strdup(index_path);
419 420
		if (!index->index_file_path)
			goto fail;
421 422 423 424 425

		/* Check if index file is stored on disk already */
		if (git_path_exists(index->index_file_path) == true)
			index->on_disk = 1;
	}
426

427
	if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
428 429 430 431
	    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)
432
		goto fail;
433

434 435 436
	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
437
	index->reuc_search = reuc_srch;
David Turner committed
438
	index->version = INDEX_VERSION_NUMBER_DEFAULT;
439

440 441
	if (index_path != NULL && (error = git_index_read(index, true)) < 0)
		goto fail;
442

Vicent Marti committed
443
	*index_out = index;
444
	GIT_REFCOUNT_INC(index);
445

446
	return 0;
447 448

fail:
449
	git_pool_clear(&index->tree_pool);
450 451
	git_index_free(index);
	return error;
452 453
}

454 455 456 457 458
int git_index_new(git_index **out)
{
	return git_index_open(out, NULL);
}

459
static void index_free(git_index *index)
460
{
461 462 463
	/* index iterators increment the refcount of the index, so if we
	 * get here then there should be no outstanding iterators.
	 */
464
	if (git_atomic32_get(&index->readers))
Edward Thomson committed
465
		return;
466

467
	git_index_clear(index);
468
	git_idxmap_free(index->entries_map);
469
	git_vector_free(&index->entries);
Edward Thomson committed
470
	git_vector_free(&index->names);
Edward Thomson committed
471
	git_vector_free(&index->reuc);
472
	git_vector_free(&index->deleted);
473

474
	git__free(index->index_file_path);
475

476
	git__memzero(index, sizeof(*index));
477
	git__free(index);
478 479
}

480 481
void git_index_free(git_index *index)
{
482
	if (index == NULL)
483 484
		return;

485
	GIT_REFCOUNT_DEC(index, index_free);
486 487
}

488 489
/* call with locked index */
static void index_free_deleted(git_index *index)
490
{
491
	int readers = (int)git_atomic32_get(&index->readers);
492
	size_t i;
493

494
	if (readers > 0 || !index->deleted.length)
495 496
		return;

497
	for (i = 0; i < index->deleted.length; ++i) {
498
		git_index_entry *ie = git_atomic_swap(index->deleted.contents[i], NULL);
499 500
		index_entry_free(ie);
	}
501 502 503 504

	git_vector_clear(&index->deleted);
}

505 506
/* call with locked index */
static int index_remove_entry(git_index *index, size_t pos)
507 508 509 510
{
	int error = 0;
	git_index_entry *entry = git_vector_get(&index->entries, pos);

511
	if (entry != NULL) {
512
		git_tree_cache_invalidate_path(index->tree, entry->path);
513
		index_map_delete(index->entries_map, entry, index->ignore_case);
514
	}
515 516 517 518

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

	if (!error) {
519
		if (git_atomic32_get(&index->readers) > 0) {
520
			error = git_vector_insert(&index->deleted, entry);
521
		} else {
522
			index_entry_free(entry);
523
		}
524 525

		index->dirty = 1;
526 527 528
	}

	return error;
529
}
530

531
int git_index_clear(git_index *index)
532
{
533 534
	int error = 0;

Edward Thomson committed
535
	GIT_ASSERT_ARG(index);
536

537
	index->dirty = 1;
538
	index->tree = NULL;
539
	git_pool_clear(&index->tree_pool);
540

541
	git_idxmap_clear(index->entries_map);
542
	while (!error && index->entries.length > 0)
543
		error = index_remove_entry(index, index->entries.length - 1);
544 545 546 547

	if (error)
		goto done;

548 549
	index_free_deleted(index);

550 551 552
	if ((error = git_index_name_clear(index)) < 0 ||
		(error = git_index_reuc_clear(index)) < 0)
	    goto done;
nulltoken committed
553

554
	git_futils_filestamp_set(&index->stamp, NULL);
555

556
done:
557
	return error;
558 559
}

560 561
static int create_index_error(int error, const char *msg)
{
562
	git_error_set_str(GIT_ERROR_INDEX, msg);
563 564 565
	return error;
}

Russell Belfer committed
566
int git_index_set_caps(git_index *index, int caps)
567
{
Linquize committed
568
	unsigned int old_ignore_case;
569

Edward Thomson committed
570
	GIT_ASSERT_ARG(index);
571

572 573
	old_ignore_case = index->ignore_case;

574
	if (caps == GIT_INDEX_CAPABILITY_FROM_OWNER) {
575
		git_repository *repo = INDEX_OWNER(index);
576 577
		int val;

578 579
		if (!repo)
			return create_index_error(
580
				-1, "cannot access repository to set index caps");
581

582
		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_IGNORECASE))
583
			index->ignore_case = (val != 0);
584
		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FILEMODE))
585
			index->distrust_filemode = (val == 0);
586
		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_SYMLINKS))
587
			index->no_symlinks = (val == 0);
588 589
	}
	else {
590 591 592
		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);
593 594
	}

595
	if (old_ignore_case != index->ignore_case) {
Linquize committed
596
		git_index__set_ignore_case(index, (bool)index->ignore_case);
597 598
	}

599 600 601
	return 0;
}

Russell Belfer committed
602
int git_index_caps(const git_index *index)
603
{
604 605 606
	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));
607 608
}

609 610 611 612 613 614 615 616 617 618
const git_oid *git_index_checksum(git_index *index)
{
	return &index->checksum;
}

/**
 * Returns 1 for changed, 0 for not changed and <0 for errors
 */
static int compare_checksum(git_index *index)
{
619
	int fd;
620 621 622 623 624 625
	ssize_t bytes_read;
	git_oid checksum = {{ 0 }};

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

626
	if (p_lseek(fd, -20, SEEK_END) < 0) {
627
		p_close(fd);
628
		git_error_set(GIT_ERROR_OS, "failed to seek to end of file");
629 630 631 632 633 634 635 636 637 638 639 640
		return -1;
	}

	bytes_read = p_read(fd, &checksum, GIT_OID_RAWSZ);
	p_close(fd);

	if (bytes_read < 0)
		return -1;

	return !!git_oid_cmp(&checksum, &index->checksum);
}

641
int git_index_read(git_index *index, int force)
642
{
643
	int error = 0, updated;
644
	git_buf buffer = GIT_BUF_INIT;
645
	git_futils_filestamp stamp = index->stamp;
646

647 648
	if (!index->index_file_path)
		return create_index_error(-1,
649
			"failed to read index: The index is in-memory only");
650

651 652 653
	index->on_disk = git_path_exists(index->index_file_path);

	if (!index->on_disk) {
654 655 656 657
		if (force && (error = git_index_clear(index)) < 0)
			return error;

		index->dirty = 0;
658
		return 0;
659 660
	}

661 662
	if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) ||
	    ((updated = compare_checksum(index)) < 0)) {
663 664
		git_error_set(
			GIT_ERROR_INDEX,
665
			"failed to read index: '%s' no longer exists",
666
			index->index_file_path);
667
		return updated;
668
	}
669

670 671
	if (!updated && !force)
		return 0;
672 673

	error = git_futils_readbuffer(&buffer, index->index_file_path);
674 675
	if (error < 0)
		return error;
676

677 678 679
	index->tree = NULL;
	git_pool_clear(&index->tree_pool);

680 681 682 683
	error = git_index_clear(index);

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

685
	if (!error) {
686
		git_futils_filestamp_set(&index->stamp, &stamp);
687 688
		index->dirty = 0;
	}
689

690
	git_buf_dispose(&buffer);
691 692 693
	return error;
}

694 695
int git_index_read_safely(git_index *index)
{
696
	if (git_index__enforce_unsaved_safety && index->dirty) {
697
		git_error_set(GIT_ERROR_INDEX,
698
			"the index has unsaved changes that would be overwritten by this operation");
699
		return GIT_EINDEXDIRTY;
700 701 702 703 704
	}

	return git_index_read(index, false);
}

705
int git_index__changed_relative_to(
706
	git_index *index, const git_oid *checksum)
707 708 709
{
	/* attempt to update index (ignoring errors) */
	if (git_index_read(index, false) < 0)
710
		git_error_clear();
711

712
	return !!git_oid_cmp(&index->checksum, checksum);
713 714
}

715
static bool is_racy_entry(git_index *index, const git_index_entry *entry)
716 717 718 719 720
{
	/* Git special-cases submodules in the check */
	if (S_ISGITLINK(entry->mode))
		return false;

721
	return git_index_entry_newer_than_index(entry, index);
722 723
}

724 725 726 727
/*
 * Force the next diff to take a look at those entries which have the
 * same timestamp as the current index.
 */
728
static int truncate_racily_clean(git_index *index)
729 730
{
	size_t i;
731
	int error;
732
	git_index_entry *entry;
733
	git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
734 735 736
	git_diff *diff = NULL;
	git_vector paths = GIT_VECTOR_INIT;
	git_diff_delta *delta;
737 738 739 740

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

742 743 744 745 746
	/* 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;
747
	git_vector_foreach(&index->entries, i, entry) {
748
		if ((entry->flags_extended & GIT_INDEX_ENTRY_UPTODATE) == 0 &&
749
			is_racy_entry(index, entry))
750 751
			git_vector_insert(&paths, (char *)entry->path);
	}
752

753 754
	if (paths.length == 0)
		goto done;
755

756 757
	diff_opts.pathspec.count = paths.length;
	diff_opts.pathspec.strings = (char **)paths.contents;
758

759 760
	if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
		return error;
761

762 763 764 765 766 767
	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.
		 */
768
		if (entry) {
769
			entry->file_size = 0;
770 771
			index->dirty = 1;
		}
772
	}
773

774 775 776
done:
	git_diff_free(diff);
	git_vector_free(&paths);
777
	return 0;
778 779
}

David Turner committed
780 781
unsigned git_index_version(git_index *index)
{
Edward Thomson committed
782
	GIT_ASSERT_ARG(index);
David Turner committed
783 784 785 786 787 788

	return index->version;
}

int git_index_set_version(git_index *index, unsigned int version)
{
Edward Thomson committed
789
	GIT_ASSERT_ARG(index);
David Turner committed
790 791 792

	if (version < INDEX_VERSION_NUMBER_LB ||
	    version > INDEX_VERSION_NUMBER_UB) {
793
		git_error_set(GIT_ERROR_INDEX, "invalid version number");
David Turner committed
794 795 796 797 798 799 800 801
		return -1;
	}

	index->version = version;

	return 0;
}

802 803
int git_index_write(git_index *index)
{
804
	git_indexwriter writer = GIT_INDEXWRITER_INIT;
805
	int error;
806

807 808
	truncate_racily_clean(index);

809 810 811
	if ((error = git_indexwriter_init(&writer, index)) == 0 &&
		(error = git_indexwriter_commit(&writer)) == 0)
		index->dirty = 0;
812

813
	git_indexwriter_cleanup(&writer);
814

815
	return error;
816
}
817

Edward Thomson committed
818
const char *git_index_path(const git_index *index)
819
{
Edward Thomson committed
820
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
821 822
	return index->index_file_path;
}
823

824 825 826 827
int git_index_write_tree(git_oid *oid, git_index *index)
{
	git_repository *repo;

Edward Thomson committed
828 829
	GIT_ASSERT_ARG(oid);
	GIT_ASSERT_ARG(index);
830

831
	repo = INDEX_OWNER(index);
832

833 834
	if (repo == NULL)
		return create_index_error(-1, "Failed to write tree. "
835
		  "the index file is not backed up by an existing repository");
836 837 838 839

	return git_tree__write_index(oid, index, repo);
}

840 841
int git_index_write_tree_to(
	git_oid *oid, git_index *index, git_repository *repo)
842
{
Edward Thomson committed
843 844 845 846
	GIT_ASSERT_ARG(oid);
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(repo);

847 848 849
	return git_tree__write_index(oid, index, repo);
}

850
size_t git_index_entrycount(const git_index *index)
851
{
Edward Thomson committed
852 853
	GIT_ASSERT_ARG(index);

854
	return index->entries.length;
855 856
}

857 858
const git_index_entry *git_index_get_byindex(
	git_index *index, size_t n)
859
{
Edward Thomson committed
860 861
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);

862
	git_vector_sort(&index->entries);
Edward Thomson committed
863
	return git_vector_get(&index->entries, n);
864 865
}

866 867
const git_index_entry *git_index_get_bypath(
	git_index *index, const char *path, int stage)
868
{
869
	git_index_entry key = {{ 0 }};
870
	git_index_entry *value;
Edward Thomson committed
871

Edward Thomson committed
872
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
Edward Thomson committed
873

874
	key.path = path;
875
	GIT_INDEX_ENTRY_STAGE_SET(&key, stage);
876

877 878 879 880
	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
881

882 883 884 885
	if (!value) {
	    git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path);
	    return NULL;
	}
886

887
	return value;
888 889
}

890 891
void git_index_entry__init_from_stat(
	git_index_entry *entry, struct stat *st, bool trust_mode)
892
{
893 894
	entry->ctime.seconds = (int32_t)st->st_ctime;
	entry->mtime.seconds = (int32_t)st->st_mtime;
895
#if defined(GIT_USE_NSEC)
896 897
	entry->mtime.nanoseconds = st->st_mtime_nsec;
	entry->ctime.nanoseconds = st->st_ctime_nsec;
898
#endif
899 900
	entry->dev  = st->st_rdev;
	entry->ino  = st->st_ino;
901
	entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
902
		git_index__create_mode(0666) : git_index__create_mode(st->st_mode);
903 904
	entry->uid  = st->st_uid;
	entry->gid  = st->st_gid;
905
	entry->file_size = (uint32_t)st->st_size;
906 907
}

908 909 910 911
static void index_entry_adjust_namemask(
		git_index_entry *entry,
		size_t path_length)
{
912
	entry->flags &= ~GIT_INDEX_ENTRY_NAMEMASK;
913

914 915
	if (path_length < GIT_INDEX_ENTRY_NAMEMASK)
		entry->flags |= path_length & GIT_INDEX_ENTRY_NAMEMASK;
916
	else
917
		entry->flags |= GIT_INDEX_ENTRY_NAMEMASK;
918 919
}

920 921 922 923 924 925
/* 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.
 */
926 927 928
static int index_entry_create(
	git_index_entry **out,
	git_repository *repo,
929
	const char *path,
930
	struct stat *st,
931
	bool from_workdir)
932
{
933
	size_t pathlen = strlen(path), alloclen;
934
	struct entry_internal *entry;
935
	unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
936
	uint16_t mode = 0;
937

938 939 940 941 942 943
	/* 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;
944 945
	if (st)
		mode = st->st_mode;
946

947
	if (!git_path_validate(repo, path, mode, path_valid_flags)) {
948
		git_error_set(GIT_ERROR_INDEX, "invalid path: '%s'", path);
949
		return -1;
950
	}
951

952 953
	GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen);
	GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
954
	entry = git__calloc(1, alloclen);
955
	GIT_ERROR_CHECK_ALLOC(entry);
956 957 958 959 960

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

961 962
	*out = (git_index_entry *)entry;
	return 0;
963 964
}

965
static int index_entry_init(
966 967 968
	git_index_entry **entry_out,
	git_index *index,
	const char *rel_path)
969
{
970
	int error = 0;
971
	git_index_entry *entry = NULL;
972
	git_buf path = GIT_BUF_INIT;
973 974
	struct stat st;
	git_oid oid;
975
	git_repository *repo;
976

977 978
	if (INDEX_OWNER(index) == NULL)
		return create_index_error(-1,
979
			"could not initialize index entry. "
980 981
			"Index is not backed up by an existing repository.");

982 983 984 985 986 987 988 989 990
	/*
	 * 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;

991
	if (git_repository_workdir_path(&path, repo, rel_path) < 0)
992 993 994
		return -1;

	error = git_path_lstat(path.ptr, &st);
995
	git_buf_dispose(&path);
996 997 998 999 1000

	if (error < 0)
		return error;

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

1003 1004 1005
	/* 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);
1006

1007 1008 1009 1010
	if (error < 0) {
		index_entry_free(entry);
		return error;
	}
1011

1012
	entry->id = oid;
1013
	git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
1014

1015
	*entry_out = (git_index_entry *)entry;
1016
	return 0;
1017 1018
}

1019 1020
static git_index_reuc_entry *reuc_entry_alloc(const char *path)
{
1021
	size_t pathlen = strlen(path),
1022 1023
		structlen = sizeof(struct reuc_entry_internal),
		alloclen;
1024 1025
	struct reuc_entry_internal *entry;

1026 1027
	if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) ||
		GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1))
1028 1029
		return NULL;

1030
	entry = git__calloc(1, alloclen);
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
	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
1041 1042
static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
	const char *path,
Edward Thomson committed
1043 1044 1045
	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
1046 1047 1048
{
	git_index_reuc_entry *reuc = NULL;

Edward Thomson committed
1049 1050
	GIT_ASSERT_ARG(reuc_out);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
1051

1052
	*reuc_out = reuc = reuc_entry_alloc(path);
1053
	GIT_ERROR_CHECK_ALLOC(reuc);
Edward Thomson committed
1054

1055
	if ((reuc->mode[0] = ancestor_mode) > 0) {
Edward Thomson committed
1056
		GIT_ASSERT(ancestor_oid);
1057
		git_oid_cpy(&reuc->oid[0], ancestor_oid);
1058
	}
Edward Thomson committed
1059

1060
	if ((reuc->mode[1] = our_mode) > 0) {
Edward Thomson committed
1061
		GIT_ASSERT(our_oid);
1062
		git_oid_cpy(&reuc->oid[1], our_oid);
1063
	}
Edward Thomson committed
1064

1065
	if ((reuc->mode[2] = their_mode) > 0) {
Edward Thomson committed
1066
		GIT_ASSERT(their_oid);
1067
		git_oid_cpy(&reuc->oid[2], their_oid);
1068
	}
Edward Thomson committed
1069 1070 1071 1072

	return 0;
}

1073 1074
static void index_entry_cpy(
	git_index_entry *tgt,
1075
	const git_index_entry *src)
1076
{
1077
	const char *tgt_path = tgt->path;
1078
	memcpy(tgt, src, sizeof(*tgt));
1079
	tgt->path = tgt_path;
1080 1081
}

1082 1083
static int index_entry_dup(
	git_index_entry **out,
1084
	git_index *index,
1085
	const git_index_entry *src)
1086
{
1087
	if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0)
1088
		return -1;
1089

1090 1091 1092
	index_entry_cpy(*out, src);
	return 0;
}
1093

1094 1095 1096 1097 1098 1099 1100
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;
1101
	tgt->flags_extended = (src->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS);
1102 1103 1104 1105 1106 1107 1108
}

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

1112
	index_entry_cpy_nocache(*out, src);
1113
	return 0;
1114 1115
}

1116
static int has_file_name(git_index *index,
1117
	 const git_index_entry *entry, size_t pos, int ok_to_replace)
1118
{
1119
	size_t len = strlen(entry->path);
1120
	int stage = GIT_INDEX_ENTRY_STAGE(entry);
1121
	const char *name = entry->path;
1122

1123
	while (pos < index->entries.length) {
1124
		struct entry_internal *p = index->entries.contents[pos++];
1125

1126
		if (len >= p->pathlen)
1127
			break;
1128
		if (memcmp(name, p->path, len))
1129
			break;
1130
		if (GIT_INDEX_ENTRY_STAGE(&p->entry) != stage)
1131
			continue;
1132
		if (p->path[len] != '/')
1133 1134
			continue;
		if (!ok_to_replace)
1135
			return -1;
1136

1137
		if (index_remove_entry(index, --pos) < 0)
1138
			break;
1139
	}
1140
	return 0;
1141 1142 1143 1144 1145 1146 1147 1148 1149
}

/*
 * 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)
{
1150
	int stage = GIT_INDEX_ENTRY_STAGE(entry);
1151 1152
	const char *name = entry->path;
	const char *slash = name + strlen(name);
1153 1154

	for (;;) {
1155
		size_t len, pos;
1156 1157 1158 1159

		for (;;) {
			if (*--slash == '/')
				break;
1160
			if (slash <= entry->path)
1161
				return 0;
1162 1163 1164
		}
		len = slash - name;

1165
		if (!index_find(&pos, index, name, len, stage)) {
1166
			if (!ok_to_replace)
1167
				return -1;
1168

1169
			if (index_remove_entry(index, pos) < 0)
1170
				break;
1171
			continue;
1172 1173 1174 1175 1176 1177 1178
		}

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

1182 1183
			if (p->pathlen <= len ||
			    p->path[len] != '/' ||
1184
			    memcmp(p->path, name, len))
1185
				break; /* not our subdirectory */
1186

1187
			if (GIT_INDEX_ENTRY_STAGE(&p->entry) == stage)
1188
				return 0;
1189 1190
		}
	}
1191

1192
	return 0;
1193
}
1194

1195
static int check_file_directory_collision(git_index *index,
1196 1197
		git_index_entry *entry, size_t pos, int ok_to_replace)
{
1198 1199
	if (has_file_name(index, entry, pos, ok_to_replace) < 0 ||
	    has_dir_name(index, entry, ok_to_replace) < 0) {
1200
		git_error_set(GIT_ERROR_INDEX,
1201
			"'%s' appears as both a file and a directory", entry->path);
1202 1203 1204 1205 1206
		return -1;
	}

	return 0;
}
1207

1208
static int canonicalize_directory_path(
1209 1210 1211
	git_index *index,
	git_index_entry *entry,
	git_index_entry *existing)
1212 1213 1214 1215 1216 1217 1218 1219 1220
{
	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 */
1221 1222
	if (existing) {
		memcpy((char *)entry->path, existing->path, strlen(existing->path));
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
		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))) {
1245
			if (GIT_INDEX_ENTRY_STAGE(match) != 0) {
1246
				/* conflicts do not contribute to canonical paths */
1247
			} else if (strncmp(search, match->path, search_len) == 0) {
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
				/* 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;
}

1278 1279 1280 1281
static int index_no_dups(void **old, void *new)
{
	const git_index_entry *entry = new;
	GIT_UNUSED(old);
1282
	git_error_set(GIT_ERROR_INDEX, "'%s' appears multiple times at stage %d",
1283
		entry->path, GIT_INDEX_ENTRY_STAGE(entry));
1284 1285 1286
	return GIT_EEXISTS;
}

1287
static void index_existing_and_best(
1288
	git_index_entry **existing,
1289
	size_t *existing_position,
1290
	git_index_entry **best,
1291 1292 1293
	git_index *index,
	const git_index_entry *entry)
{
1294
	git_index_entry *e;
1295 1296 1297 1298
	size_t pos;
	int error;

	error = index_find(&pos,
1299
		index, entry->path, 0, GIT_INDEX_ENTRY_STAGE(entry));
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311

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

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

1312
	if (GIT_INDEX_ENTRY_STAGE(entry) == 0) {
1313 1314 1315 1316 1317 1318 1319 1320 1321
		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;

1322
			if (GIT_INDEX_ENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) {
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
				*best = e;
				continue;
			} else {
				*best = e;
				break;
			}
		}
	}
}

1333 1334 1335 1336
/* 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).
1337
 *
1338 1339 1340
 * 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.
1341
 *
1342
 * trust_mode is whether we trust the mode in entry_ptr.
1343 1344
 *
 * trust_id is whether we trust the id or it should be validated.
1345 1346
 */
static int index_insert(
1347 1348 1349 1350
	git_index *index,
	git_index_entry **entry_ptr,
	int replace,
	bool trust_path,
1351 1352
	bool trust_mode,
	bool trust_id)
1353
{
1354
	git_index_entry *existing, *best, *entry;
1355 1356
	size_t path_length, position;
	int error;
1357

Edward Thomson committed
1358 1359
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(entry_ptr);
1360 1361

	entry = *entry_ptr;
1362

1363
	/* Make sure that the path length flag is correct */
1364
	path_length = ((struct entry_internal *)entry)->pathlen;
1365
	index_entry_adjust_namemask(entry, path_length);
1366

1367
	/* This entry is now up-to-date and should not be checked for raciness */
1368
	entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
1369

1370 1371
	git_vector_sort(&index->entries);

1372 1373
	/*
	 * Look if an entry with this path already exists, either staged, or (if
1374 1375 1376 1377
	 * this entry is a regular staged item) as the "ours" side of a conflict.
	 */
	index_existing_and_best(&existing, &position, &best, index, entry);

1378
	/* Update the file mode */
1379 1380 1381
	entry->mode = trust_mode ?
		git_index__create_mode(entry->mode) :
		index_merge_mode(index, best, entry->mode);
1382

1383 1384 1385
	/* Canonicalize the directory name */
	if (!trust_path && (error = canonicalize_directory_path(index, entry, best)) < 0)
		goto out;
1386

1387 1388 1389
	/* 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) {
1390 1391

		if (!git_object__is_valid(INDEX_OWNER(index), &entry->id,
1392
					  git_object__type_from_filemode(entry->mode))) {
1393
			error = -1;
1394 1395
			goto out;
		}
1396 1397
	}

1398 1399 1400
	/* Look for tree / blob name collisions, removing conflicts if requested */
	if ((error = check_file_directory_collision(index, entry, position, replace)) < 0)
		goto out;
1401

1402 1403
	/*
	 * If we are replacing an existing item, overwrite the existing entry
1404 1405
	 * and return it in place of the passed in one.
	 */
1406
	if (existing) {
1407 1408 1409 1410 1411 1412 1413
		if (replace) {
			index_entry_cpy(existing, entry);

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

1414
		index_entry_free(entry);
1415 1416 1417 1418
		*entry_ptr = existing;
	} else {
		/*
		 * If replace is not requested or no existing entry exists, insert
1419 1420
		 * at the sorted position.  (Since we re-sort after each insert to
		 * check for dups, this is actually cheaper in the long run.)
1421
		 */
1422 1423
		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)
1424
			goto out;
1425
	}
1426

1427 1428 1429
	index->dirty = 1;

out:
1430 1431 1432 1433
	if (error < 0) {
		index_entry_free(*entry_ptr);
		*entry_ptr = NULL;
	}
1434

1435
	return error;
1436 1437
}

Edward Thomson committed
1438
static int index_conflict_to_reuc(git_index *index, const char *path)
1439
{
1440
	const git_index_entry *conflict_entries[3];
Edward Thomson committed
1441
	int ancestor_mode, our_mode, their_mode;
Edward Thomson committed
1442
	git_oid const *ancestor_oid, *our_oid, *their_oid;
1443
	int ret;
1444

Edward Thomson committed
1445 1446
	if ((ret = git_index_conflict_get(&conflict_entries[0],
		&conflict_entries[1], &conflict_entries[2], index, path)) < 0)
1447
		return ret;
1448

Edward Thomson committed
1449 1450 1451
	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;
1452

1453 1454 1455
	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
1456 1457 1458 1459 1460 1461

	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;
1462 1463
}

1464
GIT_INLINE(bool) is_file_or_link(const int filemode)
1465 1466 1467
{
	return (filemode == GIT_FILEMODE_BLOB ||
		filemode == GIT_FILEMODE_BLOB_EXECUTABLE ||
1468 1469 1470 1471 1472 1473
		filemode == GIT_FILEMODE_LINK);
}

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

1476
int git_index_add_from_buffer(
1477
    git_index *index, const git_index_entry *source_entry,
1478 1479 1480 1481 1482 1483
    const void *buffer, size_t len)
{
	git_index_entry *entry = NULL;
	int error = 0;
	git_oid id;

Edward Thomson committed
1484 1485
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(source_entry && source_entry->path);
1486 1487 1488

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

1492
	if (!is_file_or_link(source_entry->mode)) {
1493
		git_error_set(GIT_ERROR_INDEX, "invalid filemode");
1494 1495 1496
		return -1;
	}

1497 1498 1499 1500 1501
	if (len > UINT32_MAX) {
		git_error_set(GIT_ERROR_INDEX, "buffer is too large");
		return -1;
	}

1502
	if (index_entry_dup(&entry, index, source_entry) < 0)
1503 1504
		return -1;

1505
	error = git_blob_create_from_buffer(&id, INDEX_OWNER(index), buffer, len);
1506 1507 1508 1509 1510 1511
	if (error < 0) {
		index_entry_free(entry);
		return error;
	}

	git_oid_cpy(&entry->id, &id);
1512
	entry->file_size = (uint32_t)len;
1513

1514
	if ((error = index_insert(index, &entry, 1, true, true, true)) < 0)
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524
		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;
}

1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path)
{
	git_repository *sub;
	git_buf abspath = GIT_BUF_INIT;
	git_repository *repo = INDEX_OWNER(index);
	git_reference *head;
	git_index_entry *entry;
	struct stat st;
	int error;

1535
	if ((error = git_repository_workdir_path(&abspath, repo, path)) < 0)
1536 1537 1538
		return error;

	if ((error = p_stat(abspath.ptr, &st)) < 0) {
1539
		git_error_set(GIT_ERROR_OS, "failed to stat repository dir");
1540 1541 1542
		return -1;
	}

1543 1544 1545
	if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0)
		return -1;

1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
	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);
1559
	git_buf_dispose(&abspath);
1560 1561 1562 1563

	*out = entry;
	return 0;
}
1564

1565
int git_index_add_bypath(git_index *index, const char *path)
1566
{
Edward Thomson committed
1567 1568 1569
	git_index_entry *entry = NULL;
	int ret;

Edward Thomson committed
1570 1571
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
1572

1573
	if ((ret = index_entry_init(&entry, index, path)) == 0)
1574
		ret = index_insert(index, &entry, 1, false, false, true);
1575 1576 1577 1578 1579 1580 1581 1582 1583

	/* 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;
		git_error_state err;

1584
		git_error_state_capture(&err, ret);
1585 1586 1587

		ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
		if (ret == GIT_ENOTFOUND)
1588
			return git_error_state_restore(&err);
1589

1590
		git_error_state_free(&err);
1591 1592 1593 1594 1595 1596 1597 1598 1599

		/*
		 * 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;

1600
			if ((ret = index_insert(index, &entry, 1, false, false, true)) < 0)
1601 1602 1603 1604 1605 1606 1607 1608
				return ret;
		} else if (ret < 0) {
			return ret;
		} else {
			ret = git_submodule_add_to_index(sm, false);
			git_submodule_free(sm);
			return ret;
		}
1609
	}
Edward Thomson committed
1610 1611 1612

	/* Adding implies conflict was resolved, move conflict entries to REUC */
	if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
1613
		return ret;
Edward Thomson committed
1614 1615 1616

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

1619 1620 1621 1622
int git_index_remove_bypath(git_index *index, const char *path)
{
	int ret;

Edward Thomson committed
1623 1624
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1625 1626 1627 1628 1629 1630 1631

	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;

1632
	if (ret == GIT_ENOTFOUND)
1633
		git_error_clear();
1634

1635 1636 1637
	return 0;
}

1638 1639 1640
int git_index__fill(git_index *index, const git_vector *source_entries)
{
	const git_index_entry *source_entry = NULL;
1641
	int error = 0;
1642 1643
	size_t i;

Edward Thomson committed
1644
	GIT_ASSERT_ARG(index);
1645

1646 1647 1648
	if (!source_entries->length)
		return 0;

1649
	if (git_vector_size_hint(&index->entries, source_entries->length) < 0 ||
1650 1651
	    index_map_resize(index->entries_map, (size_t)(source_entries->length * 1.3),
			     index->ignore_case) < 0)
1652
		return -1;
1653

1654 1655 1656
	git_vector_foreach(source_entries, i, source_entry) {
		git_index_entry *entry = NULL;

1657
		if ((error = index_entry_dup(&entry, index, source_entry)) < 0)
1658 1659
			break;

1660
		index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen);
1661
		entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
1662
		entry->mode = git_index__create_mode(entry->mode);
1663

1664
		if ((error = git_vector_insert(&index->entries, entry)) < 0)
1665 1666
			break;

1667
		if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0)
1668
			break;
1669 1670

		index->dirty = 1;
1671 1672
	}

1673
	if (!error)
1674 1675
		git_vector_sort(&index->entries);

1676
	return error;
1677 1678
}

1679

Edward Thomson committed
1680
int git_index_add(git_index *index, const git_index_entry *source_entry)
1681 1682 1683 1684
{
	git_index_entry *entry = NULL;
	int ret;

Edward Thomson committed
1685 1686
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(source_entry && source_entry->path);
1687

1688
	if (!valid_filemode(source_entry->mode)) {
1689
		git_error_set(GIT_ERROR_INDEX, "invalid entry mode");
1690 1691 1692
		return -1;
	}

1693
	if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
1694
		(ret = index_insert(index, &entry, 1, true, true, false)) < 0)
1695
		return ret;
1696

1697
	git_tree_cache_invalidate_path(index->tree, entry->path);
1698
	return 0;
1699 1700
}

Edward Thomson committed
1701
int git_index_remove(git_index *index, const char *path, int stage)
1702
{
1703
	int error;
1704
	size_t position;
1705
	git_index_entry remove_key = {{ 0 }};
1706

1707
	remove_key.path = path;
1708
	GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage);
1709

1710
	index_map_delete(index->entries_map, &remove_key, index->ignore_case);
1711

1712
	if (index_find(&position, index, path, 0, stage) < 0) {
1713 1714
		git_error_set(
			GIT_ERROR_INDEX, "index does not contain %s at stage %d", path, stage);
1715 1716 1717
		error = GIT_ENOTFOUND;
	} else {
		error = index_remove_entry(index, position);
1718
	}
Edward Thomson committed
1719

1720
	return error;
1721
}
1722

1723 1724 1725 1726 1727 1728 1729
int git_index_remove_directory(git_index *index, const char *dir, int stage)
{
	git_buf pfx = GIT_BUF_INIT;
	int error = 0;
	size_t pos;
	git_index_entry *entry;

1730 1731
	if (!(error = git_buf_sets(&pfx, dir)) &&
		!(error = git_path_to_dir(&pfx)))
1732
		index_find(&pos, index, pfx.ptr, pfx.size, GIT_INDEX_STAGE_ANY);
1733

1734
	while (!error) {
1735 1736 1737 1738
		entry = git_vector_get(&index->entries, pos);
		if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
			break;

1739
		if (GIT_INDEX_ENTRY_STAGE(entry) != stage) {
1740 1741 1742 1743
			++pos;
			continue;
		}

1744
		error = index_remove_entry(index, pos);
1745

1746
		/* removed entry at 'pos' so we don't need to increment */
1747 1748
	}

1749
	git_buf_dispose(&pfx);
1750 1751 1752 1753

	return error;
}

1754 1755 1756 1757 1758 1759
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;

1760
	index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY);
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
	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;
}

1771
int git_index__find_pos(
1772 1773
	size_t *out, git_index *index, const char *path, size_t path_len, int stage)
{
Edward Thomson committed
1774 1775
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1776
	return index_find(out, index, path, path_len, stage);
Edward Thomson committed
1777 1778
}

1779
int git_index_find(size_t *at_pos, git_index *index, const char *path)
1780
{
1781
	size_t pos;
Edward Thomson committed
1782

Edward Thomson committed
1783 1784
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
1785

1786 1787
	if (git_vector_bsearch2(
			&pos, &index->entries, index->entries_search_path, path) < 0) {
1788
		git_error_set(GIT_ERROR_INDEX, "index does not contain %s", path);
1789
		return GIT_ENOTFOUND;
1790
	}
Edward Thomson committed
1791 1792

	/* Since our binary search only looked at path, we may be in the
1793 1794
	 * middle of a list of stages.
	 */
1795 1796
	for (; pos > 0; --pos) {
		const git_index_entry *prev = git_vector_get(&index->entries, pos - 1);
Edward Thomson committed
1797 1798 1799 1800 1801

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

1802 1803 1804 1805
	if (at_pos)
		*at_pos = pos;

	return 0;
1806 1807
}

Edward Thomson committed
1808 1809 1810 1811 1812 1813
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 };
1814
	unsigned short i;
Edward Thomson committed
1815 1816
	int ret = 0;

Edward Thomson committed
1817
	GIT_ASSERT_ARG(index);
Edward Thomson committed
1818

1819 1820 1821 1822 1823 1824
	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))
1825
		goto on_error;
Edward Thomson committed
1826

1827 1828 1829
	/* Validate entries */
	for (i = 0; i < 3; i++) {
		if (entries[i] && !valid_filemode(entries[i]->mode)) {
1830
			git_error_set(GIT_ERROR_INDEX, "invalid filemode for stage %d entry",
1831
				i + 1);
abyss7 committed
1832 1833
			ret = -1;
			goto on_error;
1834 1835 1836
		}
	}

1837 1838 1839 1840 1841 1842 1843 1844 1845
	/* 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;

1846
			git_error_clear();
1847 1848 1849 1850 1851
			ret = 0;
		}
	}

	/* Add the conflict entries */
Edward Thomson committed
1852 1853 1854 1855 1856
	for (i = 0; i < 3; i++) {
		if (entries[i] == NULL)
			continue;

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

1859
		if ((ret = index_insert(index, &entries[i], 1, true, true, false)) < 0)
Edward Thomson committed
1860
			goto on_error;
1861 1862

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

nulltoken committed
1865
	return 0;
Edward Thomson committed
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875

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

	return ret;
}

1876 1877 1878 1879 1880 1881
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
1882
{
1883 1884 1885 1886
	const git_index_entry *conflict_entry;
	const char *path = NULL;
	size_t count;
	int stage, len = 0;
Edward Thomson committed
1887

Edward Thomson committed
1888 1889 1890 1891
	GIT_ASSERT_ARG(ancestor_out);
	GIT_ASSERT_ARG(our_out);
	GIT_ASSERT_ARG(their_out);
	GIT_ASSERT_ARG(index);
1892

Edward Thomson committed
1893 1894 1895 1896
	*ancestor_out = NULL;
	*our_out = NULL;
	*their_out = NULL;

1897 1898
	for (count = git_index_entrycount(index); n < count; ++n) {
		conflict_entry = git_vector_get(&index->entries, n);
Edward Thomson committed
1899

1900
		if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
Edward Thomson committed
1901 1902
			break;

1903
		stage = GIT_INDEX_ENTRY_STAGE(conflict_entry);
1904
		path = conflict_entry->path;
1905

Edward Thomson committed
1906 1907 1908
		switch (stage) {
		case 3:
			*their_out = conflict_entry;
1909
			len++;
Edward Thomson committed
1910 1911 1912
			break;
		case 2:
			*our_out = conflict_entry;
1913
			len++;
Edward Thomson committed
1914 1915 1916
			break;
		case 1:
			*ancestor_out = conflict_entry;
1917
			len++;
Edward Thomson committed
1918 1919 1920 1921 1922 1923
			break;
		default:
			break;
		};
	}

1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
	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
1937 1938 1939 1940 1941
	GIT_ASSERT_ARG(ancestor_out);
	GIT_ASSERT_ARG(our_out);
	GIT_ASSERT_ARG(their_out);
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956

	*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
1957 1958
}

1959
static int index_conflict_remove(git_index *index, const char *path)
Edward Thomson committed
1960
{
1961
	size_t pos = 0;
Edward Thomson committed
1962
	git_index_entry *conflict_entry;
1963
	int error = 0;
Edward Thomson committed
1964

1965
	if (path != NULL && git_index_find(&pos, index, path) < 0)
1966
		return GIT_ENOTFOUND;
Edward Thomson committed
1967

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

1970 1971
		if (path != NULL &&
			index->entries_cmp_path(conflict_entry->path, path) != 0)
Edward Thomson committed
1972 1973
			break;

1974
		if (GIT_INDEX_ENTRY_STAGE(conflict_entry) == 0) {
Edward Thomson committed
1975 1976 1977 1978
			pos++;
			continue;
		}

1979
		if ((error = index_remove_entry(index, pos)) < 0)
1980
			break;
Edward Thomson committed
1981 1982
	}

1983
	return error;
Edward Thomson committed
1984 1985
}

1986
int git_index_conflict_remove(git_index *index, const char *path)
Edward Thomson committed
1987
{
Edward Thomson committed
1988 1989
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
1990
	return index_conflict_remove(index, path);
Edward Thomson committed
1991 1992
}

1993
int git_index_conflict_cleanup(git_index *index)
Edward Thomson committed
1994
{
Edward Thomson committed
1995
	GIT_ASSERT_ARG(index);
1996
	return index_conflict_remove(index, NULL);
Edward Thomson committed
1997 1998
}

1999
int git_index_has_conflicts(const git_index *index)
2000
{
2001
	size_t i;
2002 2003
	git_index_entry *entry;

Edward Thomson committed
2004
	GIT_ASSERT_ARG(index);
2005 2006

	git_vector_foreach(&index->entries, i, entry) {
2007
		if (GIT_INDEX_ENTRY_STAGE(entry) > 0)
2008 2009 2010 2011 2012 2013
			return 1;
	}

	return 0;
}

2014 2015 2016 2017 2018 2019 2020
int git_index_iterator_new(
	git_index_iterator **iterator_out,
	git_index *index)
{
	git_index_iterator *it;
	int error;

Edward Thomson committed
2021 2022
	GIT_ASSERT_ARG(iterator_out);
	GIT_ASSERT_ARG(index);
2023 2024

	it = git__calloc(1, sizeof(git_index_iterator));
2025
	GIT_ERROR_CHECK_ALLOC(it);
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041

	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
2042 2043
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(it);
2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060

	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);
}

2061 2062 2063 2064 2065 2066
int git_index_conflict_iterator_new(
	git_index_conflict_iterator **iterator_out,
	git_index *index)
{
	git_index_conflict_iterator *it = NULL;

Edward Thomson committed
2067 2068
	GIT_ASSERT_ARG(iterator_out);
	GIT_ASSERT_ARG(index);
2069 2070

	it = git__calloc(1, sizeof(git_index_conflict_iterator));
2071
	GIT_ERROR_CHECK_ALLOC(it);
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087

	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
2088 2089 2090 2091
	GIT_ASSERT_ARG(ancestor_out);
	GIT_ASSERT_ARG(our_out);
	GIT_ASSERT_ARG(their_out);
	GIT_ASSERT_ARG(iterator);
2092 2093 2094 2095 2096 2097 2098 2099

	*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);

2100
		if (git_index_entry_is_conflict(entry)) {
2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
			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);
}

2127
size_t git_index_name_entrycount(git_index *index)
Edward Thomson committed
2128
{
Edward Thomson committed
2129
	GIT_ASSERT_ARG(index);
2130
	return index->names.length;
Edward Thomson committed
2131 2132 2133 2134 2135
}

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

Edward Thomson committed
2138 2139 2140 2141
	git_vector_sort(&index->names);
	return git_vector_get(&index->names, n);
}

2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
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
2152 2153 2154 2155 2156
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
2157
	GIT_ASSERT_ARG((ancestor && ours) || (ancestor && theirs) || (ours && theirs));
Edward Thomson committed
2158 2159

	conflict_name = git__calloc(1, sizeof(git_index_name_entry));
2160
	GIT_ERROR_CHECK_ALLOC(conflict_name);
nulltoken committed
2161

2162 2163 2164 2165 2166 2167 2168
	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
2169
	}
nulltoken committed
2170

2171
	index->dirty = 1;
2172
	return 0;
Edward Thomson committed
2173 2174
}

2175
int git_index_name_clear(git_index *index)
Edward Thomson committed
2176 2177 2178 2179
{
	size_t i;
	git_index_name_entry *conflict_name;

Edward Thomson committed
2180
	GIT_ASSERT_ARG(index);
nulltoken committed
2181

2182 2183
	git_vector_foreach(&index->names, i, conflict_name)
		index_name_entry_free(conflict_name);
nulltoken committed
2184

Edward Thomson committed
2185
	git_vector_clear(&index->names);
2186 2187

	index->dirty = 1;
2188 2189

	return 0;
Edward Thomson committed
2190 2191
}

2192
size_t git_index_reuc_entrycount(git_index *index)
Edward Thomson committed
2193
{
Edward Thomson committed
2194
	GIT_ASSERT_ARG(index);
2195
	return index->reuc.length;
Edward Thomson committed
2196 2197
}

2198 2199 2200 2201 2202 2203 2204
static int index_reuc_on_dup(void **old, void *new)
{
	index_entry_reuc_free(*old);
	*old = new;
	return GIT_EEXISTS;
}

Edward Thomson committed
2205 2206
static int index_reuc_insert(
	git_index *index,
2207
	git_index_reuc_entry *reuc)
Edward Thomson committed
2208
{
2209
	int res;
Edward Thomson committed
2210

Edward Thomson committed
2211 2212 2213
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(reuc && reuc->path != NULL);
	GIT_ASSERT(git_vector_is_sorted(&index->reuc));
Edward Thomson committed
2214

2215
	res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
2216 2217
	index->dirty = 1;

2218
	return res == GIT_EEXISTS ? 0 : res;
Edward Thomson committed
2219 2220 2221
}

int git_index_reuc_add(git_index *index, const char *path,
Edward Thomson committed
2222 2223 2224
	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
2225 2226 2227 2228
{
	git_index_reuc_entry *reuc = NULL;
	int error = 0;

Edward Thomson committed
2229 2230
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(path);
Edward Thomson committed
2231

2232 2233
	if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
			ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
2234
		(error = index_reuc_insert(index, reuc)) < 0)
Edward Thomson committed
2235 2236 2237
		index_entry_reuc_free(reuc);

	return error;
2238
}
Edward Thomson committed
2239

2240
int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path)
2241
{
2242
	return git_vector_bsearch2(at_pos, &index->reuc, index->reuc_search, path);
2243 2244
}

Edward Thomson committed
2245
const git_index_reuc_entry *git_index_reuc_get_bypath(
2246
	git_index *index, const char *path)
2247
{
2248
	size_t pos;
Edward Thomson committed
2249 2250 2251

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

Edward Thomson committed
2253
	if (!index->reuc.length)
2254
		return NULL;
2255

Edward Thomson committed
2256
	GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL);
Edward Thomson committed
2257

2258
	if (git_index_reuc_find(&pos, index, path) < 0)
2259
		return NULL;
2260

Edward Thomson committed
2261
	return git_vector_get(&index->reuc, pos);
2262 2263
}

Edward Thomson committed
2264
const git_index_reuc_entry *git_index_reuc_get_byindex(
2265
	git_index *index, size_t n)
2266
{
Edward Thomson committed
2267 2268
	GIT_ASSERT_ARG_WITH_RETVAL(index, NULL);
	GIT_ASSERT_WITH_RETVAL(git_vector_is_sorted(&index->reuc), NULL);
Edward Thomson committed
2269 2270 2271 2272

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

Ben Straub committed
2273
int git_index_reuc_remove(git_index *index, size_t position)
Edward Thomson committed
2274 2275 2276 2277
{
	int error;
	git_index_reuc_entry *reuc;

Edward Thomson committed
2278 2279
	GIT_ASSERT_ARG(index);
	GIT_ASSERT(git_vector_is_sorted(&index->reuc));
Edward Thomson committed
2280 2281

	reuc = git_vector_get(&index->reuc, position);
2282
	error = git_vector_remove(&index->reuc, position);
Edward Thomson committed
2283 2284 2285 2286

	if (!error)
		index_entry_reuc_free(reuc);

2287
	index->dirty = 1;
Edward Thomson committed
2288
	return error;
2289 2290
}

2291
int git_index_reuc_clear(git_index *index)
Edward Thomson committed
2292 2293 2294
{
	size_t i;

Edward Thomson committed
2295
	GIT_ASSERT_ARG(index);
Edward Thomson committed
2296

2297
	for (i = 0; i < index->reuc.length; ++i)
2298
		index_entry_reuc_free(git_atomic_swap(index->reuc.contents[i], NULL));
Edward Thomson committed
2299 2300

	git_vector_clear(&index->reuc);
2301 2302

	index->dirty = 1;
2303 2304

	return 0;
Edward Thomson committed
2305 2306
}

2307 2308
static int index_error_invalid(const char *message)
{
2309
	git_error_set(GIT_ERROR_INDEX, "invalid data in index - %s", message);
2310 2311 2312
	return -1;
}

Edward Thomson committed
2313
static int read_reuc(git_index *index, const char *buffer, size_t size)
2314
{
2315 2316
	const char *endptr;
	size_t len;
2317 2318
	int i;

2319 2320 2321
	/* 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)
2322
		return -1;
2323 2324

	while (size) {
Edward Thomson committed
2325
		git_index_reuc_entry *lost;
2326

2327
		len = p_strnlen(buffer, size) + 1;
2328
		if (size <= len)
Edward Thomson committed
2329
			return index_error_invalid("reading reuc entries");
2330

2331
		lost = reuc_entry_alloc(buffer);
2332
		GIT_ERROR_CHECK_ALLOC(lost);
2333 2334 2335 2336

		size -= len;
		buffer += len;

2337
		/* read 3 ASCII octal numbers for stage entries */
2338
		for (i = 0; i < 3; i++) {
2339
			int64_t tmp;
2340

2341
			if (git__strntol64(&tmp, buffer, size, &endptr, 8) < 0 ||
2342
				!endptr || endptr == buffer || *endptr ||
2343
				tmp < 0 || tmp > UINT32_MAX) {
2344
				index_entry_reuc_free(lost);
Edward Thomson committed
2345
				return index_error_invalid("reading reuc entry stage");
2346
			}
2347

2348
			lost->mode[i] = (uint32_t)tmp;
2349

2350
			len = (endptr + 1) - buffer;
2351 2352
			if (size <= len) {
				index_entry_reuc_free(lost);
Edward Thomson committed
2353
				return index_error_invalid("reading reuc entry stage");
2354
			}
2355

2356 2357 2358 2359
			size -= len;
			buffer += len;
		}

2360
		/* read up to 3 OIDs for stage entries */
2361 2362 2363
		for (i = 0; i < 3; i++) {
			if (!lost->mode[i])
				continue;
2364 2365
			if (size < 20) {
				index_entry_reuc_free(lost);
Edward Thomson committed
2366
				return index_error_invalid("reading reuc entry oid");
2367
			}
2368

2369
			git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer);
2370 2371 2372
			size -= 20;
			buffer += 20;
		}
2373 2374 2375 2376

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

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

2382
	return 0;
2383 2384
}

Edward Thomson committed
2385 2386 2387 2388

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

Edward Thomson committed
2390 2391 2392 2393 2394 2395
	/* 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) \
2396
	len = p_strnlen(buffer, size) + 1; \
2397 2398 2399 2400
	if (size < len) { \
		index_error_invalid("reading conflict name entries"); \
		goto out_err; \
	} \
Edward Thomson committed
2401 2402 2403 2404
	if (len == 1) \
		ptr = NULL; \
	else { \
		ptr = git__malloc(len); \
2405
		GIT_ERROR_CHECK_ALLOC(ptr); \
Edward Thomson committed
2406 2407 2408 2409 2410
		memcpy(ptr, buffer, len); \
	} \
	\
	buffer += len; \
	size -= len;
nulltoken committed
2411

Edward Thomson committed
2412 2413
	while (size) {
		git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry));
2414
		GIT_ERROR_CHECK_ALLOC(conflict_name);
Edward Thomson committed
2415 2416 2417 2418

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

Edward Thomson committed
2420
		if (git_vector_insert(&index->names, conflict_name) < 0)
2421 2422 2423 2424 2425 2426 2427 2428 2429 2430
			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
2431 2432 2433
	}

#undef read_conflict_name
nulltoken committed
2434

Edward Thomson committed
2435
	/* entries are guaranteed to be sorted on-disk */
2436
	git_vector_set_sorted(&index->names, true);
nulltoken committed
2437 2438

	return 0;
Edward Thomson committed
2439 2440
}

2441 2442 2443
static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags)
{
	if (varint_len) {
2444
		if (flags & GIT_INDEX_ENTRY_EXTENDED)
2445 2446 2447 2448
			return offsetof(struct entry_long, path) + path_len + 1 + varint_len;
		else
			return offsetof(struct entry_short, path) + path_len + 1 + varint_len;
	} else {
2449
#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
2450
		if (flags & GIT_INDEX_ENTRY_EXTENDED)
2451
			return entry_size(struct entry_long, path_len);
2452
		else
2453 2454
			return entry_size(struct entry_short, path_len);
#undef entry_size
2455 2456 2457
	}
}

2458
static int read_entry(
2459
	git_index_entry **out,
2460
	size_t *out_size,
2461 2462
	git_index *index,
	const void *buffer,
David Turner committed
2463
	size_t buffer_size,
2464
	const char *last)
2465 2466 2467
{
	size_t path_length, entry_size;
	const char *path_ptr;
2468
	struct entry_short source;
2469
	git_index_entry entry = {{0}};
David Turner committed
2470 2471
	bool compressed = index->version >= INDEX_VERSION_NUMBER_COMP;
	char *tmp_path = NULL;
2472 2473

	if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
2474
		return -1;
2475

2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490
	/* buffer is not guaranteed to be aligned */
	memcpy(&source, buffer, sizeof(struct entry_short));

	entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds);
	entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds);
	entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds);
	entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds);
	entry.dev = ntohl(source.dev);
	entry.ino = ntohl(source.ino);
	entry.mode = ntohl(source.mode);
	entry.uid = ntohl(source.uid);
	entry.gid = ntohl(source.gid);
	entry.file_size = ntohl(source.file_size);
	git_oid_cpy(&entry.id, &source.oid);
	entry.flags = ntohs(source.flags);
2491

2492
	if (entry.flags & GIT_INDEX_ENTRY_EXTENDED) {
2493 2494
		uint16_t flags_raw;
		size_t flags_offset;
2495

2496 2497 2498 2499 2500 2501 2502
		flags_offset = offsetof(struct entry_long, flags_extended);
		memcpy(&flags_raw, (const char *) buffer + flags_offset,
			sizeof(flags_raw));
		flags_raw = ntohs(flags_raw);

		memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw));
		path_ptr = (const char *) buffer + offsetof(struct entry_long, path);
2503
	} else
2504
		path_ptr = (const char *) buffer + offsetof(struct entry_short, path);
2505

David Turner committed
2506
	if (!compressed) {
2507
		path_length = entry.flags & GIT_INDEX_ENTRY_NAMEMASK;
2508

David Turner committed
2509 2510 2511 2512
		/* if this is a very long string, we must find its
		 * real length without overflowing */
		if (path_length == 0xFFF) {
			const char *path_end;
2513

David Turner committed
2514 2515
			path_end = memchr(path_ptr, '\0', buffer_size);
			if (path_end == NULL)
2516
				return -1;
2517

David Turner committed
2518 2519
			path_length = path_end - path_ptr;
		}
2520

2521
		entry_size = index_entry_size(path_length, 0, entry.flags);
David Turner committed
2522 2523
		entry.path = (char *)path_ptr;
	} else {
2524 2525 2526 2527 2528 2529 2530
		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
2531 2532
			return index_error_invalid("incorrect prefix length");

2533
		prefix_len = last_len - (size_t)strip_len;
2534 2535
		suffix_len = strlen(path_ptr + varint_len);

2536 2537
		GIT_ERROR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
		GIT_ERROR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
2538 2539 2540 2541

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

2542
		tmp_path = git__malloc(path_len);
2543
		GIT_ERROR_CHECK_ALLOC(tmp_path);
2544 2545 2546

		memcpy(tmp_path, last, prefix_len);
		memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1);
2547
		entry_size = index_entry_size(suffix_len, varint_len, entry.flags);
David Turner committed
2548 2549 2550
		entry.path = tmp_path;
	}

2551 2552 2553
	if (entry_size == 0)
		return -1;

2554
	if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
2555
		return -1;
2556

David Turner committed
2557 2558
	if (index_entry_dup(out, index, &entry) < 0) {
		git__free(tmp_path);
2559
		return -1;
David Turner committed
2560
	}
2561

David Turner committed
2562
	git__free(tmp_path);
2563 2564
	*out_size = entry_size;
	return 0;
2565 2566 2567 2568
}

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

2571 2572
	dest->signature = ntohl(source->signature);
	if (dest->signature != INDEX_HEADER_SIG)
2573
		return index_error_invalid("incorrect header signature");
2574 2575

	dest->version = ntohl(source->version);
David Turner committed
2576 2577
	if (dest->version < INDEX_VERSION_NUMBER_LB ||
		dest->version > INDEX_VERSION_NUMBER_UB)
2578
		return index_error_invalid("incorrect header version");
2579 2580

	dest->entry_count = ntohl(source->entry_count);
2581
	return 0;
2582 2583
}

2584
static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size)
2585 2586 2587 2588
{
	struct index_extension dest;
	size_t total_size;

2589 2590 2591
	/* buffer is not guaranteed to be aligned */
	memcpy(&dest, buffer, sizeof(struct index_extension));
	dest.extension_size = ntohl(dest.extension_size);
2592 2593 2594

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

2595 2596
	if (dest.extension_size > total_size ||
		buffer_size < total_size ||
2597 2598 2599 2600
		buffer_size - total_size < INDEX_FOOTER_SIZE) {
		index_error_invalid("extension is truncated");
		return -1;
	}
2601 2602 2603 2604 2605

	/* optional extension */
	if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
		/* tree cache */
		if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
2606
			if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0)
2607
				return -1;
2608
		} else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
Edward Thomson committed
2609
			if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
2610
				return -1;
Edward Thomson committed
2611 2612
		} else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
			if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
2613
				return -1;
2614
		}
2615 2616
		/* else, unsupported extension. We cannot parse this, but we can skip
		 * it by returning `total_size */
2617 2618 2619
	} else {
		/* we cannot handle non-ignorable extensions;
		 * in fact they aren't even defined in the standard */
2620 2621
		git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature);
		return -1;
2622 2623
	}

2624 2625 2626
	*read_len = total_size;

	return 0;
2627 2628
}

2629
static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
2630
{
2631
	int error = 0;
2632
	unsigned int i;
2633
	struct index_header header = { 0 };
2634
	git_oid checksum_calculated, checksum_expected;
2635
	const char *last = NULL;
David Turner committed
2636
	const char *empty = "";
2637 2638

#define seek_forward(_increase) { \
2639 2640 2641
	if (_increase >= buffer_size) { \
		error = index_error_invalid("ran out of data while parsing"); \
		goto done; } \
2642 2643 2644 2645 2646
	buffer += _increase; \
	buffer_size -= _increase;\
}

	if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE)
2647
		return index_error_invalid("insufficient buffer space");
2648 2649 2650

	/* Precalculate the SHA1 of the files's contents -- we'll match it to
	 * the provided SHA1 in the footer */
2651
	git_hash_buf(&checksum_calculated, buffer, buffer_size - INDEX_FOOTER_SIZE);
2652 2653

	/* Parse header */
2654 2655
	if ((error = read_header(&header, buffer)) < 0)
		return error;
2656

David Turner committed
2657 2658
	index->version = header.version;
	if (index->version >= INDEX_VERSION_NUMBER_COMP)
2659
		last = empty;
David Turner committed
2660

2661 2662
	seek_forward(INDEX_HEADER_SIZE);

Edward Thomson committed
2663
	GIT_ASSERT(!index->entries.length);
2664

2665
	if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0)
2666
		return error;
2667

2668
	/* Parse all the entries */
2669
	for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
2670
		git_index_entry *entry = NULL;
2671
		size_t entry_size;
2672

2673
		if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) {
2674 2675 2676
			error = index_error_invalid("invalid entry");
			goto done;
		}
2677

2678 2679
		if ((error = git_vector_insert(&index->entries, entry)) < 0) {
			index_entry_free(entry);
2680
			goto done;
2681
		}
2682

2683
		if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) {
2684 2685 2686
			index_entry_free(entry);
			goto done;
		}
2687
		error = 0;
2688

2689 2690 2691
		if (index->version >= INDEX_VERSION_NUMBER_COMP)
			last = entry->path;

2692 2693 2694
		seek_forward(entry_size);
	}

2695 2696 2697 2698
	if (i != header.entry_count) {
		error = index_error_invalid("header entries changed while parsing");
		goto done;
	}
2699

2700 2701 2702 2703
	/* There's still space for some extensions! */
	while (buffer_size > INDEX_FOOTER_SIZE) {
		size_t extension_size;

2704
		if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) {
2705 2706
			goto done;
		}
2707 2708 2709 2710

		seek_forward(extension_size);
	}

2711 2712 2713 2714 2715
	if (buffer_size != INDEX_FOOTER_SIZE) {
		error = index_error_invalid(
			"buffer size does not match index footer size");
		goto done;
	}
2716 2717

	/* 160-bit SHA-1 over the content of the index file before this checksum. */
Vicent Marti committed
2718
	git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer);
2719

2720 2721 2722 2723 2724
	if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) {
		error = index_error_invalid(
			"calculated checksum does not match expected");
		goto done;
	}
2725

2726 2727
	git_oid_cpy(&index->checksum, &checksum_calculated);

2728 2729
#undef seek_forward

2730 2731 2732 2733
	/* 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);
2734
	git_vector_sort(&index->entries);
2735

2736
	index->dirty = 0;
2737 2738
done:
	return error;
2739 2740
}

2741
static bool is_index_extended(git_index *index)
Vicent Marti committed
2742
{
2743
	size_t i, extended;
2744
	git_index_entry *entry;
Vicent Marti committed
2745 2746 2747

	extended = 0;

2748
	git_vector_foreach(&index->entries, i, entry) {
2749 2750
		entry->flags &= ~GIT_INDEX_ENTRY_EXTENDED;
		if (entry->flags_extended & GIT_INDEX_ENTRY_EXTENDED_FLAGS) {
Vicent Marti committed
2751
			extended++;
2752
			entry->flags |= GIT_INDEX_ENTRY_EXTENDED;
Vicent Marti committed
2753 2754
		}
	}
2755

2756
	return (extended > 0);
Vicent Marti committed
2757 2758
}

2759
static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last)
2760
{
2761
	void *mem = NULL;
2762
	struct entry_short ondisk;
2763
	size_t path_len, disk_size;
2764
	int varint_len = 0;
2765
	char *path;
David Turner committed
2766 2767
	const char *path_start = entry->path;
	size_t same_len = 0;
2768

2769
	path_len = ((struct entry_internal *)entry)->pathlen;
2770

David Turner committed
2771
	if (last) {
2772
		const char *last_c = last;
David Turner committed
2773 2774 2775 2776 2777 2778 2779 2780 2781

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

2785
	disk_size = index_entry_size(path_len, varint_len, entry->flags);
2786

2787 2788
	if (git_filebuf_reserve(file, &mem, disk_size) < 0)
		return -1;
2789

2790
	memset(mem, 0x0, disk_size);
2791

2792 2793 2794 2795 2796 2797 2798 2799 2800 2801
	/**
	 * 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
	 */
2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
	ondisk.ctime.seconds = htonl((uint32_t)entry->ctime.seconds);
	ondisk.mtime.seconds = htonl((uint32_t)entry->mtime.seconds);
	ondisk.ctime.nanoseconds = htonl(entry->ctime.nanoseconds);
	ondisk.mtime.nanoseconds = htonl(entry->mtime.nanoseconds);
	ondisk.dev = htonl(entry->dev);
	ondisk.ino = htonl(entry->ino);
	ondisk.mode = htonl(entry->mode);
	ondisk.uid = htonl(entry->uid);
	ondisk.gid = htonl(entry->gid);
	ondisk.file_size = htonl((uint32_t)entry->file_size);
2812

2813
	git_oid_cpy(&ondisk.oid, &entry->id);
2814

2815
	ondisk.flags = htons(entry->flags);
2816

2817
	if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) {
2818
		const size_t path_offset = offsetof(struct entry_long, path);
2819 2820 2821
		struct entry_long ondisk_ext;
		memcpy(&ondisk_ext, &ondisk, sizeof(struct entry_short));
		ondisk_ext.flags_extended = htons(entry->flags_extended &
2822
			GIT_INDEX_ENTRY_EXTENDED_FLAGS);
2823 2824 2825
		memcpy(mem, &ondisk_ext, path_offset);
		path = (char *)mem + path_offset;
		disk_size -= path_offset;
2826
	} else {
2827 2828 2829 2830
		const size_t path_offset = offsetof(struct entry_short, path);
		memcpy(mem, &ondisk, path_offset);
		path = (char *)mem + path_offset;
		disk_size -= path_offset;
2831
	}
2832

David Turner committed
2833
	if (last) {
2834
		varint_len = git_encode_varint((unsigned char *) path,
2835
					  disk_size, strlen(last) - same_len);
Edward Thomson committed
2836 2837
		GIT_ASSERT(varint_len > 0);

2838 2839 2840 2841 2842 2843 2844
		path += varint_len;
		disk_size -= varint_len;

		/*
		 * If using path compression, we are not allowed
		 * to have additional trailing NULs.
		 */
Edward Thomson committed
2845
		GIT_ASSERT(disk_size == path_len + 1);
2846 2847 2848 2849 2850 2851
	} 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
2852
		GIT_ASSERT(disk_size > path_len);
David Turner committed
2853
	}
2854 2855

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

2857
	return 0;
2858 2859
}

2860
static int write_entries(git_index *index, git_filebuf *file)
2861
{
2862
	int error = 0;
2863
	size_t i;
2864
	git_vector case_sorted = GIT_VECTOR_INIT, *entries = NULL;
2865
	git_index_entry *entry;
2866
	const char *last = NULL;
2867 2868 2869 2870

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

2874
		git_vector_sort(&case_sorted);
2875 2876 2877
		entries = &case_sorted;
	} else {
		entries = &index->entries;
2878 2879
	}

David Turner committed
2880
	if (index->version >= INDEX_VERSION_NUMBER_COMP)
2881
		last = "";
David Turner committed
2882

2883
	git_vector_foreach(entries, i, entry) {
David Turner committed
2884
		if ((error = write_disk_entry(file, entry, last)) < 0)
2885
			break;
2886 2887 2888
		if (index->version >= INDEX_VERSION_NUMBER_COMP)
			last = entry->path;
	}
2889

2890 2891
done:
	git_vector_free(&case_sorted);
2892
	return error;
2893 2894
}

Edward Thomson committed
2895 2896 2897 2898 2899 2900 2901 2902
static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data)
{
	struct index_extension ondisk;

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

2903 2904
	git_filebuf_write(file, &ondisk, sizeof(struct index_extension));
	return git_filebuf_write(file, data->ptr, data->size);
Edward Thomson committed
2905 2906
}

Edward Thomson committed
2907 2908 2909 2910 2911 2912 2913 2914
static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name)
{
	int error = 0;

	if (conflict_name->ancestor == NULL)
		error = git_buf_put(name_buf, "\0", 1);
	else
		error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1);
nulltoken committed
2915

Edward Thomson committed
2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943
	if (error != 0)
		goto on_error;

	if (conflict_name->ours == NULL)
		error = git_buf_put(name_buf, "\0", 1);
	else
		error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1);

	if (error != 0)
		goto on_error;

	if (conflict_name->theirs == NULL)
		error = git_buf_put(name_buf, "\0", 1);
	else
		error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1);

on_error:
	return error;
}

static int write_name_extension(git_index *index, git_filebuf *file)
{
	git_buf name_buf = GIT_BUF_INIT;
	git_vector *out = &index->names;
	git_index_name_entry *conflict_name;
	struct index_extension extension;
	size_t i;
	int error = 0;
nulltoken committed
2944

Edward Thomson committed
2945 2946 2947 2948
	git_vector_foreach(out, i, conflict_name) {
		if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0)
			goto done;
	}
nulltoken committed
2949

Edward Thomson committed
2950 2951 2952
	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
2953

Edward Thomson committed
2954
	error = write_extension(file, &extension, &name_buf);
nulltoken committed
2955

2956
	git_buf_dispose(&name_buf);
nulltoken committed
2957

Edward Thomson committed
2958 2959 2960 2961
done:
	return error;
}

Edward Thomson committed
2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989
static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc)
{
	int i;
	int error = 0;

	if ((error = git_buf_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0)
		return error;

	for (i = 0; i < 3; i++) {
		if ((error = git_buf_printf(reuc_buf, "%o", reuc->mode[i])) < 0 ||
			(error = git_buf_put(reuc_buf, "\0", 1)) < 0)
			return error;
	}

	for (i = 0; i < 3; i++) {
		if (reuc->mode[i] && (error = git_buf_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_RAWSZ)) < 0)
			return error;
	}

	return 0;
}

static int write_reuc_extension(git_index *index, git_filebuf *file)
{
	git_buf reuc_buf = GIT_BUF_INIT;
	git_vector *out = &index->reuc;
	git_index_reuc_entry *reuc;
	struct index_extension extension;
2990
	size_t i;
Edward Thomson committed
2991 2992 2993 2994 2995 2996 2997 2998 2999
	int error = 0;

	git_vector_foreach(out, i, reuc) {
		if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0)
			goto done;
	}

	memset(&extension, 0x0, sizeof(struct index_extension));
	memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4);
3000
	extension.extension_size = (uint32_t)reuc_buf.size;
Edward Thomson committed
3001 3002 3003

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

3004
	git_buf_dispose(&reuc_buf);
Edward Thomson committed
3005 3006 3007 3008 3009

done:
	return error;
}

3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027
static int write_tree_extension(git_index *index, git_filebuf *file)
{
	struct index_extension extension;
	git_buf buf = GIT_BUF_INIT;
	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);

3028
	git_buf_dispose(&buf);
3029 3030 3031 3032

	return error;
}

3033 3034 3035 3036 3037 3038
static void clear_uptodate(git_index *index)
{
	git_index_entry *entry;
	size_t i;

	git_vector_foreach(&index->entries, i, entry)
3039
		entry->flags_extended &= ~GIT_INDEX_ENTRY_UPTODATE;
3040 3041
}

3042
static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
3043 3044 3045
{
	git_oid hash_final;
	struct index_header header;
3046
	bool is_extended;
Ben Straub committed
3047
	uint32_t index_version_number;
3048

Edward Thomson committed
3049 3050
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(file);
3051

David Turner committed
3052 3053 3054 3055 3056 3057
	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
3058

3059
	header.signature = htonl(INDEX_HEADER_SIG);
Ben Straub committed
3060
	header.version = htonl(index_version_number);
3061
	header.entry_count = htonl((uint32_t)index->entries.length);
3062

3063 3064
	if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0)
		return -1;
3065

3066 3067
	if (write_entries(index, file) < 0)
		return -1;
3068

3069 3070 3071
	/* write the tree cache extension */
	if (index->tree != NULL && write_tree_extension(index, file) < 0)
		return -1;
Edward Thomson committed
3072

Edward Thomson committed
3073 3074 3075
	/* write the rename conflict extension */
	if (index->names.length > 0 && write_name_extension(index, file) < 0)
		return -1;
nulltoken committed
3076

Edward Thomson committed
3077 3078 3079
	/* write the reuc extension */
	if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0)
		return -1;
3080

3081 3082
	/* get out the hash for all the contents we've appended to the file */
	git_filebuf_hash(&hash_final, file);
3083
	git_oid_cpy(checksum, &hash_final);
3084 3085

	/* write it at the end of the file */
3086 3087 3088 3089 3090 3091 3092
	if (git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ) < 0)
		return -1;

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

	return 0;
3093
}
3094 3095 3096

int git_index_entry_stage(const git_index_entry *entry)
{
3097
	return GIT_INDEX_ENTRY_STAGE(entry);
3098
}
3099

3100 3101
int git_index_entry_is_conflict(const git_index_entry *entry)
{
3102
	return (GIT_INDEX_ENTRY_STAGE(entry) > 0);
3103 3104
}

3105
typedef struct read_tree_data {
3106
	git_index *index;
3107
	git_vector *old_entries;
3108
	git_vector *new_entries;
3109
	git_vector_cmp entry_cmp;
3110
	git_tree_cache *tree;
3111 3112
} read_tree_data;

3113 3114
static int read_tree_cb(
	const char *root, const git_tree_entry *tentry, void *payload)
3115
{
3116 3117
	read_tree_data *data = payload;
	git_index_entry *entry = NULL, *old_entry;
3118
	git_buf path = GIT_BUF_INIT;
3119
	size_t pos;
3120

Vicent Martí committed
3121
	if (git_tree_entry__is_tree(tentry))
3122
		return 0;
3123

3124 3125
	if (git_buf_joinpath(&path, root, tentry->filename) < 0)
		return -1;
3126

3127
	if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0)
3128
		return -1;
3129 3130

	entry->mode = tentry->attr;
3131
	git_oid_cpy(&entry->id, git_tree_entry_id(tentry));
3132

3133
	/* look for corresponding old entry and copy data to new entry */
3134
	if (data->old_entries != NULL &&
3135
		!index_find_in_entries(
3136 3137 3138 3139 3140
			&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))
	{
3141
		index_entry_cpy(entry, old_entry);
3142
		entry->flags_extended = 0;
3143 3144
	}

3145
	index_entry_adjust_namemask(entry, path.size);
3146
	git_buf_dispose(&path);
3147

3148
	if (git_vector_insert(data->new_entries, entry) < 0) {
3149
		index_entry_free(entry);
3150 3151 3152 3153
		return -1;
	}

	return 0;
3154 3155
}

Ben Straub committed
3156
int git_index_read_tree(git_index *index, const git_tree *tree)
3157
{
3158 3159
	int error = 0;
	git_vector entries = GIT_VECTOR_INIT;
3160
	git_idxmap *entries_map;
3161
	read_tree_data data;
3162 3163 3164
	size_t i;
	git_index_entry *e;

3165
	if (git_idxmap_new(&entries_map) < 0)
3166
		return -1;
3167

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

3170
	data.index = index;
3171 3172
	data.old_entries = &index->entries;
	data.new_entries = &entries;
3173
	data.entry_cmp   = index->entries_search;
3174

3175 3176 3177
	index->tree = NULL;
	git_pool_clear(&index->tree_pool);

3178
	git_vector_sort(&index->entries);
3179

3180 3181
	if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0)
		goto cleanup;
3182

3183
	if ((error = index_map_resize(entries_map, entries.length, index->ignore_case)) < 0)
3184
		goto cleanup;
3185

3186
	git_vector_foreach(&entries, i, e) {
3187
		if ((error = index_map_set(entries_map, e, index->ignore_case)) < 0) {
3188
			git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map");
3189
			return error;
3190
		}
3191 3192
	}

3193 3194 3195 3196
	error = 0;

	git_vector_sort(&entries);

3197
	if ((error = git_index_clear(index)) < 0) {
3198 3199 3200
		/* well, this isn't good */;
	} else {
		git_vector_swap(&entries, &index->entries);
3201
		entries_map = git_atomic_swap(index->entries_map, entries_map);
3202 3203
	}

3204 3205
	index->dirty = 1;

3206
cleanup:
3207
	git_vector_free(&entries);
3208
	git_idxmap_free(entries_map);
3209 3210 3211 3212
	if (error < 0)
		return error;

	error = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool);
3213 3214

	return error;
3215
}
3216

3217
static int git_index_read_iterator(
3218
	git_index *index,
3219 3220
	git_iterator *new_iterator,
	size_t new_length_hint)
3221 3222 3223
{
	git_vector new_entries = GIT_VECTOR_INIT,
		remove_entries = GIT_VECTOR_INIT;
3224
	git_idxmap *new_entries_map = NULL;
3225
	git_iterator *index_iterator = NULL;
3226
	git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
3227 3228 3229 3230 3231
	const git_index_entry *old_entry, *new_entry;
	git_index_entry *entry;
	size_t i;
	int error;

Edward Thomson committed
3232
	GIT_ASSERT((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
3233 3234

	if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 ||
3235 3236
	    (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
	    (error = git_idxmap_new(&new_entries_map)) < 0)
3237 3238
		goto done;

3239 3240
	if (new_length_hint && (error = index_map_resize(new_entries_map, new_length_hint,
							 index->ignore_case)) < 0)
3241
		goto done;
3242

3243 3244
	opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_CONFLICTS;
3245

3246 3247 3248
	if ((error = git_iterator_for_index(&index_iterator,
			git_index_owner(index), index, &opts)) < 0 ||
		((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
3249
			error != GIT_ITEROVER) ||
3250
		((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
3251 3252 3253 3254
			error != GIT_ITEROVER))
		goto done;

	while (true) {
3255 3256 3257 3258
		git_index_entry
			*dup_entry = NULL,
			*add_entry = NULL,
			*remove_entry = NULL;
3259 3260
		int diff;

3261 3262
		error = 0;

3263 3264 3265 3266 3267 3268 3269 3270 3271 3272
		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) {
3273
			remove_entry = (git_index_entry *)old_entry;
3274
		} else if (diff > 0) {
3275
			dup_entry = (git_index_entry *)new_entry;
3276 3277 3278 3279
		} else {
			/* Path and stage are equal, if the OID is equal, keep it to
			 * keep the stat cache data.
			 */
3280 3281
			if (git_oid_equal(&old_entry->id, &new_entry->id) &&
				old_entry->mode == new_entry->mode) {
3282
				add_entry = (git_index_entry *)old_entry;
3283
			} else {
3284
				dup_entry = (git_index_entry *)new_entry;
3285
				remove_entry = (git_index_entry *)old_entry;
3286 3287 3288
			}
		}

3289 3290 3291
		if (dup_entry) {
			if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0)
				goto done;
3292 3293 3294

			index_entry_adjust_namemask(add_entry,
				((struct entry_internal *)add_entry)->pathlen);
3295 3296
		}

3297 3298 3299 3300 3301 3302
		/* 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);

3303 3304
		if (add_entry) {
			if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
3305 3306
				error = index_map_set(new_entries_map, add_entry,
						      index->ignore_case);
3307 3308
		}

3309
		if (remove_entry && error >= 0)
3310 3311 3312
			error = git_vector_insert(&remove_entries, remove_entry);

		if (error < 0) {
3313
			git_error_set(GIT_ERROR_INDEX, "failed to insert entry");
3314
			goto done;
3315 3316
		}

3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329
		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;
		}
	}

3330 3331 3332
	if ((error = git_index_name_clear(index)) < 0 ||
		(error = git_index_reuc_clear(index)) < 0)
	    goto done;
3333 3334

	git_vector_swap(&new_entries, &index->entries);
3335
	new_entries_map = git_atomic_swap(index->entries_map, new_entries_map);
3336 3337 3338 3339 3340 3341 3342 3343

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

		index_entry_free(entry);
	}

3344 3345
	clear_uptodate(index);

3346
	index->dirty = 1;
3347 3348 3349
	error = 0;

done:
3350
	git_idxmap_free(new_entries_map);
3351 3352 3353
	git_vector_free(&new_entries);
	git_vector_free(&remove_entries);
	git_iterator_free(index_iterator);
3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364
	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;

3365 3366
	opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_CONFLICTS;
3367 3368

	if ((error = git_iterator_for_index(&new_iterator,
3369 3370 3371
		git_index_owner(new_index), (git_index *)new_index, &opts)) < 0 ||
		(error = git_index_read_iterator(index, new_iterator,
		new_index->entries.length)) < 0)
3372 3373 3374
		goto done;

done:
3375 3376 3377 3378
	git_iterator_free(new_iterator);
	return error;
}

3379 3380 3381 3382
git_repository *git_index_owner(const git_index *index)
{
	return INDEX_OWNER(index);
}
3383

3384 3385 3386 3387 3388 3389 3390
enum {
	INDEX_ACTION_NONE = 0,
	INDEX_ACTION_UPDATE = 1,
	INDEX_ACTION_REMOVE = 2,
	INDEX_ACTION_ADDALL = 3,
};

3391 3392 3393 3394 3395 3396 3397 3398 3399 3400
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;
	git_iterator *wditer = NULL;
3401
	git_pathspec ps;
3402 3403
	bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;

Edward Thomson committed
3404
	GIT_ASSERT_ARG(index);
3405 3406 3407 3408 3409

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

3410
	if ((error = git_pathspec__init(&ps, paths)) < 0)
3411 3412 3413 3414 3415 3416 3417 3418 3419
		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;

3420
	error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload);
3421

3422
	if (error)
3423
		git_error_set_after_callback(error);
3424 3425 3426

cleanup:
	git_iterator_free(wditer);
3427
	git_pathspec__clear(&ps);
3428 3429 3430 3431

	return error;
}

3432 3433 3434
struct foreach_diff_data {
	git_index *index;
	const git_pathspec *pathspec;
3435
	unsigned int flags;
3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463
	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;

3464 3465
	/* If the workdir item does not exist, remove it from the index. */
	if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
3466 3467
		error = git_index_remove_bypath(data->index, path);
	else
3468
		error = git_index_add_bypath(data->index, delta->new_file.path);
3469 3470 3471 3472 3473

	return error;
}

static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
3474
				  unsigned int flags,
3475 3476 3477 3478 3479 3480
				  git_index_matched_path_cb cb, void *payload)
{
	int error;
	git_diff *diff;
	git_pathspec ps;
	git_repository *repo;
3481
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
3482 3483 3484
	struct foreach_diff_data data = {
		index,
		NULL,
3485
		flags,
3486 3487 3488 3489
		cb,
		payload,
	};

Edward Thomson committed
3490 3491
	GIT_ASSERT_ARG(index);
	GIT_ASSERT_ARG(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507

	repo = INDEX_OWNER(index);

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

	/*
	 * We do the matching ourselves intead of passing the list to
	 * 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;

3508
	opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
3509
	if (action == INDEX_ACTION_ADDALL) {
3510
		opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
3511
			GIT_DIFF_RECURSE_UNTRACKED_DIRS;
3512

3513 3514 3515 3516 3517
		if (flags == GIT_INDEX_ADD_FORCE)
			opts.flags |= GIT_DIFF_INCLUDE_IGNORED;
	}

	if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0)
3518 3519 3520
		goto cleanup;

	data.pathspec = &ps;
3521
	error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data);
3522 3523 3524
	git_diff_free(diff);

	if (error) /* make sure error is set if callback stopped iteration */
3525
		git_error_set_after_callback(error);
3526 3527 3528 3529 3530 3531

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

3532 3533 3534 3535 3536 3537 3538 3539 3540
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;
3541
	git_pathspec ps;
3542
	const char *match;
3543
	git_buf path = GIT_BUF_INIT;
3544

Edward Thomson committed
3545
	GIT_ASSERT_ARG(index);
3546

3547
	if ((error = git_pathspec__init(&ps, paths)) < 0)
3548 3549 3550 3551 3552 3553 3554 3555
		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 */
3556
		if (!git_pathspec__match(
Linquize committed
3557
				&ps.pathspec, entry->path, false, (bool)index->ignore_case,
3558
				&match, NULL))
3559 3560 3561 3562 3563 3564 3565 3566
			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;
			}
3567
			if (error < 0)   /* return < 0 means abort */
3568 3569 3570
				break;
		}

3571 3572 3573 3574
		/* index manipulation may alter entry, so don't depend on it */
		if ((error = git_buf_sets(&path, entry->path)) < 0)
			break;

3575 3576 3577 3578
		switch (action) {
		case INDEX_ACTION_NONE:
			break;
		case INDEX_ACTION_UPDATE:
3579
			error = git_index_add_bypath(index, path.ptr);
3580 3581

			if (error == GIT_ENOTFOUND) {
3582
				git_error_clear();
3583

3584
				error = git_index_remove_bypath(index, path.ptr);
3585 3586 3587 3588 3589 3590

				if (!error) /* back up foreach if we removed this */
					i--;
			}
			break;
		case INDEX_ACTION_REMOVE:
3591
			if (!(error = git_index_remove_bypath(index, path.ptr)))
3592 3593 3594
				i--; /* back up foreach if we removed this */
			break;
		default:
3595
			git_error_set(GIT_ERROR_INVALID, "unknown index action %d", action);
3596 3597 3598 3599 3600
			error = -1;
			break;
		}
	}

3601
	git_buf_dispose(&path);
3602
	git_pathspec__clear(&ps);
3603 3604 3605 3606 3607 3608 3609 3610 3611 3612

	return error;
}

int git_index_remove_all(
	git_index *index,
	const git_strarray *pathspec,
	git_index_matched_path_cb cb,
	void *payload)
{
3613
	int error = index_apply_to_all(
3614
		index, INDEX_ACTION_REMOVE, pathspec, cb, payload);
3615 3616

	if (error) /* make sure error is set if callback stopped iteration */
3617
		git_error_set_after_callback(error);
3618 3619

	return error;
3620 3621 3622 3623 3624 3625 3626 3627
}

int git_index_update_all(
	git_index *index,
	const git_strarray *pathspec,
	git_index_matched_path_cb cb,
	void *payload)
{
3628
	int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload);
3629
	if (error) /* make sure error is set if callback stopped iteration */
3630
		git_error_set_after_callback(error);
3631 3632

	return error;
3633
}
3634

3635
int git_index_snapshot_new(git_vector *snap, git_index *index)
3636 3637 3638 3639
{
	int error;

	GIT_REFCOUNT_INC(index);
3640

3641
	git_atomic32_inc(&index->readers);
3642
	git_vector_sort(&index->entries);
3643

3644
	error = git_vector_dup(snap, &index->entries, index->entries._cmp);
3645 3646

	if (error < 0)
3647
		git_index_snapshot_release(snap, index);
3648 3649 3650 3651

	return error;
}

3652
void git_index_snapshot_release(git_vector *snap, git_index *index)
3653
{
3654 3655
	git_vector_free(snap);

3656
	git_atomic32_dec(&index->readers);
3657

3658
	git_index_free(index);
3659
}
3660 3661 3662 3663 3664 3665 3666

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);
}
3667 3668 3669 3670 3671 3672 3673

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

3674 3675
	GIT_REFCOUNT_INC(index);

3676 3677 3678 3679
	writer->index = index;

	if (!index->index_file_path)
		return create_index_error(-1,
3680
			"failed to write index: The index is in-memory only");
3681 3682 3683

	if ((error = git_filebuf_open(
		&writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) {
3684

3685
		if (error == GIT_ELOCKED)
3686
			git_error_set(GIT_ERROR_INDEX, "the index is locked; this might be due to a concurrent or crashed process");
3687 3688 3689 3690

		return error;
	}

3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710
	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;

3711 3712 3713 3714 3715 3716
	return 0;
}

int git_indexwriter_commit(git_indexwriter *writer)
{
	int error;
3717
	git_oid checksum = {{ 0 }};
3718

3719 3720 3721
	if (!writer->should_write)
		return 0;

3722
	git_vector_sort(&writer->index->entries);
3723 3724
	git_vector_sort(&writer->index->reuc);

3725
	if ((error = write_index(&checksum, writer->index, &writer->file)) < 0) {
3726 3727 3728 3729 3730 3731 3732 3733 3734
		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) {
3735
		git_error_set(GIT_ERROR_OS, "could not read index timestamp");
3736 3737 3738
		return -1;
	}

3739
	writer->index->dirty = 0;
3740
	writer->index->on_disk = 1;
3741
	git_oid_cpy(&writer->index->checksum, &checksum);
3742

3743 3744 3745
	git_index_free(writer->index);
	writer->index = NULL;

3746 3747 3748 3749 3750 3751
	return 0;
}

void git_indexwriter_cleanup(git_indexwriter *writer)
{
	git_filebuf_cleanup(&writer->file);
3752 3753 3754

	git_index_free(writer->index);
	writer->index = NULL;
3755
}
3756 3757 3758

/* Deprecated functions */

3759
#ifndef GIT_DEPRECATE_HARD
3760 3761 3762 3763 3764 3765
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);
}
3766
#endif