1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "checkout.h"
9 
10 #include <assert.h>
11 
12 #include "git2/repository.h"
13 #include "git2/refs.h"
14 #include "git2/tree.h"
15 #include "git2/blob.h"
16 #include "git2/config.h"
17 #include "git2/diff.h"
18 #include "git2/submodule.h"
19 #include "git2/sys/index.h"
20 #include "git2/sys/filter.h"
21 #include "git2/merge.h"
22 
23 #include "refs.h"
24 #include "repository.h"
25 #include "index.h"
26 #include "filter.h"
27 #include "blob.h"
28 #include "diff.h"
29 #include "diff_generate.h"
30 #include "pathspec.h"
31 #include "buf_text.h"
32 #include "diff_xdiff.h"
33 #include "path.h"
34 #include "attr.h"
35 #include "pool.h"
36 #include "strmap.h"
37 
38 /* See docs/checkout-internals.md for more information */
39 
40 enum {
41 	CHECKOUT_ACTION__NONE = 0,
42 	CHECKOUT_ACTION__REMOVE = 1,
43 	CHECKOUT_ACTION__UPDATE_BLOB = 2,
44 	CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
45 	CHECKOUT_ACTION__CONFLICT = 8,
46 	CHECKOUT_ACTION__REMOVE_CONFLICT = 16,
47 	CHECKOUT_ACTION__UPDATE_CONFLICT = 32,
48 	CHECKOUT_ACTION__MAX = 32,
49 	CHECKOUT_ACTION__DEFER_REMOVE = 64,
50 	CHECKOUT_ACTION__REMOVE_AND_UPDATE =
51 		(CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
52 };
53 
54 typedef struct {
55 	git_repository *repo;
56 	git_iterator *target;
57 	git_diff *diff;
58 	git_checkout_options opts;
59 	bool opts_free_baseline;
60 	char *pfx;
61 	git_index *index;
62 	git_pool pool;
63 	git_vector removes;
64 	git_vector remove_conflicts;
65 	git_vector update_conflicts;
66 	git_vector *update_reuc;
67 	git_vector *update_names;
68 	git_buf target_path;
69 	size_t target_len;
70 	git_buf tmp;
71 	unsigned int strategy;
72 	int can_symlink;
73 	int respect_filemode;
74 	bool reload_submodules;
75 	size_t total_steps;
76 	size_t completed_steps;
77 	git_checkout_perfdata perfdata;
78 	git_strmap *mkdir_map;
79 	git_attr_session attr_session;
80 } checkout_data;
81 
82 typedef struct {
83 	const git_index_entry *ancestor;
84 	const git_index_entry *ours;
85 	const git_index_entry *theirs;
86 
87 	int name_collision:1,
88 		directoryfile:1,
89 		one_to_two:1,
90 		binary:1,
91 		submodule:1;
92 } checkout_conflictdata;
93 
checkout_notify(checkout_data * data,git_checkout_notify_t why,const git_diff_delta * delta,const git_index_entry * wditem)94 static int checkout_notify(
95 	checkout_data *data,
96 	git_checkout_notify_t why,
97 	const git_diff_delta *delta,
98 	const git_index_entry *wditem)
99 {
100 	git_diff_file wdfile;
101 	const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL;
102 	const char *path = NULL;
103 
104 	if (!data->opts.notify_cb ||
105 		(why & data->opts.notify_flags) == 0)
106 		return 0;
107 
108 	if (wditem) {
109 		memset(&wdfile, 0, sizeof(wdfile));
110 
111 		git_oid_cpy(&wdfile.id, &wditem->id);
112 		wdfile.path = wditem->path;
113 		wdfile.size = wditem->file_size;
114 		wdfile.flags = GIT_DIFF_FLAG_VALID_ID;
115 		wdfile.mode = wditem->mode;
116 
117 		workdir = &wdfile;
118 
119 		path = wditem->path;
120 	}
121 
122 	if (delta) {
123 		switch (delta->status) {
124 		case GIT_DELTA_UNMODIFIED:
125 		case GIT_DELTA_MODIFIED:
126 		case GIT_DELTA_TYPECHANGE:
127 		default:
128 			baseline = &delta->old_file;
129 			target = &delta->new_file;
130 			break;
131 		case GIT_DELTA_ADDED:
132 		case GIT_DELTA_IGNORED:
133 		case GIT_DELTA_UNTRACKED:
134 		case GIT_DELTA_UNREADABLE:
135 			target = &delta->new_file;
136 			break;
137 		case GIT_DELTA_DELETED:
138 			baseline = &delta->old_file;
139 			break;
140 		}
141 
142 		path = delta->old_file.path;
143 	}
144 
145 	{
146 		int error = data->opts.notify_cb(
147 			why, path, baseline, target, workdir, data->opts.notify_payload);
148 
149 		return git_error_set_after_callback_function(
150 			error, "git_checkout notification");
151 	}
152 }
153 
is_workdir_base_or_new(const git_oid * workdir_id,const git_diff_file * baseitem,const git_diff_file * newitem)154 GIT_INLINE(bool) is_workdir_base_or_new(
155 	const git_oid *workdir_id,
156 	const git_diff_file *baseitem,
157 	const git_diff_file *newitem)
158 {
159 	return (git_oid__cmp(&baseitem->id, workdir_id) == 0 ||
160 		git_oid__cmp(&newitem->id, workdir_id) == 0);
161 }
162 
is_filemode_changed(git_filemode_t a,git_filemode_t b,int respect_filemode)163 GIT_INLINE(bool) is_filemode_changed(git_filemode_t a, git_filemode_t b, int respect_filemode)
164 {
165 	/* If core.filemode = false, ignore links in the repository and executable bit changes */
166 	if (!respect_filemode) {
167 		if (a == S_IFLNK)
168 			a = GIT_FILEMODE_BLOB;
169 		if (b == S_IFLNK)
170 			b = GIT_FILEMODE_BLOB;
171 
172 		a &= ~0111;
173 		b &= ~0111;
174 	}
175 
176 	return (a != b);
177 }
178 
checkout_is_workdir_modified(checkout_data * data,const git_diff_file * baseitem,const git_diff_file * newitem,const git_index_entry * wditem)179 static bool checkout_is_workdir_modified(
180 	checkout_data *data,
181 	const git_diff_file *baseitem,
182 	const git_diff_file *newitem,
183 	const git_index_entry *wditem)
184 {
185 	git_oid oid;
186 	const git_index_entry *ie;
187 
188 	/* handle "modified" submodule */
189 	if (wditem->mode == GIT_FILEMODE_COMMIT) {
190 		git_submodule *sm;
191 		unsigned int sm_status = 0;
192 		const git_oid *sm_oid = NULL;
193 		bool rval = false;
194 
195 		if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0) {
196 			git_error_clear();
197 			return true;
198 		}
199 
200 		if (git_submodule_status(&sm_status, data->repo, wditem->path, GIT_SUBMODULE_IGNORE_UNSPECIFIED) < 0 ||
201 			GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
202 			rval = true;
203 		else if ((sm_oid = git_submodule_wd_id(sm)) == NULL)
204 			rval = false;
205 		else
206 			rval = (git_oid__cmp(&baseitem->id, sm_oid) != 0);
207 
208 		git_submodule_free(sm);
209 		return rval;
210 	}
211 
212 	/*
213 	 * Look at the cache to decide if the workdir is modified: if the
214 	 * cache contents match the workdir contents, then we do not need
215 	 * to examine the working directory directly, instead we can
216 	 * examine the cache to see if _it_ has been modified.  This allows
217 	 * us to avoid touching the disk.
218 	 */
219 	ie = git_index_get_bypath(data->index, wditem->path, 0);
220 
221 	if (ie != NULL &&
222 		git_index_time_eq(&wditem->mtime, &ie->mtime) &&
223 		wditem->file_size == ie->file_size &&
224 		!is_filemode_changed(wditem->mode, ie->mode, data->respect_filemode)) {
225 
226 		/* The workdir is modified iff the index entry is modified */
227 		return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
228 			is_filemode_changed(baseitem->mode, ie->mode, data->respect_filemode);
229 	}
230 
231 	/* depending on where base is coming from, we may or may not know
232 	 * the actual size of the data, so we can't rely on this shortcut.
233 	 */
234 	if (baseitem->size && wditem->file_size != baseitem->size)
235 		return true;
236 
237 	/* if the workdir item is a directory, it cannot be a modified file */
238 	if (S_ISDIR(wditem->mode))
239 		return false;
240 
241 	if (is_filemode_changed(baseitem->mode, wditem->mode, data->respect_filemode))
242 		return true;
243 
244 	if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
245 		return false;
246 
247 	/* Allow the checkout if the workdir is not modified *or* if the checkout
248 	 * target's contents are already in the working directory.
249 	 */
250 	return !is_workdir_base_or_new(&oid, baseitem, newitem);
251 }
252 
253 #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
254 	((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
255 
checkout_action_common(int * action,checkout_data * data,const git_diff_delta * delta,const git_index_entry * wd)256 static int checkout_action_common(
257 	int *action,
258 	checkout_data *data,
259 	const git_diff_delta *delta,
260 	const git_index_entry *wd)
261 {
262 	git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
263 
264 	if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
265 		*action = (*action & ~CHECKOUT_ACTION__REMOVE);
266 
267 	if ((*action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) {
268 		if (S_ISGITLINK(delta->new_file.mode))
269 			*action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB) |
270 				CHECKOUT_ACTION__UPDATE_SUBMODULE;
271 
272 		/* to "update" a symlink, we must remove the old one first */
273 		if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL)
274 			*action |= CHECKOUT_ACTION__REMOVE;
275 
276 		/* if the file is on disk and doesn't match our mode, force update */
277 		if (wd &&
278 			GIT_PERMS_IS_EXEC(wd->mode) !=
279 			GIT_PERMS_IS_EXEC(delta->new_file.mode))
280 				*action |= CHECKOUT_ACTION__REMOVE;
281 
282 		notify = GIT_CHECKOUT_NOTIFY_UPDATED;
283 	}
284 
285 	if ((*action & CHECKOUT_ACTION__CONFLICT) != 0)
286 		notify = GIT_CHECKOUT_NOTIFY_CONFLICT;
287 
288 	return checkout_notify(data, notify, delta, wd);
289 }
290 
checkout_action_no_wd(int * action,checkout_data * data,const git_diff_delta * delta)291 static int checkout_action_no_wd(
292 	int *action,
293 	checkout_data *data,
294 	const git_diff_delta *delta)
295 {
296 	int error = 0;
297 
298 	*action = CHECKOUT_ACTION__NONE;
299 
300 	switch (delta->status) {
301 	case GIT_DELTA_UNMODIFIED: /* case 12 */
302 		error = checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL);
303 		if (error)
304 			return error;
305 		*action = CHECKOUT_ACTION_IF(RECREATE_MISSING, UPDATE_BLOB, NONE);
306 		break;
307 	case GIT_DELTA_ADDED:    /* case 2 or 28 (and 5 but not really) */
308 		*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
309 		break;
310 	case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
311 		*action = CHECKOUT_ACTION_IF(RECREATE_MISSING, UPDATE_BLOB, CONFLICT);
312 		break;
313 	case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/
314 		if (delta->new_file.mode == GIT_FILEMODE_TREE)
315 			*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
316 		break;
317 	case GIT_DELTA_DELETED: /* case 8 or 25 */
318 		*action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
319 		break;
320 	default: /* impossible */
321 		break;
322 	}
323 
324 	return checkout_action_common(action, data, delta, NULL);
325 }
326 
checkout_target_fullpath(git_buf ** out,checkout_data * data,const char * path)327 static int checkout_target_fullpath(
328 	git_buf **out, checkout_data *data, const char *path)
329 {
330 	git_buf_truncate(&data->target_path, data->target_len);
331 
332 	if (path && git_buf_puts(&data->target_path, path) < 0)
333 		return -1;
334 
335 	*out = &data->target_path;
336 
337 	return 0;
338 }
339 
wd_item_is_removable(checkout_data * data,const git_index_entry * wd)340 static bool wd_item_is_removable(
341 	checkout_data *data, const git_index_entry *wd)
342 {
343 	git_buf *full;
344 
345 	if (wd->mode != GIT_FILEMODE_TREE)
346 		return true;
347 
348 	if (checkout_target_fullpath(&full, data, wd->path) < 0)
349 		return false;
350 
351 	return !full || !git_path_contains(full, DOT_GIT);
352 }
353 
checkout_queue_remove(checkout_data * data,const char * path)354 static int checkout_queue_remove(checkout_data *data, const char *path)
355 {
356 	char *copy = git_pool_strdup(&data->pool, path);
357 	GIT_ERROR_CHECK_ALLOC(copy);
358 	return git_vector_insert(&data->removes, copy);
359 }
360 
361 /* note that this advances the iterator over the wd item */
checkout_action_wd_only(checkout_data * data,git_iterator * workdir,const git_index_entry ** wditem,git_vector * pathspec)362 static int checkout_action_wd_only(
363 	checkout_data *data,
364 	git_iterator *workdir,
365 	const git_index_entry **wditem,
366 	git_vector *pathspec)
367 {
368 	int error = 0;
369 	bool remove = false;
370 	git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
371 	const git_index_entry *wd = *wditem;
372 
373 	if (!git_pathspec__match(
374 			pathspec, wd->path,
375 			(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
376 			git_iterator_ignore_case(workdir), NULL, NULL))
377 		return git_iterator_advance(wditem, workdir);
378 
379 	/* check if item is tracked in the index but not in the checkout diff */
380 	if (data->index != NULL) {
381 		size_t pos;
382 
383 		error = git_index__find_pos(
384 			&pos, data->index, wd->path, 0, GIT_INDEX_STAGE_ANY);
385 
386 		if (wd->mode != GIT_FILEMODE_TREE) {
387 			if (!error) { /* found by git_index__find_pos call */
388 				notify = GIT_CHECKOUT_NOTIFY_DIRTY;
389 				remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
390 			} else if (error != GIT_ENOTFOUND)
391 				return error;
392 			else
393 				error = 0; /* git_index__find_pos does not set error msg */
394 		} else {
395 			/* for tree entries, we have to see if there are any index
396 			 * entries that are contained inside that tree
397 			 */
398 			const git_index_entry *e = git_index_get_byindex(data->index, pos);
399 
400 			if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0)
401 				return git_iterator_advance_into(wditem, workdir);
402 		}
403 	}
404 
405 	if (notify != GIT_CHECKOUT_NOTIFY_NONE) {
406 		/* if we found something in the index, notify and advance */
407 		if ((error = checkout_notify(data, notify, NULL, wd)) != 0)
408 			return error;
409 
410 		if (remove && wd_item_is_removable(data, wd))
411 			error = checkout_queue_remove(data, wd->path);
412 
413 		if (!error)
414 			error = git_iterator_advance(wditem, workdir);
415 	} else {
416 		/* untracked or ignored - can't know which until we advance through */
417 		bool over = false, removable = wd_item_is_removable(data, wd);
418 		git_iterator_status_t untracked_state;
419 
420 		/* copy the entry for issuing notification callback later */
421 		git_index_entry saved_wd = *wd;
422 		git_buf_sets(&data->tmp, wd->path);
423 		saved_wd.path = data->tmp.ptr;
424 
425 		error = git_iterator_advance_over(
426 			wditem, &untracked_state, workdir);
427 		if (error == GIT_ITEROVER)
428 			over = true;
429 		else if (error < 0)
430 			return error;
431 
432 		if (untracked_state == GIT_ITERATOR_STATUS_IGNORED) {
433 			notify = GIT_CHECKOUT_NOTIFY_IGNORED;
434 			remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
435 		} else {
436 			notify = GIT_CHECKOUT_NOTIFY_UNTRACKED;
437 			remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0);
438 		}
439 
440 		if ((error = checkout_notify(data, notify, NULL, &saved_wd)) != 0)
441 			return error;
442 
443 		if (remove && removable)
444 			error = checkout_queue_remove(data, saved_wd.path);
445 
446 		if (!error && over) /* restore ITEROVER if needed */
447 			error = GIT_ITEROVER;
448 	}
449 
450 	return error;
451 }
452 
submodule_is_config_only(checkout_data * data,const char * path)453 static bool submodule_is_config_only(
454 	checkout_data *data,
455 	const char *path)
456 {
457 	git_submodule *sm = NULL;
458 	unsigned int sm_loc = 0;
459 	bool rval = false;
460 
461 	if (git_submodule_lookup(&sm, data->repo, path) < 0)
462 		return true;
463 
464 	if (git_submodule_location(&sm_loc, sm) < 0 ||
465 		sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
466 		rval = true;
467 
468 	git_submodule_free(sm);
469 
470 	return rval;
471 }
472 
checkout_is_empty_dir(checkout_data * data,const char * path)473 static bool checkout_is_empty_dir(checkout_data *data, const char *path)
474 {
475 	git_buf *fullpath;
476 
477 	if (checkout_target_fullpath(&fullpath, data, path) < 0)
478 		return false;
479 
480 	return git_path_is_empty_dir(fullpath->ptr);
481 }
482 
checkout_action_with_wd(int * action,checkout_data * data,const git_diff_delta * delta,git_iterator * workdir,const git_index_entry * wd)483 static int checkout_action_with_wd(
484 	int *action,
485 	checkout_data *data,
486 	const git_diff_delta *delta,
487 	git_iterator *workdir,
488 	const git_index_entry *wd)
489 {
490 	*action = CHECKOUT_ACTION__NONE;
491 
492 	switch (delta->status) {
493 	case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */
494 		if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) {
495 			GIT_ERROR_CHECK_ERROR(
496 				checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
497 			*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
498 		}
499 		break;
500 	case GIT_DELTA_ADDED: /* case 3, 4 or 6 */
501 		if (git_iterator_current_is_ignored(workdir))
502 			*action = CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, UPDATE_BLOB);
503 		else
504 			*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
505 		break;
506 	case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
507 		if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
508 			*action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
509 		else
510 			*action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
511 		break;
512 	case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
513 		if (wd->mode != GIT_FILEMODE_COMMIT &&
514 			checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
515 			*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
516 		else
517 			*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
518 		break;
519 	case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */
520 		if (delta->old_file.mode == GIT_FILEMODE_TREE) {
521 			if (wd->mode == GIT_FILEMODE_TREE)
522 				/* either deleting items in old tree will delete the wd dir,
523 				 * or we'll get a conflict when we attempt blob update...
524 				 */
525 				*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
526 			else if (wd->mode == GIT_FILEMODE_COMMIT) {
527 				/* workdir is possibly a "phantom" submodule - treat as a
528 				 * tree if the only submodule info came from the config
529 				 */
530 				if (submodule_is_config_only(data, wd->path))
531 					*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
532 				else
533 					*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
534 			} else
535 				*action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
536 		}
537 		else if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
538 			*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
539 		else
540 			*action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
541 
542 		/* don't update if the typechange is to a tree */
543 		if (delta->new_file.mode == GIT_FILEMODE_TREE)
544 			*action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB);
545 		break;
546 	default: /* impossible */
547 		break;
548 	}
549 
550 	return checkout_action_common(action, data, delta, wd);
551 }
552 
checkout_action_with_wd_blocker(int * action,checkout_data * data,const git_diff_delta * delta,const git_index_entry * wd)553 static int checkout_action_with_wd_blocker(
554 	int *action,
555 	checkout_data *data,
556 	const git_diff_delta *delta,
557 	const git_index_entry *wd)
558 {
559 	*action = CHECKOUT_ACTION__NONE;
560 
561 	switch (delta->status) {
562 	case GIT_DELTA_UNMODIFIED:
563 		/* should show delta as dirty / deleted */
564 		GIT_ERROR_CHECK_ERROR(
565 			checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
566 		*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
567 		break;
568 	case GIT_DELTA_ADDED:
569 	case GIT_DELTA_MODIFIED:
570 		*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
571 		break;
572 	case GIT_DELTA_DELETED:
573 		*action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
574 		break;
575 	case GIT_DELTA_TYPECHANGE:
576 		/* not 100% certain about this... */
577 		*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
578 		break;
579 	default: /* impossible */
580 		break;
581 	}
582 
583 	return checkout_action_common(action, data, delta, wd);
584 }
585 
checkout_action_with_wd_dir(int * action,checkout_data * data,const git_diff_delta * delta,git_iterator * workdir,const git_index_entry * wd)586 static int checkout_action_with_wd_dir(
587 	int *action,
588 	checkout_data *data,
589 	const git_diff_delta *delta,
590 	git_iterator *workdir,
591 	const git_index_entry *wd)
592 {
593 	*action = CHECKOUT_ACTION__NONE;
594 
595 	switch (delta->status) {
596 	case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */
597 		GIT_ERROR_CHECK_ERROR(
598 			checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL));
599 		GIT_ERROR_CHECK_ERROR(
600 			checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
601 		*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
602 		break;
603 	case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
604 	case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
605 		if (delta->old_file.mode == GIT_FILEMODE_COMMIT)
606 			/* expected submodule (and maybe found one) */;
607 		else if (delta->new_file.mode != GIT_FILEMODE_TREE)
608 			*action = git_iterator_current_is_ignored(workdir) ?
609 				CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, REMOVE_AND_UPDATE) :
610 				CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
611 		break;
612 	case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */
613 		if (delta->old_file.mode != GIT_FILEMODE_TREE)
614 			GIT_ERROR_CHECK_ERROR(
615 				checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
616 		break;
617 	case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */
618 		if (delta->old_file.mode == GIT_FILEMODE_TREE) {
619 			/* For typechange from dir, remove dir and add blob, but it is
620 			 * not safe to remove dir if it contains modified files.
621 			 * However, safely removing child files will remove the parent
622 			 * directory if is it left empty, so we can defer removing the
623 			 * dir and it will succeed if no children are left.
624 			 */
625 			*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
626 		}
627 		else if (delta->new_file.mode != GIT_FILEMODE_TREE)
628 			/* For typechange to dir, dir is already created so no action */
629 			*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
630 		break;
631 	default: /* impossible */
632 		break;
633 	}
634 
635 	return checkout_action_common(action, data, delta, wd);
636 }
637 
checkout_action_with_wd_dir_empty(int * action,checkout_data * data,const git_diff_delta * delta)638 static int checkout_action_with_wd_dir_empty(
639 	int *action,
640 	checkout_data *data,
641 	const git_diff_delta *delta)
642 {
643 	int error = checkout_action_no_wd(action, data, delta);
644 
645 	/* We can always safely remove an empty directory. */
646 	if (error == 0 && *action != CHECKOUT_ACTION__NONE)
647 		*action |= CHECKOUT_ACTION__REMOVE;
648 
649 	return error;
650 }
651 
checkout_action(int * action,checkout_data * data,git_diff_delta * delta,git_iterator * workdir,const git_index_entry ** wditem,git_vector * pathspec)652 static int checkout_action(
653 	int *action,
654 	checkout_data *data,
655 	git_diff_delta *delta,
656 	git_iterator *workdir,
657 	const git_index_entry **wditem,
658 	git_vector *pathspec)
659 {
660 	int cmp = -1, error;
661 	int (*strcomp)(const char *, const char *) = data->diff->strcomp;
662 	int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp;
663 	int (*advance)(const git_index_entry **, git_iterator *) = NULL;
664 
665 	/* move workdir iterator to follow along with deltas */
666 
667 	while (1) {
668 		const git_index_entry *wd = *wditem;
669 
670 		if (!wd)
671 			return checkout_action_no_wd(action, data, delta);
672 
673 		cmp = strcomp(wd->path, delta->old_file.path);
674 
675 		/* 1. wd before delta ("a/a" before "a/b")
676 		 * 2. wd prefixes delta & should expand ("a/" before "a/b")
677 		 * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
678 		 * 4. wd equals delta ("a/b" and "a/b")
679 		 * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
680 		 * 6. wd after delta ("a/c" after "a/b")
681 		 */
682 
683 		if (cmp < 0) {
684 			cmp = pfxcomp(delta->old_file.path, wd->path);
685 
686 			if (cmp == 0) {
687 				if (wd->mode == GIT_FILEMODE_TREE) {
688 					/* case 2 - entry prefixed by workdir tree */
689 					error = git_iterator_advance_into(wditem, workdir);
690 					if (error < 0 && error != GIT_ITEROVER)
691 						goto done;
692 					continue;
693 				}
694 
695 				/* case 3 maybe - wd contains non-dir where dir expected */
696 				if (delta->old_file.path[strlen(wd->path)] == '/') {
697 					error = checkout_action_with_wd_blocker(
698 						action, data, delta, wd);
699 					advance = git_iterator_advance;
700 					goto done;
701 				}
702 			}
703 
704 			/* case 1 - handle wd item (if it matches pathspec) */
705 			error = checkout_action_wd_only(data, workdir, wditem, pathspec);
706 			if (error && error != GIT_ITEROVER)
707 				goto done;
708 			continue;
709 		}
710 
711 		if (cmp == 0) {
712 			/* case 4 */
713 			error = checkout_action_with_wd(action, data, delta, workdir, wd);
714 			advance = git_iterator_advance;
715 			goto done;
716 		}
717 
718 		cmp = pfxcomp(wd->path, delta->old_file.path);
719 
720 		if (cmp == 0) { /* case 5 */
721 			if (wd->path[strlen(delta->old_file.path)] != '/')
722 				return checkout_action_no_wd(action, data, delta);
723 
724 			if (delta->status == GIT_DELTA_TYPECHANGE) {
725 				if (delta->old_file.mode == GIT_FILEMODE_TREE) {
726 					error = checkout_action_with_wd(action, data, delta, workdir, wd);
727 					advance = git_iterator_advance_into;
728 					goto done;
729 				}
730 
731 				if (delta->new_file.mode == GIT_FILEMODE_TREE ||
732 					delta->new_file.mode == GIT_FILEMODE_COMMIT ||
733 					delta->old_file.mode == GIT_FILEMODE_COMMIT)
734 				{
735 					error = checkout_action_with_wd(action, data, delta, workdir, wd);
736 					advance = git_iterator_advance;
737 					goto done;
738 				}
739 			}
740 
741 			return checkout_is_empty_dir(data, wd->path) ?
742 				checkout_action_with_wd_dir_empty(action, data, delta) :
743 				checkout_action_with_wd_dir(action, data, delta, workdir, wd);
744 		}
745 
746 		/* case 6 - wd is after delta */
747 		return checkout_action_no_wd(action, data, delta);
748 	}
749 
750 done:
751 	if (!error && advance != NULL &&
752 		(error = advance(wditem, workdir)) < 0) {
753 		*wditem = NULL;
754 		if (error == GIT_ITEROVER)
755 			error = 0;
756 	}
757 
758 	return error;
759 }
760 
checkout_remaining_wd_items(checkout_data * data,git_iterator * workdir,const git_index_entry * wd,git_vector * spec)761 static int checkout_remaining_wd_items(
762 	checkout_data *data,
763 	git_iterator *workdir,
764 	const git_index_entry *wd,
765 	git_vector *spec)
766 {
767 	int error = 0;
768 
769 	while (wd && !error)
770 		error = checkout_action_wd_only(data, workdir, &wd, spec);
771 
772 	if (error == GIT_ITEROVER)
773 		error = 0;
774 
775 	return error;
776 }
777 
checkout_idxentry_cmp(const git_index_entry * a,const git_index_entry * b)778 GIT_INLINE(int) checkout_idxentry_cmp(
779 	const git_index_entry *a,
780 	const git_index_entry *b)
781 {
782 	if (!a && !b)
783 		return 0;
784 	else if (!a && b)
785 		return -1;
786 	else if(a && !b)
787 		return 1;
788 	else
789 		return strcmp(a->path, b->path);
790 }
791 
checkout_conflictdata_cmp(const void * a,const void * b)792 static int checkout_conflictdata_cmp(const void *a, const void *b)
793 {
794 	const checkout_conflictdata *ca = a;
795 	const checkout_conflictdata *cb = b;
796 	int diff;
797 
798 	if ((diff = checkout_idxentry_cmp(ca->ancestor, cb->ancestor)) == 0 &&
799 		(diff = checkout_idxentry_cmp(ca->ours, cb->theirs)) == 0)
800 		diff = checkout_idxentry_cmp(ca->theirs, cb->theirs);
801 
802 	return diff;
803 }
804 
checkout_conflictdata_empty(const git_vector * conflicts,size_t idx,void * payload)805 int checkout_conflictdata_empty(
806 	const git_vector *conflicts, size_t idx, void *payload)
807 {
808 	checkout_conflictdata *conflict;
809 
810 	GIT_UNUSED(payload);
811 
812 	if ((conflict = git_vector_get(conflicts, idx)) == NULL)
813 		return -1;
814 
815 	if (conflict->ancestor || conflict->ours || conflict->theirs)
816 		return 0;
817 
818 	git__free(conflict);
819 	return 1;
820 }
821 
conflict_pathspec_match(checkout_data * data,git_iterator * workdir,git_vector * pathspec,const git_index_entry * ancestor,const git_index_entry * ours,const git_index_entry * theirs)822 GIT_INLINE(bool) conflict_pathspec_match(
823 	checkout_data *data,
824 	git_iterator *workdir,
825 	git_vector *pathspec,
826 	const git_index_entry *ancestor,
827 	const git_index_entry *ours,
828 	const git_index_entry *theirs)
829 {
830 	/* if the pathspec matches ours *or* theirs, proceed */
831 	if (ours && git_pathspec__match(pathspec, ours->path,
832 		(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
833 		git_iterator_ignore_case(workdir), NULL, NULL))
834 		return true;
835 
836 	if (theirs && git_pathspec__match(pathspec, theirs->path,
837 		(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
838 		git_iterator_ignore_case(workdir), NULL, NULL))
839 		return true;
840 
841 	if (ancestor && git_pathspec__match(pathspec, ancestor->path,
842 		(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
843 		git_iterator_ignore_case(workdir), NULL, NULL))
844 		return true;
845 
846 	return false;
847 }
848 
checkout_conflict_detect_submodule(checkout_conflictdata * conflict)849 GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata *conflict)
850 {
851 	conflict->submodule = ((conflict->ancestor && S_ISGITLINK(conflict->ancestor->mode)) ||
852 		(conflict->ours && S_ISGITLINK(conflict->ours->mode)) ||
853 		(conflict->theirs && S_ISGITLINK(conflict->theirs->mode)));
854 	return 0;
855 }
856 
checkout_conflict_detect_binary(git_repository * repo,checkout_conflictdata * conflict)857 GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict)
858 {
859 	git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
860 	int error = 0;
861 
862 	if (conflict->submodule)
863 		return 0;
864 
865 	if (conflict->ancestor) {
866 		if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->id)) < 0)
867 			goto done;
868 
869 		conflict->binary = git_blob_is_binary(ancestor_blob);
870 	}
871 
872 	if (!conflict->binary && conflict->ours) {
873 		if ((error = git_blob_lookup(&our_blob, repo, &conflict->ours->id)) < 0)
874 			goto done;
875 
876 		conflict->binary = git_blob_is_binary(our_blob);
877 	}
878 
879 	if (!conflict->binary && conflict->theirs) {
880 		if ((error = git_blob_lookup(&their_blob, repo, &conflict->theirs->id)) < 0)
881 			goto done;
882 
883 		conflict->binary = git_blob_is_binary(their_blob);
884 	}
885 
886 done:
887 	git_blob_free(ancestor_blob);
888 	git_blob_free(our_blob);
889 	git_blob_free(their_blob);
890 
891 	return error;
892 }
893 
checkout_conflict_append_update(const git_index_entry * ancestor,const git_index_entry * ours,const git_index_entry * theirs,void * payload)894 static int checkout_conflict_append_update(
895 	const git_index_entry *ancestor,
896 	const git_index_entry *ours,
897 	const git_index_entry *theirs,
898 	void *payload)
899 {
900 	checkout_data *data = payload;
901 	checkout_conflictdata *conflict;
902 	int error;
903 
904 	conflict = git__calloc(1, sizeof(checkout_conflictdata));
905 	GIT_ERROR_CHECK_ALLOC(conflict);
906 
907 	conflict->ancestor = ancestor;
908 	conflict->ours = ours;
909 	conflict->theirs = theirs;
910 
911 	if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
912 		(error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
913 	{
914 		git__free(conflict);
915 		return error;
916 	}
917 
918 	if (git_vector_insert(&data->update_conflicts, conflict))
919 		return -1;
920 
921 	return 0;
922 }
923 
checkout_conflicts_foreach(checkout_data * data,git_index * index,git_iterator * workdir,git_vector * pathspec,int (* cb)(const git_index_entry *,const git_index_entry *,const git_index_entry *,void *),void * payload)924 static int checkout_conflicts_foreach(
925 	checkout_data *data,
926 	git_index *index,
927 	git_iterator *workdir,
928 	git_vector *pathspec,
929 	int (*cb)(const git_index_entry *, const git_index_entry *, const git_index_entry *, void *),
930 	void *payload)
931 {
932 	git_index_conflict_iterator *iterator = NULL;
933 	const git_index_entry *ancestor, *ours, *theirs;
934 	int error = 0;
935 
936 	if ((error = git_index_conflict_iterator_new(&iterator, index)) < 0)
937 		goto done;
938 
939 	/* Collect the conflicts */
940 	while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) {
941 		if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs))
942 			continue;
943 
944 		if ((error = cb(ancestor, ours, theirs, payload)) < 0)
945 			goto done;
946 	}
947 
948 	if (error == GIT_ITEROVER)
949 		error = 0;
950 
951 done:
952 	git_index_conflict_iterator_free(iterator);
953 
954 	return error;
955 }
956 
checkout_conflicts_load(checkout_data * data,git_iterator * workdir,git_vector * pathspec)957 static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
958 {
959 	git_index *index;
960 
961 	/* Only write conficts from sources that have them: indexes. */
962 	if ((index = git_iterator_index(data->target)) == NULL)
963 		return 0;
964 
965 	data->update_conflicts._cmp = checkout_conflictdata_cmp;
966 
967 	if (checkout_conflicts_foreach(data, index, workdir, pathspec, checkout_conflict_append_update, data) < 0)
968 		return -1;
969 
970 	/* Collect the REUC and NAME entries */
971 	data->update_reuc = &index->reuc;
972 	data->update_names = &index->names;
973 
974 	return 0;
975 }
976 
checkout_conflicts_cmp_entry(const char * path,const git_index_entry * entry)977 GIT_INLINE(int) checkout_conflicts_cmp_entry(
978 	const char *path,
979 	const git_index_entry *entry)
980 {
981 	return strcmp((const char *)path, entry->path);
982 }
983 
checkout_conflicts_cmp_ancestor(const void * p,const void * c)984 static int checkout_conflicts_cmp_ancestor(const void *p, const void *c)
985 {
986 	const char *path = p;
987 	const checkout_conflictdata *conflict = c;
988 
989 	if (!conflict->ancestor)
990 		return 1;
991 
992 	return checkout_conflicts_cmp_entry(path, conflict->ancestor);
993 }
994 
checkout_conflicts_search_ancestor(checkout_data * data,const char * path)995 static checkout_conflictdata *checkout_conflicts_search_ancestor(
996 	checkout_data *data,
997 	const char *path)
998 {
999 	size_t pos;
1000 
1001 	if (git_vector_bsearch2(&pos, &data->update_conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
1002 		return NULL;
1003 
1004 	return git_vector_get(&data->update_conflicts, pos);
1005 }
1006 
checkout_conflicts_search_branch(checkout_data * data,const char * path)1007 static checkout_conflictdata *checkout_conflicts_search_branch(
1008 	checkout_data *data,
1009 	const char *path)
1010 {
1011 	checkout_conflictdata *conflict;
1012 	size_t i;
1013 
1014 	git_vector_foreach(&data->update_conflicts, i, conflict) {
1015 		int cmp = -1;
1016 
1017 		if (conflict->ancestor)
1018 			break;
1019 
1020 		if (conflict->ours)
1021 			cmp = checkout_conflicts_cmp_entry(path, conflict->ours);
1022 		else if (conflict->theirs)
1023 			cmp = checkout_conflicts_cmp_entry(path, conflict->theirs);
1024 
1025 		if (cmp == 0)
1026 			return conflict;
1027 	}
1028 
1029 	return NULL;
1030 }
1031 
checkout_conflicts_load_byname_entry(checkout_conflictdata ** ancestor_out,checkout_conflictdata ** ours_out,checkout_conflictdata ** theirs_out,checkout_data * data,const git_index_name_entry * name_entry)1032 static int checkout_conflicts_load_byname_entry(
1033 	checkout_conflictdata **ancestor_out,
1034 	checkout_conflictdata **ours_out,
1035 	checkout_conflictdata **theirs_out,
1036 	checkout_data *data,
1037 	const git_index_name_entry *name_entry)
1038 {
1039 	checkout_conflictdata *ancestor, *ours = NULL, *theirs = NULL;
1040 	int error = 0;
1041 
1042 	*ancestor_out = NULL;
1043 	*ours_out = NULL;
1044 	*theirs_out = NULL;
1045 
1046 	if (!name_entry->ancestor) {
1047 		git_error_set(GIT_ERROR_INDEX, "a NAME entry exists without an ancestor");
1048 		error = -1;
1049 		goto done;
1050 	}
1051 
1052 	if (!name_entry->ours && !name_entry->theirs) {
1053 		git_error_set(GIT_ERROR_INDEX, "a NAME entry exists without an ours or theirs");
1054 		error = -1;
1055 		goto done;
1056 	}
1057 
1058 	if ((ancestor = checkout_conflicts_search_ancestor(data,
1059 		name_entry->ancestor)) == NULL) {
1060 		git_error_set(GIT_ERROR_INDEX,
1061 			"a NAME entry referenced ancestor entry '%s' which does not exist in the main index",
1062 			name_entry->ancestor);
1063 		error = -1;
1064 		goto done;
1065 	}
1066 
1067 	if (name_entry->ours) {
1068 		if (strcmp(name_entry->ancestor, name_entry->ours) == 0)
1069 			ours = ancestor;
1070 		else if ((ours = checkout_conflicts_search_branch(data, name_entry->ours)) == NULL ||
1071 			ours->ours == NULL) {
1072 			git_error_set(GIT_ERROR_INDEX,
1073 				"a NAME entry referenced our entry '%s' which does not exist in the main index",
1074 				name_entry->ours);
1075 			error = -1;
1076 			goto done;
1077 		}
1078 	}
1079 
1080 	if (name_entry->theirs) {
1081 		if (strcmp(name_entry->ancestor, name_entry->theirs) == 0)
1082 			theirs = ancestor;
1083 		else if (name_entry->ours && strcmp(name_entry->ours, name_entry->theirs) == 0)
1084 			theirs = ours;
1085 		else if ((theirs = checkout_conflicts_search_branch(data, name_entry->theirs)) == NULL ||
1086 			theirs->theirs == NULL) {
1087 			git_error_set(GIT_ERROR_INDEX,
1088 				"a NAME entry referenced their entry '%s' which does not exist in the main index",
1089 				name_entry->theirs);
1090 			error = -1;
1091 			goto done;
1092 		}
1093 	}
1094 
1095 	*ancestor_out = ancestor;
1096 	*ours_out = ours;
1097 	*theirs_out = theirs;
1098 
1099 done:
1100 	return error;
1101 }
1102 
checkout_conflicts_coalesce_renames(checkout_data * data)1103 static int checkout_conflicts_coalesce_renames(
1104 	checkout_data *data)
1105 {
1106 	git_index *index;
1107 	const git_index_name_entry *name_entry;
1108 	checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict;
1109 	size_t i, names;
1110 	int error = 0;
1111 
1112 	if ((index = git_iterator_index(data->target)) == NULL)
1113 		return 0;
1114 
1115 	/* Juggle entries based on renames */
1116 	names = git_index_name_entrycount(index);
1117 
1118 	for (i = 0; i < names; i++) {
1119 		name_entry = git_index_name_get_byindex(index, i);
1120 
1121 		if ((error = checkout_conflicts_load_byname_entry(
1122 			&ancestor_conflict, &our_conflict, &their_conflict,
1123 			data, name_entry)) < 0)
1124 			goto done;
1125 
1126 		if (our_conflict && our_conflict != ancestor_conflict) {
1127 			ancestor_conflict->ours = our_conflict->ours;
1128 			our_conflict->ours = NULL;
1129 
1130 			if (our_conflict->theirs)
1131 				our_conflict->name_collision = 1;
1132 
1133 			if (our_conflict->name_collision)
1134 				ancestor_conflict->name_collision = 1;
1135 		}
1136 
1137 		if (their_conflict && their_conflict != ancestor_conflict) {
1138 			ancestor_conflict->theirs = their_conflict->theirs;
1139 			their_conflict->theirs = NULL;
1140 
1141 			if (their_conflict->ours)
1142 				their_conflict->name_collision = 1;
1143 
1144 			if (their_conflict->name_collision)
1145 				ancestor_conflict->name_collision = 1;
1146 		}
1147 
1148 		if (our_conflict && our_conflict != ancestor_conflict &&
1149 			their_conflict && their_conflict != ancestor_conflict)
1150 			ancestor_conflict->one_to_two = 1;
1151 	}
1152 
1153 	git_vector_remove_matching(
1154 		&data->update_conflicts, checkout_conflictdata_empty, NULL);
1155 
1156 done:
1157 	return error;
1158 }
1159 
checkout_conflicts_mark_directoryfile(checkout_data * data)1160 static int checkout_conflicts_mark_directoryfile(
1161 	checkout_data *data)
1162 {
1163 	git_index *index;
1164 	checkout_conflictdata *conflict;
1165 	const git_index_entry *entry;
1166 	size_t i, j, len;
1167 	const char *path;
1168 	int prefixed, error = 0;
1169 
1170 	if ((index = git_iterator_index(data->target)) == NULL)
1171 		return 0;
1172 
1173 	len = git_index_entrycount(index);
1174 
1175 	/* Find d/f conflicts */
1176 	git_vector_foreach(&data->update_conflicts, i, conflict) {
1177 		if ((conflict->ours && conflict->theirs) ||
1178 			(!conflict->ours && !conflict->theirs))
1179 			continue;
1180 
1181 		path = conflict->ours ?
1182 			conflict->ours->path : conflict->theirs->path;
1183 
1184 		if ((error = git_index_find(&j, index, path)) < 0) {
1185 			if (error == GIT_ENOTFOUND)
1186 				git_error_set(GIT_ERROR_INDEX,
1187 					"index inconsistency, could not find entry for expected conflict '%s'", path);
1188 
1189 			goto done;
1190 		}
1191 
1192 		for (; j < len; j++) {
1193 			if ((entry = git_index_get_byindex(index, j)) == NULL) {
1194 				git_error_set(GIT_ERROR_INDEX,
1195 					"index inconsistency, truncated index while loading expected conflict '%s'", path);
1196 				error = -1;
1197 				goto done;
1198 			}
1199 
1200 			prefixed = git_path_equal_or_prefixed(path, entry->path, NULL);
1201 
1202 			if (prefixed == GIT_PATH_EQUAL)
1203 				continue;
1204 
1205 			if (prefixed == GIT_PATH_PREFIX)
1206 				conflict->directoryfile = 1;
1207 
1208 			break;
1209 		}
1210 	}
1211 
1212 done:
1213 	return error;
1214 }
1215 
checkout_get_update_conflicts(checkout_data * data,git_iterator * workdir,git_vector * pathspec)1216 static int checkout_get_update_conflicts(
1217 	checkout_data *data,
1218 	git_iterator *workdir,
1219 	git_vector *pathspec)
1220 {
1221 	int error = 0;
1222 
1223 	if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED)
1224 		return 0;
1225 
1226 	if ((error = checkout_conflicts_load(data, workdir, pathspec)) < 0 ||
1227 		(error = checkout_conflicts_coalesce_renames(data)) < 0 ||
1228 		(error = checkout_conflicts_mark_directoryfile(data)) < 0)
1229 		goto done;
1230 
1231 done:
1232 	return error;
1233 }
1234 
checkout_conflict_append_remove(const git_index_entry * ancestor,const git_index_entry * ours,const git_index_entry * theirs,void * payload)1235 static int checkout_conflict_append_remove(
1236 	const git_index_entry *ancestor,
1237 	const git_index_entry *ours,
1238 	const git_index_entry *theirs,
1239 	void *payload)
1240 {
1241 	checkout_data *data = payload;
1242 	const char *name;
1243 
1244 	assert(ancestor || ours || theirs);
1245 
1246 	if (ancestor)
1247 		name = git__strdup(ancestor->path);
1248 	else if (ours)
1249 		name = git__strdup(ours->path);
1250 	else if (theirs)
1251 		name = git__strdup(theirs->path);
1252 	else
1253 		abort();
1254 
1255 	GIT_ERROR_CHECK_ALLOC(name);
1256 
1257 	return git_vector_insert(&data->remove_conflicts, (char *)name);
1258 }
1259 
checkout_get_remove_conflicts(checkout_data * data,git_iterator * workdir,git_vector * pathspec)1260 static int checkout_get_remove_conflicts(
1261 	checkout_data *data,
1262 	git_iterator *workdir,
1263 	git_vector *pathspec)
1264 {
1265 	if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0)
1266 		return 0;
1267 
1268 	return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data);
1269 }
1270 
checkout_verify_paths(git_repository * repo,int action,git_diff_delta * delta)1271 static int checkout_verify_paths(
1272 	git_repository *repo,
1273 	int action,
1274 	git_diff_delta *delta)
1275 {
1276 	unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
1277 
1278 	if (action & CHECKOUT_ACTION__REMOVE) {
1279 		if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) {
1280 			git_error_set(GIT_ERROR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
1281 			return -1;
1282 		}
1283 	}
1284 
1285 	if (action & ~CHECKOUT_ACTION__REMOVE) {
1286 		if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) {
1287 			git_error_set(GIT_ERROR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
1288 			return -1;
1289 		}
1290 	}
1291 
1292 	return 0;
1293 }
1294 
checkout_get_actions(uint32_t ** actions_ptr,size_t ** counts_ptr,checkout_data * data,git_iterator * workdir)1295 static int checkout_get_actions(
1296 	uint32_t **actions_ptr,
1297 	size_t **counts_ptr,
1298 	checkout_data *data,
1299 	git_iterator *workdir)
1300 {
1301 	int error = 0, act;
1302 	const git_index_entry *wditem;
1303 	git_vector pathspec = GIT_VECTOR_INIT, *deltas;
1304 	git_pool pathpool;
1305 	git_diff_delta *delta;
1306 	size_t i, *counts = NULL;
1307 	uint32_t *actions = NULL;
1308 
1309 	git_pool_init(&pathpool, 1);
1310 
1311 	if (data->opts.paths.count > 0 &&
1312 		git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
1313 		return -1;
1314 
1315 	if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
1316 		error != GIT_ITEROVER)
1317 		goto fail;
1318 
1319 	deltas = &data->diff->deltas;
1320 
1321 	*counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t));
1322 	*actions_ptr = actions = git__calloc(
1323 		deltas->length ? deltas->length : 1, sizeof(uint32_t));
1324 	if (!counts || !actions) {
1325 		error = -1;
1326 		goto fail;
1327 	}
1328 
1329 	git_vector_foreach(deltas, i, delta) {
1330 		if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0)
1331 			error = checkout_verify_paths(data->repo, act, delta);
1332 
1333 		if (error != 0)
1334 			goto fail;
1335 
1336 		actions[i] = act;
1337 
1338 		if (act & CHECKOUT_ACTION__REMOVE)
1339 			counts[CHECKOUT_ACTION__REMOVE]++;
1340 		if (act & CHECKOUT_ACTION__UPDATE_BLOB)
1341 			counts[CHECKOUT_ACTION__UPDATE_BLOB]++;
1342 		if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE)
1343 			counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++;
1344 		if (act & CHECKOUT_ACTION__CONFLICT)
1345 			counts[CHECKOUT_ACTION__CONFLICT]++;
1346 	}
1347 
1348 	error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec);
1349 	if (error)
1350 		goto fail;
1351 
1352 	counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
1353 
1354 	if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
1355 		(data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
1356 	{
1357 		git_error_set(GIT_ERROR_CHECKOUT, "%"PRIuZ" %s checkout",
1358 			counts[CHECKOUT_ACTION__CONFLICT],
1359 			counts[CHECKOUT_ACTION__CONFLICT] == 1 ?
1360 			"conflict prevents" : "conflicts prevent");
1361 		error = GIT_ECONFLICT;
1362 		goto fail;
1363 	}
1364 
1365 
1366 	if ((error = checkout_get_remove_conflicts(data, workdir, &pathspec)) < 0 ||
1367 		(error = checkout_get_update_conflicts(data, workdir, &pathspec)) < 0)
1368 		goto fail;
1369 
1370 	counts[CHECKOUT_ACTION__REMOVE_CONFLICT] = git_vector_length(&data->remove_conflicts);
1371 	counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->update_conflicts);
1372 
1373 	git_pathspec__vfree(&pathspec);
1374 	git_pool_clear(&pathpool);
1375 
1376 	return 0;
1377 
1378 fail:
1379 	*counts_ptr = NULL;
1380 	git__free(counts);
1381 	*actions_ptr = NULL;
1382 	git__free(actions);
1383 
1384 	git_pathspec__vfree(&pathspec);
1385 	git_pool_clear(&pathpool);
1386 
1387 	return error;
1388 }
1389 
should_remove_existing(checkout_data * data)1390 static bool should_remove_existing(checkout_data *data)
1391 {
1392 	int ignorecase;
1393 
1394 	if (git_repository__configmap_lookup(&ignorecase, data->repo, GIT_CONFIGMAP_IGNORECASE) < 0) {
1395 		ignorecase = 0;
1396 	}
1397 
1398 	return (ignorecase &&
1399 		(data->strategy & GIT_CHECKOUT_DONT_REMOVE_EXISTING) == 0);
1400 }
1401 
1402 #define MKDIR_NORMAL \
1403 	GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR
1404 #define MKDIR_REMOVE_EXISTING \
1405 	MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
1406 
checkout_mkdir(checkout_data * data,const char * path,const char * base,mode_t mode,unsigned int flags)1407 static int checkout_mkdir(
1408 	checkout_data *data,
1409 	const char *path,
1410 	const char *base,
1411 	mode_t mode,
1412 	unsigned int flags)
1413 {
1414 	struct git_futils_mkdir_options mkdir_opts = {0};
1415 	int error;
1416 
1417 	mkdir_opts.dir_map = data->mkdir_map;
1418 	mkdir_opts.pool = &data->pool;
1419 
1420 	error = git_futils_mkdir_relative(
1421 		path, base, mode, flags, &mkdir_opts);
1422 
1423 	data->perfdata.mkdir_calls += mkdir_opts.perfdata.mkdir_calls;
1424 	data->perfdata.stat_calls += mkdir_opts.perfdata.stat_calls;
1425 	data->perfdata.chmod_calls += mkdir_opts.perfdata.chmod_calls;
1426 
1427 	return error;
1428 }
1429 
mkpath2file(checkout_data * data,const char * path,unsigned int mode)1430 static int mkpath2file(
1431 	checkout_data *data, const char *path, unsigned int mode)
1432 {
1433 	struct stat st;
1434 	bool remove_existing = should_remove_existing(data);
1435 	unsigned int flags =
1436 		(remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL) |
1437 		GIT_MKDIR_SKIP_LAST;
1438 	int error;
1439 
1440 	if ((error = checkout_mkdir(
1441 			data, path, data->opts.target_directory, mode, flags)) < 0)
1442 		return error;
1443 
1444 	if (remove_existing) {
1445 		data->perfdata.stat_calls++;
1446 
1447 		if (p_lstat(path, &st) == 0) {
1448 
1449 			/* Some file, symlink or folder already exists at this name.
1450 			 * We would have removed it in remove_the_old unless we're on
1451 			 * a case inensitive filesystem (or the user has asked us not
1452 			 * to).  Remove the similarly named file to write the new.
1453 			 */
1454 			error = git_futils_rmdir_r(path, NULL, GIT_RMDIR_REMOVE_FILES);
1455 		} else if (errno != ENOENT) {
1456 			git_error_set(GIT_ERROR_OS, "failed to stat '%s'", path);
1457 			return GIT_EEXISTS;
1458 		} else {
1459 			git_error_clear();
1460 		}
1461 	}
1462 
1463 	return error;
1464 }
1465 
1466 struct checkout_stream {
1467 	git_writestream base;
1468 	const char *path;
1469 	int fd;
1470 	int open;
1471 };
1472 
checkout_stream_write(git_writestream * s,const char * buffer,size_t len)1473 static int checkout_stream_write(
1474 	git_writestream *s, const char *buffer, size_t len)
1475 {
1476 	struct checkout_stream *stream = (struct checkout_stream *)s;
1477 	int ret;
1478 
1479 	if ((ret = p_write(stream->fd, buffer, len)) < 0)
1480 		git_error_set(GIT_ERROR_OS, "could not write to '%s'", stream->path);
1481 
1482 	return ret;
1483 }
1484 
checkout_stream_close(git_writestream * s)1485 static int checkout_stream_close(git_writestream *s)
1486 {
1487 	struct checkout_stream *stream = (struct checkout_stream *)s;
1488 	assert(stream && stream->open);
1489 
1490 	stream->open = 0;
1491 	return p_close(stream->fd);
1492 }
1493 
checkout_stream_free(git_writestream * s)1494 static void checkout_stream_free(git_writestream *s)
1495 {
1496 	GIT_UNUSED(s);
1497 }
1498 
blob_content_to_file(checkout_data * data,struct stat * st,git_blob * blob,const char * path,const char * hint_path,mode_t entry_filemode)1499 static int blob_content_to_file(
1500 	checkout_data *data,
1501 	struct stat *st,
1502 	git_blob *blob,
1503 	const char *path,
1504 	const char *hint_path,
1505 	mode_t entry_filemode)
1506 {
1507 	int flags = data->opts.file_open_flags;
1508 	mode_t file_mode = data->opts.file_mode ?
1509 		data->opts.file_mode : entry_filemode;
1510 	git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
1511 	struct checkout_stream writer;
1512 	mode_t mode;
1513 	git_filter_list *fl = NULL;
1514 	int fd;
1515 	int error = 0;
1516 
1517 	if (hint_path == NULL)
1518 		hint_path = path;
1519 
1520 	if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
1521 		return error;
1522 
1523 	if (flags <= 0)
1524 		flags = O_CREAT | O_TRUNC | O_WRONLY;
1525 	if (!(mode = file_mode))
1526 		mode = GIT_FILEMODE_BLOB;
1527 
1528 	if ((fd = p_open(path, flags, mode)) < 0) {
1529 		git_error_set(GIT_ERROR_OS, "could not open '%s' for writing", path);
1530 		return fd;
1531 	}
1532 
1533 	filter_opts.attr_session = &data->attr_session;
1534 	filter_opts.temp_buf = &data->tmp;
1535 
1536 	if (!data->opts.disable_filters &&
1537 		(error = git_filter_list__load_ext(
1538 			&fl, data->repo, blob, hint_path,
1539 			GIT_FILTER_TO_WORKTREE, &filter_opts))) {
1540 		p_close(fd);
1541 		return error;
1542 	}
1543 
1544 	/* setup the writer */
1545 	memset(&writer, 0, sizeof(struct checkout_stream));
1546 	writer.base.write = checkout_stream_write;
1547 	writer.base.close = checkout_stream_close;
1548 	writer.base.free = checkout_stream_free;
1549 	writer.path = path;
1550 	writer.fd = fd;
1551 	writer.open = 1;
1552 
1553 	error = git_filter_list_stream_blob(fl, blob, &writer.base);
1554 
1555 	assert(writer.open == 0);
1556 
1557 	git_filter_list_free(fl);
1558 
1559 	if (error < 0)
1560 		return error;
1561 
1562 	if (st) {
1563 		data->perfdata.stat_calls++;
1564 
1565 		if ((error = p_stat(path, st)) < 0) {
1566 			git_error_set(GIT_ERROR_OS, "failed to stat '%s'", path);
1567 			return error;
1568 		}
1569 
1570 		st->st_mode = entry_filemode;
1571 	}
1572 
1573 	return 0;
1574 }
1575 
blob_content_to_link(checkout_data * data,struct stat * st,git_blob * blob,const char * path)1576 static int blob_content_to_link(
1577 	checkout_data *data,
1578 	struct stat *st,
1579 	git_blob *blob,
1580 	const char *path)
1581 {
1582 	git_buf linktarget = GIT_BUF_INIT;
1583 	int error;
1584 
1585 	if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
1586 		return error;
1587 
1588 	if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
1589 		return error;
1590 
1591 	if (data->can_symlink) {
1592 		if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
1593 			git_error_set(GIT_ERROR_OS, "could not create symlink %s", path);
1594 	} else {
1595 		error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
1596 	}
1597 
1598 	if (!error) {
1599 		data->perfdata.stat_calls++;
1600 
1601 		if ((error = p_lstat(path, st)) < 0)
1602 			git_error_set(GIT_ERROR_CHECKOUT, "could not stat symlink %s", path);
1603 
1604 		st->st_mode = GIT_FILEMODE_LINK;
1605 	}
1606 
1607 	git_buf_dispose(&linktarget);
1608 
1609 	return error;
1610 }
1611 
checkout_update_index(checkout_data * data,const git_diff_file * file,struct stat * st)1612 static int checkout_update_index(
1613 	checkout_data *data,
1614 	const git_diff_file *file,
1615 	struct stat *st)
1616 {
1617 	git_index_entry entry;
1618 
1619 	if (!data->index)
1620 		return 0;
1621 
1622 	memset(&entry, 0, sizeof(entry));
1623 	entry.path = (char *)file->path; /* cast to prevent warning */
1624 	git_index_entry__init_from_stat(&entry, st, true);
1625 	git_oid_cpy(&entry.id, &file->id);
1626 
1627 	return git_index_add(data->index, &entry);
1628 }
1629 
checkout_submodule_update_index(checkout_data * data,const git_diff_file * file)1630 static int checkout_submodule_update_index(
1631 	checkout_data *data,
1632 	const git_diff_file *file)
1633 {
1634 	git_buf *fullpath;
1635 	struct stat st;
1636 
1637 	/* update the index unless prevented */
1638 	if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0)
1639 		return 0;
1640 
1641 	if (checkout_target_fullpath(&fullpath, data, file->path) < 0)
1642 		return -1;
1643 
1644 	data->perfdata.stat_calls++;
1645 	if (p_stat(fullpath->ptr, &st) < 0) {
1646 		git_error_set(
1647 			GIT_ERROR_CHECKOUT, "could not stat submodule %s\n", file->path);
1648 		return GIT_ENOTFOUND;
1649 	}
1650 
1651 	st.st_mode = GIT_FILEMODE_COMMIT;
1652 
1653 	return checkout_update_index(data, file, &st);
1654 }
1655 
checkout_submodule(checkout_data * data,const git_diff_file * file)1656 static int checkout_submodule(
1657 	checkout_data *data,
1658 	const git_diff_file *file)
1659 {
1660 	bool remove_existing = should_remove_existing(data);
1661 	int error = 0;
1662 
1663 	/* Until submodules are supported, UPDATE_ONLY means do nothing here */
1664 	if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
1665 		return 0;
1666 
1667 	if ((error = checkout_mkdir(
1668 			data,
1669 			file->path, data->opts.target_directory, data->opts.dir_mode,
1670 			remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL)) < 0)
1671 		return error;
1672 
1673 	if ((error = git_submodule_lookup(NULL, data->repo, file->path)) < 0) {
1674 		/* I've observed repos with submodules in the tree that do not
1675 		 * have a .gitmodules - core Git just makes an empty directory
1676 		 */
1677 		if (error == GIT_ENOTFOUND) {
1678 			git_error_clear();
1679 			return checkout_submodule_update_index(data, file);
1680 		}
1681 
1682 		return error;
1683 	}
1684 
1685 	/* TODO: Support checkout_strategy options.  Two circumstances:
1686 	 * 1 - submodule already checked out, but we need to move the HEAD
1687 	 *     to the new OID, or
1688 	 * 2 - submodule not checked out and we should recursively check it out
1689 	 *
1690 	 * Checkout will not execute a pull on the submodule, but a clone
1691 	 * command should probably be able to.  Do we need a submodule callback?
1692 	 */
1693 
1694 	return checkout_submodule_update_index(data, file);
1695 }
1696 
report_progress(checkout_data * data,const char * path)1697 static void report_progress(
1698 	checkout_data *data,
1699 	const char *path)
1700 {
1701 	if (data->opts.progress_cb)
1702 		data->opts.progress_cb(
1703 			path, data->completed_steps, data->total_steps,
1704 			data->opts.progress_payload);
1705 }
1706 
checkout_safe_for_update_only(checkout_data * data,const char * path,mode_t expected_mode)1707 static int checkout_safe_for_update_only(
1708 	checkout_data *data, const char *path, mode_t expected_mode)
1709 {
1710 	struct stat st;
1711 
1712 	data->perfdata.stat_calls++;
1713 
1714 	if (p_lstat(path, &st) < 0) {
1715 		/* if doesn't exist, then no error and no update */
1716 		if (errno == ENOENT || errno == ENOTDIR)
1717 			return 0;
1718 
1719 		/* otherwise, stat error and no update */
1720 		git_error_set(GIT_ERROR_OS, "failed to stat '%s'", path);
1721 		return -1;
1722 	}
1723 
1724 	/* only safe for update if this is the same type of file */
1725 	if ((st.st_mode & ~0777) == (expected_mode & ~0777))
1726 		return 1;
1727 
1728 	return 0;
1729 }
1730 
checkout_write_content(checkout_data * data,const git_oid * oid,const char * full_path,const char * hint_path,unsigned int mode,struct stat * st)1731 static int checkout_write_content(
1732 	checkout_data *data,
1733 	const git_oid *oid,
1734 	const char *full_path,
1735 	const char *hint_path,
1736 	unsigned int mode,
1737 	struct stat *st)
1738 {
1739 	int error = 0;
1740 	git_blob *blob;
1741 
1742 	if ((error = git_blob_lookup(&blob, data->repo, oid)) < 0)
1743 		return error;
1744 
1745 	if (S_ISLNK(mode))
1746 		error = blob_content_to_link(data, st, blob, full_path);
1747 	else
1748 		error = blob_content_to_file(data, st, blob, full_path, hint_path, mode);
1749 
1750 	git_blob_free(blob);
1751 
1752 	/* if we try to create the blob and an existing directory blocks it from
1753 	 * being written, then there must have been a typechange conflict in a
1754 	 * parent directory - suppress the error and try to continue.
1755 	 */
1756 	if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 &&
1757 		(error == GIT_ENOTFOUND || error == GIT_EEXISTS))
1758 	{
1759 		git_error_clear();
1760 		error = 0;
1761 	}
1762 
1763 	return error;
1764 }
1765 
checkout_blob(checkout_data * data,const git_diff_file * file)1766 static int checkout_blob(
1767 	checkout_data *data,
1768 	const git_diff_file *file)
1769 {
1770 	git_buf *fullpath;
1771 	struct stat st;
1772 	int error = 0;
1773 
1774 	if (checkout_target_fullpath(&fullpath, data, file->path) < 0)
1775 		return -1;
1776 
1777 	if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
1778 		int rval = checkout_safe_for_update_only(
1779 			data, fullpath->ptr, file->mode);
1780 
1781 		if (rval <= 0)
1782 			return rval;
1783 	}
1784 
1785 	error = checkout_write_content(
1786 		data, &file->id, fullpath->ptr, NULL, file->mode, &st);
1787 
1788 	/* update the index unless prevented */
1789 	if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
1790 		error = checkout_update_index(data, file, &st);
1791 
1792 	/* update the submodule data if this was a new .gitmodules file */
1793 	if (!error && strcmp(file->path, ".gitmodules") == 0)
1794 		data->reload_submodules = true;
1795 
1796 	return error;
1797 }
1798 
checkout_remove_the_old(unsigned int * actions,checkout_data * data)1799 static int checkout_remove_the_old(
1800 	unsigned int *actions,
1801 	checkout_data *data)
1802 {
1803 	int error = 0;
1804 	git_diff_delta *delta;
1805 	const char *str;
1806 	size_t i;
1807 	git_buf *fullpath;
1808 	uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
1809 		GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
1810 
1811 	if (data->opts.checkout_strategy & GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES)
1812 		flg |= GIT_RMDIR_SKIP_NONEMPTY;
1813 
1814 	if (checkout_target_fullpath(&fullpath, data, NULL) < 0)
1815 		return -1;
1816 
1817 	git_vector_foreach(&data->diff->deltas, i, delta) {
1818 		if (actions[i] & CHECKOUT_ACTION__REMOVE) {
1819 			error = git_futils_rmdir_r(
1820 				delta->old_file.path, fullpath->ptr, flg);
1821 
1822 			if (error < 0)
1823 				return error;
1824 
1825 			data->completed_steps++;
1826 			report_progress(data, delta->old_file.path);
1827 
1828 			if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 &&
1829 				(data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
1830 				data->index != NULL)
1831 			{
1832 				(void)git_index_remove(data->index, delta->old_file.path, 0);
1833 			}
1834 		}
1835 	}
1836 
1837 	git_vector_foreach(&data->removes, i, str) {
1838 		error = git_futils_rmdir_r(str, fullpath->ptr, flg);
1839 		if (error < 0)
1840 			return error;
1841 
1842 		data->completed_steps++;
1843 		report_progress(data, str);
1844 
1845 		if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
1846 			data->index != NULL)
1847 		{
1848 			if (str[strlen(str) - 1] == '/')
1849 				(void)git_index_remove_directory(data->index, str, 0);
1850 			else
1851 				(void)git_index_remove(data->index, str, 0);
1852 		}
1853 	}
1854 
1855 	return 0;
1856 }
1857 
checkout_deferred_remove(git_repository * repo,const char * path)1858 static int checkout_deferred_remove(git_repository *repo, const char *path)
1859 {
1860 #if 0
1861 	int error = git_futils_rmdir_r(
1862 		path, data->opts.target_directory, GIT_RMDIR_EMPTY_PARENTS);
1863 
1864 	if (error == GIT_ENOTFOUND) {
1865 		error = 0;
1866 		git_error_clear();
1867 	}
1868 
1869 	return error;
1870 #else
1871 	GIT_UNUSED(repo);
1872 	GIT_UNUSED(path);
1873 	assert(false);
1874 	return 0;
1875 #endif
1876 }
1877 
checkout_create_the_new(unsigned int * actions,checkout_data * data)1878 static int checkout_create_the_new(
1879 	unsigned int *actions,
1880 	checkout_data *data)
1881 {
1882 	int error = 0;
1883 	git_diff_delta *delta;
1884 	size_t i;
1885 
1886 	git_vector_foreach(&data->diff->deltas, i, delta) {
1887 		if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1888 			/* this had a blocker directory that should only be removed iff
1889 			 * all of the contents of the directory were safely removed
1890 			 */
1891 			if ((error = checkout_deferred_remove(
1892 					data->repo, delta->old_file.path)) < 0)
1893 				return error;
1894 		}
1895 
1896 		if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB && !S_ISLNK(delta->new_file.mode)) {
1897 			if ((error = checkout_blob(data, &delta->new_file)) < 0)
1898 				return error;
1899 			data->completed_steps++;
1900 			report_progress(data, delta->new_file.path);
1901 		}
1902 	}
1903 
1904 	git_vector_foreach(&data->diff->deltas, i, delta) {
1905 		if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB && S_ISLNK(delta->new_file.mode)) {
1906 			if ((error = checkout_blob(data, &delta->new_file)) < 0)
1907 				return error;
1908 			data->completed_steps++;
1909 			report_progress(data, delta->new_file.path);
1910 		}
1911 	}
1912 
1913 	return 0;
1914 }
1915 
checkout_create_submodules(unsigned int * actions,checkout_data * data)1916 static int checkout_create_submodules(
1917 	unsigned int *actions,
1918 	checkout_data *data)
1919 {
1920 	int error = 0;
1921 	git_diff_delta *delta;
1922 	size_t i;
1923 
1924 	git_vector_foreach(&data->diff->deltas, i, delta) {
1925 		if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1926 			/* this has a blocker directory that should only be removed iff
1927 			 * all of the contents of the directory were safely removed
1928 			 */
1929 			if ((error = checkout_deferred_remove(
1930 					data->repo, delta->old_file.path)) < 0)
1931 				return error;
1932 		}
1933 
1934 		if (actions[i] & CHECKOUT_ACTION__UPDATE_SUBMODULE) {
1935 			int error = checkout_submodule(data, &delta->new_file);
1936 			if (error < 0)
1937 				return error;
1938 
1939 			data->completed_steps++;
1940 			report_progress(data, delta->new_file.path);
1941 		}
1942 	}
1943 
1944 	return 0;
1945 }
1946 
checkout_lookup_head_tree(git_tree ** out,git_repository * repo)1947 static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
1948 {
1949 	int error = 0;
1950 	git_reference *ref = NULL;
1951 	git_object *head;
1952 
1953 	if (!(error = git_repository_head(&ref, repo)) &&
1954 		!(error = git_reference_peel(&head, ref, GIT_OBJECT_TREE)))
1955 		*out = (git_tree *)head;
1956 
1957 	git_reference_free(ref);
1958 
1959 	return error;
1960 }
1961 
1962 
conflict_entry_name(git_buf * out,const char * side_name,const char * filename)1963 static int conflict_entry_name(
1964 	git_buf *out,
1965 	const char *side_name,
1966 	const char *filename)
1967 {
1968 	if (git_buf_puts(out, side_name) < 0 ||
1969 		git_buf_putc(out, ':') < 0 ||
1970 		git_buf_puts(out, filename) < 0)
1971 		return -1;
1972 
1973 	return 0;
1974 }
1975 
checkout_path_suffixed(git_buf * path,const char * suffix)1976 static int checkout_path_suffixed(git_buf *path, const char *suffix)
1977 {
1978 	size_t path_len;
1979 	int i = 0, error = 0;
1980 
1981 	if ((error = git_buf_putc(path, '~')) < 0 || (error = git_buf_puts(path, suffix)) < 0)
1982 		return -1;
1983 
1984 	path_len = git_buf_len(path);
1985 
1986 	while (git_path_exists(git_buf_cstr(path)) && i < INT_MAX) {
1987 		git_buf_truncate(path, path_len);
1988 
1989 		if ((error = git_buf_putc(path, '_')) < 0 ||
1990 			(error = git_buf_printf(path, "%d", i)) < 0)
1991 			return error;
1992 
1993 		i++;
1994 	}
1995 
1996 	if (i == INT_MAX) {
1997 		git_buf_truncate(path, path_len);
1998 
1999 		git_error_set(GIT_ERROR_CHECKOUT, "could not write '%s': working directory file exists", path->ptr);
2000 		return GIT_EEXISTS;
2001 	}
2002 
2003 	return 0;
2004 }
2005 
checkout_write_entry(checkout_data * data,checkout_conflictdata * conflict,const git_index_entry * side)2006 static int checkout_write_entry(
2007 	checkout_data *data,
2008 	checkout_conflictdata *conflict,
2009 	const git_index_entry *side)
2010 {
2011 	const char *hint_path = NULL, *suffix;
2012 	git_buf *fullpath;
2013 	struct stat st;
2014 	int error;
2015 
2016 	assert (side == conflict->ours || side == conflict->theirs);
2017 
2018 	if (checkout_target_fullpath(&fullpath, data, side->path) < 0)
2019 		return -1;
2020 
2021 	if ((conflict->name_collision || conflict->directoryfile) &&
2022 		(data->strategy & GIT_CHECKOUT_USE_OURS) == 0 &&
2023 		(data->strategy & GIT_CHECKOUT_USE_THEIRS) == 0) {
2024 
2025 		if (side == conflict->ours)
2026 			suffix = data->opts.our_label ? data->opts.our_label :
2027 				"ours";
2028 		else
2029 			suffix = data->opts.their_label ? data->opts.their_label :
2030 				"theirs";
2031 
2032 		if (checkout_path_suffixed(fullpath, suffix) < 0)
2033 			return -1;
2034 
2035 		hint_path = side->path;
2036 	}
2037 
2038 	if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
2039 		(error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0)
2040 		return error;
2041 
2042 	if (!S_ISGITLINK(side->mode))
2043 		return checkout_write_content(data,
2044 					      &side->id, fullpath->ptr, hint_path, side->mode, &st);
2045 
2046 	return 0;
2047 }
2048 
checkout_write_entries(checkout_data * data,checkout_conflictdata * conflict)2049 static int checkout_write_entries(
2050 	checkout_data *data,
2051 	checkout_conflictdata *conflict)
2052 {
2053 	int error = 0;
2054 
2055 	if ((error = checkout_write_entry(data, conflict, conflict->ours)) >= 0)
2056 		error = checkout_write_entry(data, conflict, conflict->theirs);
2057 
2058 	return error;
2059 }
2060 
checkout_merge_path(git_buf * out,checkout_data * data,checkout_conflictdata * conflict,git_merge_file_result * result)2061 static int checkout_merge_path(
2062 	git_buf *out,
2063 	checkout_data *data,
2064 	checkout_conflictdata *conflict,
2065 	git_merge_file_result *result)
2066 {
2067 	const char *our_label_raw, *their_label_raw, *suffix;
2068 	int error = 0;
2069 
2070 	if ((error = git_buf_joinpath(out, git_repository_workdir(data->repo), result->path)) < 0)
2071 		return error;
2072 
2073 	/* Most conflicts simply use the filename in the index */
2074 	if (!conflict->name_collision)
2075 		return 0;
2076 
2077 	/* Rename 2->1 conflicts need the branch name appended */
2078 	our_label_raw = data->opts.our_label ? data->opts.our_label : "ours";
2079 	their_label_raw = data->opts.their_label ? data->opts.their_label : "theirs";
2080 	suffix = strcmp(result->path, conflict->ours->path) == 0 ? our_label_raw : their_label_raw;
2081 
2082 	if ((error = checkout_path_suffixed(out, suffix)) < 0)
2083 		return error;
2084 
2085 	return 0;
2086 }
2087 
checkout_write_merge(checkout_data * data,checkout_conflictdata * conflict)2088 static int checkout_write_merge(
2089 	checkout_data *data,
2090 	checkout_conflictdata *conflict)
2091 {
2092 	git_buf our_label = GIT_BUF_INIT, their_label = GIT_BUF_INIT,
2093 		path_suffixed = GIT_BUF_INIT, path_workdir = GIT_BUF_INIT,
2094 		in_data = GIT_BUF_INIT, out_data = GIT_BUF_INIT;
2095 	git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
2096 	git_merge_file_result result = {0};
2097 	git_filebuf output = GIT_FILEBUF_INIT;
2098 	git_filter_list *fl = NULL;
2099 	git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
2100 	int error = 0;
2101 
2102 	if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
2103 		opts.flags |= GIT_MERGE_FILE_STYLE_DIFF3;
2104 
2105 	opts.ancestor_label = data->opts.ancestor_label ?
2106 		data->opts.ancestor_label : "ancestor";
2107 	opts.our_label = data->opts.our_label ?
2108 		data->opts.our_label : "ours";
2109 	opts.their_label = data->opts.their_label ?
2110 		data->opts.their_label : "theirs";
2111 
2112 	/* If all the paths are identical, decorate the diff3 file with the branch
2113 	 * names.  Otherwise, append branch_name:path.
2114 	 */
2115 	if (conflict->ours && conflict->theirs &&
2116 		strcmp(conflict->ours->path, conflict->theirs->path) != 0) {
2117 
2118 		if ((error = conflict_entry_name(
2119 			&our_label, opts.our_label, conflict->ours->path)) < 0 ||
2120 			(error = conflict_entry_name(
2121 			&their_label, opts.their_label, conflict->theirs->path)) < 0)
2122 			goto done;
2123 
2124 		opts.our_label = git_buf_cstr(&our_label);
2125 		opts.their_label = git_buf_cstr(&their_label);
2126 	}
2127 
2128 	if ((error = git_merge_file_from_index(&result, data->repo,
2129 		conflict->ancestor, conflict->ours, conflict->theirs, &opts)) < 0)
2130 		goto done;
2131 
2132 	if (result.path == NULL || result.mode == 0) {
2133 		git_error_set(GIT_ERROR_CHECKOUT, "could not merge contents of file");
2134 		error = GIT_ECONFLICT;
2135 		goto done;
2136 	}
2137 
2138 	if ((error = checkout_merge_path(&path_workdir, data, conflict, &result)) < 0)
2139 		goto done;
2140 
2141 	if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
2142 		(error = checkout_safe_for_update_only(data, git_buf_cstr(&path_workdir), result.mode)) <= 0)
2143 		goto done;
2144 
2145 	if (!data->opts.disable_filters) {
2146 		in_data.ptr = (char *)result.ptr;
2147 		in_data.size = result.len;
2148 
2149 		filter_opts.attr_session = &data->attr_session;
2150 		filter_opts.temp_buf = &data->tmp;
2151 
2152 		if ((error = git_filter_list__load_ext(
2153 				&fl, data->repo, NULL, git_buf_cstr(&path_workdir),
2154 				GIT_FILTER_TO_WORKTREE, &filter_opts)) < 0 ||
2155 			(error = git_filter_list_apply_to_data(&out_data, fl, &in_data)) < 0)
2156 			goto done;
2157 	} else {
2158 		out_data.ptr = (char *)result.ptr;
2159 		out_data.size = result.len;
2160 	}
2161 
2162 	if ((error = mkpath2file(data, path_workdir.ptr, data->opts.dir_mode)) < 0 ||
2163 		(error = git_filebuf_open(&output, git_buf_cstr(&path_workdir), GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
2164 		(error = git_filebuf_write(&output, out_data.ptr, out_data.size)) < 0 ||
2165 		(error = git_filebuf_commit(&output)) < 0)
2166 		goto done;
2167 
2168 done:
2169 	git_filter_list_free(fl);
2170 
2171 	git_buf_dispose(&out_data);
2172 	git_buf_dispose(&our_label);
2173 	git_buf_dispose(&their_label);
2174 
2175 	git_merge_file_result_free(&result);
2176 	git_buf_dispose(&path_workdir);
2177 	git_buf_dispose(&path_suffixed);
2178 
2179 	return error;
2180 }
2181 
checkout_conflict_add(checkout_data * data,const git_index_entry * conflict)2182 static int checkout_conflict_add(
2183 	checkout_data *data,
2184 	const git_index_entry *conflict)
2185 {
2186 	int error = git_index_remove(data->index, conflict->path, 0);
2187 
2188 	if (error == GIT_ENOTFOUND)
2189 		git_error_clear();
2190 	else if (error < 0)
2191 		return error;
2192 
2193 	return git_index_add(data->index, conflict);
2194 }
2195 
checkout_conflict_update_index(checkout_data * data,checkout_conflictdata * conflict)2196 static int checkout_conflict_update_index(
2197 	checkout_data *data,
2198 	checkout_conflictdata *conflict)
2199 {
2200 	int error = 0;
2201 
2202 	if (conflict->ancestor)
2203 		error = checkout_conflict_add(data, conflict->ancestor);
2204 
2205 	if (!error && conflict->ours)
2206 		error = checkout_conflict_add(data, conflict->ours);
2207 
2208 	if (!error && conflict->theirs)
2209 		error = checkout_conflict_add(data, conflict->theirs);
2210 
2211 	return error;
2212 }
2213 
checkout_create_conflicts(checkout_data * data)2214 static int checkout_create_conflicts(checkout_data *data)
2215 {
2216 	checkout_conflictdata *conflict;
2217 	size_t i;
2218 	int error = 0;
2219 
2220 	git_vector_foreach(&data->update_conflicts, i, conflict) {
2221 
2222 		/* Both deleted: nothing to do */
2223 		if (conflict->ours == NULL && conflict->theirs == NULL)
2224 			error = 0;
2225 
2226 		else if ((data->strategy & GIT_CHECKOUT_USE_OURS) &&
2227 			conflict->ours)
2228 			error = checkout_write_entry(data, conflict, conflict->ours);
2229 		else if ((data->strategy & GIT_CHECKOUT_USE_THEIRS) &&
2230 			conflict->theirs)
2231 			error = checkout_write_entry(data, conflict, conflict->theirs);
2232 
2233 		/* Ignore the other side of name collisions. */
2234 		else if ((data->strategy & GIT_CHECKOUT_USE_OURS) &&
2235 			!conflict->ours && conflict->name_collision)
2236 			error = 0;
2237 		else if ((data->strategy & GIT_CHECKOUT_USE_THEIRS) &&
2238 			!conflict->theirs && conflict->name_collision)
2239 			error = 0;
2240 
2241 		/* For modify/delete, name collisions and d/f conflicts, write
2242 		 * the file (potentially with the name mangled.
2243 		 */
2244 		else if (conflict->ours != NULL && conflict->theirs == NULL)
2245 			error = checkout_write_entry(data, conflict, conflict->ours);
2246 		else if (conflict->ours == NULL && conflict->theirs != NULL)
2247 			error = checkout_write_entry(data, conflict, conflict->theirs);
2248 
2249 		/* Add/add conflicts and rename 1->2 conflicts, write the
2250 		 * ours/theirs sides (potentially name mangled).
2251 		 */
2252 		else if (conflict->one_to_two)
2253 			error = checkout_write_entries(data, conflict);
2254 
2255 		/* If all sides are links, write the ours side */
2256 		else if (S_ISLNK(conflict->ours->mode) &&
2257 			S_ISLNK(conflict->theirs->mode))
2258 			error = checkout_write_entry(data, conflict, conflict->ours);
2259 		/* Link/file conflicts, write the file side */
2260 		else if (S_ISLNK(conflict->ours->mode))
2261 			error = checkout_write_entry(data, conflict, conflict->theirs);
2262 		else if (S_ISLNK(conflict->theirs->mode))
2263 			error = checkout_write_entry(data, conflict, conflict->ours);
2264 
2265 		/* If any side is a gitlink, do nothing. */
2266 		else if (conflict->submodule)
2267 			error = 0;
2268 
2269 		/* If any side is binary, write the ours side */
2270 		else if (conflict->binary)
2271 			error = checkout_write_entry(data, conflict, conflict->ours);
2272 
2273 		else if (!error)
2274 			error = checkout_write_merge(data, conflict);
2275 
2276 		/* Update the index extensions (REUC and NAME) if we're checking
2277 		 * out a different index. (Otherwise just leave them there.)
2278 		 */
2279 		if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
2280 			error = checkout_conflict_update_index(data, conflict);
2281 
2282 		if (error)
2283 			break;
2284 
2285 		data->completed_steps++;
2286 		report_progress(data,
2287 			conflict->ours ? conflict->ours->path :
2288 			(conflict->theirs ? conflict->theirs->path : conflict->ancestor->path));
2289 	}
2290 
2291 	return error;
2292 }
2293 
checkout_remove_conflicts(checkout_data * data)2294 static int checkout_remove_conflicts(checkout_data *data)
2295 {
2296 	const char *conflict;
2297 	size_t i;
2298 
2299 	git_vector_foreach(&data->remove_conflicts, i, conflict) {
2300 		if (git_index_conflict_remove(data->index, conflict) < 0)
2301 			return -1;
2302 
2303 		data->completed_steps++;
2304 	}
2305 
2306 	return 0;
2307 }
2308 
checkout_extensions_update_index(checkout_data * data)2309 static int checkout_extensions_update_index(checkout_data *data)
2310 {
2311 	const git_index_reuc_entry *reuc_entry;
2312 	const git_index_name_entry *name_entry;
2313 	size_t i;
2314 	int error = 0;
2315 
2316 	if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
2317 		return 0;
2318 
2319 	if (data->update_reuc) {
2320 		git_vector_foreach(data->update_reuc, i, reuc_entry) {
2321 			if ((error = git_index_reuc_add(data->index, reuc_entry->path,
2322 				reuc_entry->mode[0], &reuc_entry->oid[0],
2323 				reuc_entry->mode[1], &reuc_entry->oid[1],
2324 				reuc_entry->mode[2], &reuc_entry->oid[2])) < 0)
2325 				goto done;
2326 		}
2327 	}
2328 
2329 	if (data->update_names) {
2330 		git_vector_foreach(data->update_names, i, name_entry) {
2331 			if ((error = git_index_name_add(data->index, name_entry->ancestor,
2332 				name_entry->ours, name_entry->theirs)) < 0)
2333 				goto done;
2334 		}
2335 	}
2336 
2337 done:
2338 	return error;
2339 }
2340 
checkout_data_clear(checkout_data * data)2341 static void checkout_data_clear(checkout_data *data)
2342 {
2343 	if (data->opts_free_baseline) {
2344 		git_tree_free(data->opts.baseline);
2345 		data->opts.baseline = NULL;
2346 	}
2347 
2348 	git_vector_free(&data->removes);
2349 	git_pool_clear(&data->pool);
2350 
2351 	git_vector_free_deep(&data->remove_conflicts);
2352 	git_vector_free_deep(&data->update_conflicts);
2353 
2354 	git__free(data->pfx);
2355 	data->pfx = NULL;
2356 
2357 	git_buf_dispose(&data->target_path);
2358 	git_buf_dispose(&data->tmp);
2359 
2360 	git_index_free(data->index);
2361 	data->index = NULL;
2362 
2363 	git_strmap_free(data->mkdir_map);
2364 	data->mkdir_map = NULL;
2365 
2366 	git_attr_session__free(&data->attr_session);
2367 }
2368 
checkout_data_init(checkout_data * data,git_iterator * target,const git_checkout_options * proposed)2369 static int checkout_data_init(
2370 	checkout_data *data,
2371 	git_iterator *target,
2372 	const git_checkout_options *proposed)
2373 {
2374 	int error = 0;
2375 	git_repository *repo = git_iterator_owner(target);
2376 
2377 	memset(data, 0, sizeof(*data));
2378 
2379 	if (!repo) {
2380 		git_error_set(GIT_ERROR_CHECKOUT, "cannot checkout nothing");
2381 		return -1;
2382 	}
2383 
2384 	if ((!proposed || !proposed->target_directory) &&
2385 		(error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
2386 		return error;
2387 
2388 	data->repo = repo;
2389 	data->target = target;
2390 
2391 	GIT_ERROR_CHECK_VERSION(
2392 		proposed, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options");
2393 
2394 	if (!proposed)
2395 		GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTIONS_VERSION);
2396 	else
2397 		memmove(&data->opts, proposed, sizeof(git_checkout_options));
2398 
2399 	if (!data->opts.target_directory)
2400 		data->opts.target_directory = git_repository_workdir(repo);
2401 	else if (!git_path_isdir(data->opts.target_directory) &&
2402 			 (error = checkout_mkdir(data,
2403 				data->opts.target_directory, NULL,
2404 				GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
2405 		goto cleanup;
2406 
2407 	if ((error = git_repository_index(&data->index, data->repo)) < 0)
2408 		goto cleanup;
2409 
2410 	/* refresh config and index content unless NO_REFRESH is given */
2411 	if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
2412 		git_config *cfg;
2413 
2414 		if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
2415 			goto cleanup;
2416 
2417 		/* Reload the repository index (unless we're checking out the
2418 		 * index; then it has the changes we're trying to check out
2419 		 * and those should not be overwritten.)
2420 		 */
2421 		if (data->index != git_iterator_index(target)) {
2422 			if (data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) {
2423 				/* When forcing, we can blindly re-read the index */
2424 				if ((error = git_index_read(data->index, false)) < 0)
2425 					goto cleanup;
2426 			} else {
2427 				/*
2428 				 * When not being forced, we need to check for unresolved
2429 				 * conflicts and unsaved changes in the index before
2430 				 * proceeding.
2431 				 */
2432 				if (git_index_has_conflicts(data->index)) {
2433 					error = GIT_ECONFLICT;
2434 					git_error_set(GIT_ERROR_CHECKOUT,
2435 						"unresolved conflicts exist in the index");
2436 					goto cleanup;
2437 				}
2438 
2439 				if ((error = git_index_read_safely(data->index)) < 0)
2440 					goto cleanup;
2441 			}
2442 
2443 			/* clean conflict data in the current index */
2444 			git_index_name_clear(data->index);
2445 			git_index_reuc_clear(data->index);
2446 		}
2447 	}
2448 
2449 	/* if you are forcing, allow all safe updates, plus recreate missing */
2450 	if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0)
2451 		data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE |
2452 			GIT_CHECKOUT_RECREATE_MISSING;
2453 
2454 	/* if the repository does not actually have an index file, then this
2455 	 * is an initial checkout (perhaps from clone), so we allow safe updates
2456 	 */
2457 	if (!data->index->on_disk &&
2458 		(data->opts.checkout_strategy & GIT_CHECKOUT_SAFE) != 0)
2459 		data->opts.checkout_strategy |= GIT_CHECKOUT_RECREATE_MISSING;
2460 
2461 	data->strategy = data->opts.checkout_strategy;
2462 
2463 	/* opts->disable_filters is false by default */
2464 
2465 	if (!data->opts.dir_mode)
2466 		data->opts.dir_mode = GIT_DIR_MODE;
2467 
2468 	if (!data->opts.file_open_flags)
2469 		data->opts.file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
2470 
2471 	data->pfx = git_pathspec_prefix(&data->opts.paths);
2472 
2473 	if ((error = git_repository__configmap_lookup(
2474 			 &data->can_symlink, repo, GIT_CONFIGMAP_SYMLINKS)) < 0)
2475 		goto cleanup;
2476 
2477 	if ((error = git_repository__configmap_lookup(
2478 			 &data->respect_filemode, repo, GIT_CONFIGMAP_FILEMODE)) < 0)
2479 		goto cleanup;
2480 
2481 	if (!data->opts.baseline && !data->opts.baseline_index) {
2482 		data->opts_free_baseline = true;
2483 		error = 0;
2484 
2485 		/* if we don't have an index, this is an initial checkout and
2486 		 * should be against an empty baseline
2487 		 */
2488 		if (data->index->on_disk)
2489 			error = checkout_lookup_head_tree(&data->opts.baseline, repo);
2490 
2491 		if (error == GIT_EUNBORNBRANCH) {
2492 			error = 0;
2493 			git_error_clear();
2494 		}
2495 
2496 		if (error < 0)
2497 			goto cleanup;
2498 	}
2499 
2500 	if ((data->opts.checkout_strategy &
2501 		(GIT_CHECKOUT_CONFLICT_STYLE_MERGE | GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)) == 0) {
2502 		git_config_entry *conflict_style = NULL;
2503 		git_config *cfg = NULL;
2504 
2505 		if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
2506 			(error = git_config_get_entry(&conflict_style, cfg, "merge.conflictstyle")) < 0 ||
2507 			error == GIT_ENOTFOUND)
2508 			;
2509 		else if (error)
2510 			goto cleanup;
2511 		else if (strcmp(conflict_style->value, "merge") == 0)
2512 			data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_MERGE;
2513 		else if (strcmp(conflict_style->value, "diff3") == 0)
2514 			data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
2515 		else {
2516 			git_error_set(GIT_ERROR_CHECKOUT, "unknown style '%s' given for 'merge.conflictstyle'",
2517 				conflict_style->value);
2518 			error = -1;
2519 			git_config_entry_free(conflict_style);
2520 			goto cleanup;
2521 		}
2522 		git_config_entry_free(conflict_style);
2523 	}
2524 
2525 	git_pool_init(&data->pool, 1);
2526 
2527 	if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
2528 	    (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 ||
2529 	    (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
2530 	    (error = git_buf_puts(&data->target_path, data->opts.target_directory)) < 0 ||
2531 	    (error = git_path_to_dir(&data->target_path)) < 0 ||
2532 	    (error = git_strmap_new(&data->mkdir_map)) < 0)
2533 		goto cleanup;
2534 
2535 	data->target_len = git_buf_len(&data->target_path);
2536 
2537 	git_attr_session__init(&data->attr_session, data->repo);
2538 
2539 cleanup:
2540 	if (error < 0)
2541 		checkout_data_clear(data);
2542 
2543 	return error;
2544 }
2545 
2546 #define CHECKOUT_INDEX_DONT_WRITE_MASK \
2547 	(GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
2548 
git_checkout_iterator(git_iterator * target,git_index * index,const git_checkout_options * opts)2549 int git_checkout_iterator(
2550 	git_iterator *target,
2551 	git_index *index,
2552 	const git_checkout_options *opts)
2553 {
2554 	int error = 0;
2555 	git_iterator *baseline = NULL, *workdir = NULL;
2556 	git_iterator_options baseline_opts = GIT_ITERATOR_OPTIONS_INIT,
2557 		workdir_opts = GIT_ITERATOR_OPTIONS_INIT;
2558 	checkout_data data = {0};
2559 	git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
2560 	uint32_t *actions = NULL;
2561 	size_t *counts = NULL;
2562 
2563 	/* initialize structures and options */
2564 	error = checkout_data_init(&data, target, opts);
2565 	if (error < 0)
2566 		return error;
2567 
2568 	diff_opts.flags =
2569 		GIT_DIFF_INCLUDE_UNMODIFIED |
2570 		GIT_DIFF_INCLUDE_UNREADABLE |
2571 		GIT_DIFF_INCLUDE_UNTRACKED |
2572 		GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
2573 		GIT_DIFF_INCLUDE_IGNORED |
2574 		GIT_DIFF_INCLUDE_TYPECHANGE |
2575 		GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
2576 		GIT_DIFF_SKIP_BINARY_CHECK |
2577 		GIT_DIFF_INCLUDE_CASECHANGE;
2578 	if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)
2579 		diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
2580 	if (data.opts.paths.count > 0)
2581 		diff_opts.pathspec = data.opts.paths;
2582 
2583 	/* set up iterators */
2584 
2585 	workdir_opts.flags = git_iterator_ignore_case(target) ?
2586 		GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
2587 	workdir_opts.flags |= GIT_ITERATOR_DONT_AUTOEXPAND;
2588 	workdir_opts.start = data.pfx;
2589 	workdir_opts.end = data.pfx;
2590 
2591 	if ((error = git_iterator_reset_range(target, data.pfx, data.pfx)) < 0 ||
2592 		(error = git_iterator_for_workdir_ext(
2593 			&workdir, data.repo, data.opts.target_directory, index, NULL,
2594 			&workdir_opts)) < 0)
2595 		goto cleanup;
2596 
2597 	baseline_opts.flags = git_iterator_ignore_case(target) ?
2598 		GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
2599 	baseline_opts.start = data.pfx;
2600 	baseline_opts.end = data.pfx;
2601 	if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
2602 		baseline_opts.pathlist.count = opts->paths.count;
2603 		baseline_opts.pathlist.strings = opts->paths.strings;
2604 	}
2605 
2606 	if (data.opts.baseline_index) {
2607 		if ((error = git_iterator_for_index(
2608 				&baseline, git_index_owner(data.opts.baseline_index),
2609 				data.opts.baseline_index, &baseline_opts)) < 0)
2610 			goto cleanup;
2611 	} else {
2612 		if ((error = git_iterator_for_tree(
2613 				&baseline, data.opts.baseline, &baseline_opts)) < 0)
2614 			goto cleanup;
2615 	}
2616 
2617 	/* Should not have case insensitivity mismatch */
2618 	assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
2619 
2620 	/* Generate baseline-to-target diff which will include an entry for
2621 	 * every possible update that might need to be made.
2622 	 */
2623 	if ((error = git_diff__from_iterators(
2624 			&data.diff, data.repo, baseline, target, &diff_opts)) < 0)
2625 		goto cleanup;
2626 
2627 	/* Loop through diff (and working directory iterator) building a list of
2628 	 * actions to be taken, plus look for conflicts and send notifications,
2629 	 * then loop through conflicts.
2630 	 */
2631 	if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0)
2632 		goto cleanup;
2633 
2634 	data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
2635 		counts[CHECKOUT_ACTION__REMOVE_CONFLICT] +
2636 		counts[CHECKOUT_ACTION__UPDATE_BLOB] +
2637 		counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] +
2638 		counts[CHECKOUT_ACTION__UPDATE_CONFLICT];
2639 
2640 	report_progress(&data, NULL); /* establish 0 baseline */
2641 
2642 	/* To deal with some order dependencies, perform remaining checkout
2643 	 * in three passes: removes, then update blobs, then update submodules.
2644 	 */
2645 	if (counts[CHECKOUT_ACTION__REMOVE] > 0 &&
2646 		(error = checkout_remove_the_old(actions, &data)) < 0)
2647 		goto cleanup;
2648 
2649 	if (counts[CHECKOUT_ACTION__REMOVE_CONFLICT] > 0 &&
2650 		(error = checkout_remove_conflicts(&data)) < 0)
2651 		goto cleanup;
2652 
2653 	if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 &&
2654 		(error = checkout_create_the_new(actions, &data)) < 0)
2655 		goto cleanup;
2656 
2657 	if (counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] > 0 &&
2658 		(error = checkout_create_submodules(actions, &data)) < 0)
2659 		goto cleanup;
2660 
2661 	if (counts[CHECKOUT_ACTION__UPDATE_CONFLICT] > 0 &&
2662 		(error = checkout_create_conflicts(&data)) < 0)
2663 		goto cleanup;
2664 
2665 	if (data.index != git_iterator_index(target) &&
2666 		(error = checkout_extensions_update_index(&data)) < 0)
2667 		goto cleanup;
2668 
2669 	assert(data.completed_steps == data.total_steps);
2670 
2671 	if (data.opts.perfdata_cb)
2672 		data.opts.perfdata_cb(&data.perfdata, data.opts.perfdata_payload);
2673 
2674 cleanup:
2675 	if (!error && data.index != NULL &&
2676 		(data.strategy & CHECKOUT_INDEX_DONT_WRITE_MASK) == 0)
2677 		error = git_index_write(data.index);
2678 
2679 	git_diff_free(data.diff);
2680 	git_iterator_free(workdir);
2681 	git_iterator_free(baseline);
2682 	git__free(actions);
2683 	git__free(counts);
2684 	checkout_data_clear(&data);
2685 
2686 	return error;
2687 }
2688 
git_checkout_index(git_repository * repo,git_index * index,const git_checkout_options * opts)2689 int git_checkout_index(
2690 	git_repository *repo,
2691 	git_index *index,
2692 	const git_checkout_options *opts)
2693 {
2694 	int error, owned = 0;
2695 	git_iterator *index_i;
2696 
2697 	if (!index && !repo) {
2698 		git_error_set(GIT_ERROR_CHECKOUT,
2699 			"must provide either repository or index to checkout");
2700 		return -1;
2701 	}
2702 
2703 	if (index && repo &&
2704 		git_index_owner(index) &&
2705 		git_index_owner(index) != repo) {
2706 		git_error_set(GIT_ERROR_CHECKOUT,
2707 			"index to checkout does not match repository");
2708 		return -1;
2709 	} else if(index && repo && !git_index_owner(index)) {
2710 		GIT_REFCOUNT_OWN(index, repo);
2711 		owned = 1;
2712 	}
2713 
2714 	if (!repo)
2715 		repo = git_index_owner(index);
2716 
2717 	if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
2718 		return error;
2719 	GIT_REFCOUNT_INC(index);
2720 
2721 	if (!(error = git_iterator_for_index(&index_i, repo, index, NULL)))
2722 		error = git_checkout_iterator(index_i, index, opts);
2723 
2724 	if (owned)
2725 		GIT_REFCOUNT_OWN(index, NULL);
2726 
2727 	git_iterator_free(index_i);
2728 	git_index_free(index);
2729 
2730 	return error;
2731 }
2732 
git_checkout_tree(git_repository * repo,const git_object * treeish,const git_checkout_options * opts)2733 int git_checkout_tree(
2734 	git_repository *repo,
2735 	const git_object *treeish,
2736 	const git_checkout_options *opts)
2737 {
2738 	int error;
2739 	git_index *index;
2740 	git_tree *tree = NULL;
2741 	git_iterator *tree_i = NULL;
2742 	git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
2743 
2744 	if (!treeish && !repo) {
2745 		git_error_set(GIT_ERROR_CHECKOUT,
2746 			"must provide either repository or tree to checkout");
2747 		return -1;
2748 	}
2749 	if (treeish && repo && git_object_owner(treeish) != repo) {
2750 		git_error_set(GIT_ERROR_CHECKOUT,
2751 			"object to checkout does not match repository");
2752 		return -1;
2753 	}
2754 
2755 	if (!repo)
2756 		repo = git_object_owner(treeish);
2757 
2758 	if (treeish) {
2759 		if (git_object_peel((git_object **)&tree, treeish, GIT_OBJECT_TREE) < 0) {
2760 			git_error_set(
2761 				GIT_ERROR_CHECKOUT, "provided object cannot be peeled to a tree");
2762 			return -1;
2763 		}
2764 	}
2765 	else {
2766 		if ((error = checkout_lookup_head_tree(&tree, repo)) < 0) {
2767 			if (error != GIT_EUNBORNBRANCH)
2768 				git_error_set(
2769 					GIT_ERROR_CHECKOUT,
2770 					"HEAD could not be peeled to a tree and no treeish given");
2771 			return error;
2772 		}
2773 	}
2774 
2775 	if ((error = git_repository_index(&index, repo)) < 0)
2776 		return error;
2777 
2778 	if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
2779 		iter_opts.pathlist.count = opts->paths.count;
2780 		iter_opts.pathlist.strings = opts->paths.strings;
2781 	}
2782 
2783 	if (!(error = git_iterator_for_tree(&tree_i, tree, &iter_opts)))
2784 		error = git_checkout_iterator(tree_i, index, opts);
2785 
2786 	git_iterator_free(tree_i);
2787 	git_index_free(index);
2788 	git_tree_free(tree);
2789 
2790 	return error;
2791 }
2792 
git_checkout_head(git_repository * repo,const git_checkout_options * opts)2793 int git_checkout_head(
2794 	git_repository *repo,
2795 	const git_checkout_options *opts)
2796 {
2797 	assert(repo);
2798 	return git_checkout_tree(repo, NULL, opts);
2799 }
2800 
git_checkout_options_init(git_checkout_options * opts,unsigned int version)2801 int git_checkout_options_init(git_checkout_options *opts, unsigned int version)
2802 {
2803 	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2804 		opts, version, git_checkout_options, GIT_CHECKOUT_OPTIONS_INIT);
2805 	return 0;
2806 }
2807 
git_checkout_init_options(git_checkout_options * opts,unsigned int version)2808 int git_checkout_init_options(git_checkout_options *opts, unsigned int version)
2809 {
2810 	return git_checkout_options_init(opts, version);
2811 }
2812