1 /*
2  * Low level 3-way in-core file merge.
3  *
4  * Copyright (c) 2007 Junio C Hamano
5  */
6 
7 #include "cache.h"
8 #include "config.h"
9 #include "attr.h"
10 #include "xdiff-interface.h"
11 #include "run-command.h"
12 #include "ll-merge.h"
13 #include "quote.h"
14 
15 struct ll_merge_driver;
16 
17 typedef int (*ll_merge_fn)(const struct ll_merge_driver *,
18 			   mmbuffer_t *result,
19 			   const char *path,
20 			   mmfile_t *orig, const char *orig_name,
21 			   mmfile_t *src1, const char *name1,
22 			   mmfile_t *src2, const char *name2,
23 			   const struct ll_merge_options *opts,
24 			   int marker_size);
25 
26 struct ll_merge_driver {
27 	const char *name;
28 	const char *description;
29 	ll_merge_fn fn;
30 	const char *recursive;
31 	struct ll_merge_driver *next;
32 	char *cmdline;
33 };
34 
35 static struct attr_check *merge_attributes;
load_merge_attributes(void)36 static struct attr_check *load_merge_attributes(void)
37 {
38 	if (!merge_attributes)
39 		merge_attributes = attr_check_initl("merge", "conflict-marker-size", NULL);
40 	return merge_attributes;
41 }
42 
reset_merge_attributes(void)43 void reset_merge_attributes(void)
44 {
45 	attr_check_free(merge_attributes);
46 	merge_attributes = NULL;
47 }
48 
49 /*
50  * Built-in low-levels
51  */
ll_binary_merge(const struct ll_merge_driver * drv_unused,mmbuffer_t * result,const char * path,mmfile_t * orig,const char * orig_name,mmfile_t * src1,const char * name1,mmfile_t * src2,const char * name2,const struct ll_merge_options * opts,int marker_size)52 static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
53 			   mmbuffer_t *result,
54 			   const char *path,
55 			   mmfile_t *orig, const char *orig_name,
56 			   mmfile_t *src1, const char *name1,
57 			   mmfile_t *src2, const char *name2,
58 			   const struct ll_merge_options *opts,
59 			   int marker_size)
60 {
61 	mmfile_t *stolen;
62 	assert(opts);
63 
64 	/*
65 	 * The tentative merge result is the common ancestor for an
66 	 * internal merge.  For the final merge, it is "ours" by
67 	 * default but -Xours/-Xtheirs can tweak the choice.
68 	 */
69 	if (opts->virtual_ancestor) {
70 		stolen = orig;
71 	} else {
72 		switch (opts->variant) {
73 		default:
74 			warning("Cannot merge binary files: %s (%s vs. %s)",
75 				path, name1, name2);
76 			/* fallthru */
77 		case XDL_MERGE_FAVOR_OURS:
78 			stolen = src1;
79 			break;
80 		case XDL_MERGE_FAVOR_THEIRS:
81 			stolen = src2;
82 			break;
83 		}
84 	}
85 
86 	result->ptr = stolen->ptr;
87 	result->size = stolen->size;
88 	stolen->ptr = NULL;
89 
90 	/*
91 	 * With -Xtheirs or -Xours, we have cleanly merged;
92 	 * otherwise we got a conflict.
93 	 */
94 	return (opts->variant ? 0 : 1);
95 }
96 
ll_xdl_merge(const struct ll_merge_driver * drv_unused,mmbuffer_t * result,const char * path,mmfile_t * orig,const char * orig_name,mmfile_t * src1,const char * name1,mmfile_t * src2,const char * name2,const struct ll_merge_options * opts,int marker_size)97 static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
98 			mmbuffer_t *result,
99 			const char *path,
100 			mmfile_t *orig, const char *orig_name,
101 			mmfile_t *src1, const char *name1,
102 			mmfile_t *src2, const char *name2,
103 			const struct ll_merge_options *opts,
104 			int marker_size)
105 {
106 	xmparam_t xmp;
107 	assert(opts);
108 
109 	if (orig->size > MAX_XDIFF_SIZE ||
110 	    src1->size > MAX_XDIFF_SIZE ||
111 	    src2->size > MAX_XDIFF_SIZE ||
112 	    buffer_is_binary(orig->ptr, orig->size) ||
113 	    buffer_is_binary(src1->ptr, src1->size) ||
114 	    buffer_is_binary(src2->ptr, src2->size)) {
115 		return ll_binary_merge(drv_unused, result,
116 				       path,
117 				       orig, orig_name,
118 				       src1, name1,
119 				       src2, name2,
120 				       opts, marker_size);
121 	}
122 
123 	memset(&xmp, 0, sizeof(xmp));
124 	xmp.level = XDL_MERGE_ZEALOUS;
125 	xmp.favor = opts->variant;
126 	xmp.xpp.flags = opts->xdl_opts;
127 	if (git_xmerge_style >= 0)
128 		xmp.style = git_xmerge_style;
129 	if (marker_size > 0)
130 		xmp.marker_size = marker_size;
131 	xmp.ancestor = orig_name;
132 	xmp.file1 = name1;
133 	xmp.file2 = name2;
134 	return xdl_merge(orig, src1, src2, &xmp, result);
135 }
136 
ll_union_merge(const struct ll_merge_driver * drv_unused,mmbuffer_t * result,const char * path_unused,mmfile_t * orig,const char * orig_name,mmfile_t * src1,const char * name1,mmfile_t * src2,const char * name2,const struct ll_merge_options * opts,int marker_size)137 static int ll_union_merge(const struct ll_merge_driver *drv_unused,
138 			  mmbuffer_t *result,
139 			  const char *path_unused,
140 			  mmfile_t *orig, const char *orig_name,
141 			  mmfile_t *src1, const char *name1,
142 			  mmfile_t *src2, const char *name2,
143 			  const struct ll_merge_options *opts,
144 			  int marker_size)
145 {
146 	/* Use union favor */
147 	struct ll_merge_options o;
148 	assert(opts);
149 	o = *opts;
150 	o.variant = XDL_MERGE_FAVOR_UNION;
151 	return ll_xdl_merge(drv_unused, result, path_unused,
152 			    orig, NULL, src1, NULL, src2, NULL,
153 			    &o, marker_size);
154 }
155 
156 #define LL_BINARY_MERGE 0
157 #define LL_TEXT_MERGE 1
158 #define LL_UNION_MERGE 2
159 static struct ll_merge_driver ll_merge_drv[] = {
160 	{ "binary", "built-in binary merge", ll_binary_merge },
161 	{ "text", "built-in 3-way text merge", ll_xdl_merge },
162 	{ "union", "built-in union merge", ll_union_merge },
163 };
164 
create_temp(mmfile_t * src,char * path,size_t len)165 static void create_temp(mmfile_t *src, char *path, size_t len)
166 {
167 	int fd;
168 
169 	xsnprintf(path, len, ".merge_file_XXXXXX");
170 	fd = xmkstemp(path);
171 	if (write_in_full(fd, src->ptr, src->size) < 0)
172 		die_errno("unable to write temp-file");
173 	close(fd);
174 }
175 
176 /*
177  * User defined low-level merge driver support.
178  */
ll_ext_merge(const struct ll_merge_driver * fn,mmbuffer_t * result,const char * path,mmfile_t * orig,const char * orig_name,mmfile_t * src1,const char * name1,mmfile_t * src2,const char * name2,const struct ll_merge_options * opts,int marker_size)179 static int ll_ext_merge(const struct ll_merge_driver *fn,
180 			mmbuffer_t *result,
181 			const char *path,
182 			mmfile_t *orig, const char *orig_name,
183 			mmfile_t *src1, const char *name1,
184 			mmfile_t *src2, const char *name2,
185 			const struct ll_merge_options *opts,
186 			int marker_size)
187 {
188 	char temp[4][50];
189 	struct strbuf cmd = STRBUF_INIT;
190 	struct strbuf_expand_dict_entry dict[6];
191 	struct strbuf path_sq = STRBUF_INIT;
192 	const char *args[] = { NULL, NULL };
193 	int status, fd, i;
194 	struct stat st;
195 	assert(opts);
196 
197 	sq_quote_buf(&path_sq, path);
198 	dict[0].placeholder = "O"; dict[0].value = temp[0];
199 	dict[1].placeholder = "A"; dict[1].value = temp[1];
200 	dict[2].placeholder = "B"; dict[2].value = temp[2];
201 	dict[3].placeholder = "L"; dict[3].value = temp[3];
202 	dict[4].placeholder = "P"; dict[4].value = path_sq.buf;
203 	dict[5].placeholder = NULL; dict[5].value = NULL;
204 
205 	if (fn->cmdline == NULL)
206 		die("custom merge driver %s lacks command line.", fn->name);
207 
208 	result->ptr = NULL;
209 	result->size = 0;
210 	create_temp(orig, temp[0], sizeof(temp[0]));
211 	create_temp(src1, temp[1], sizeof(temp[1]));
212 	create_temp(src2, temp[2], sizeof(temp[2]));
213 	xsnprintf(temp[3], sizeof(temp[3]), "%d", marker_size);
214 
215 	strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
216 
217 	args[0] = cmd.buf;
218 	status = run_command_v_opt(args, RUN_USING_SHELL);
219 	fd = open(temp[1], O_RDONLY);
220 	if (fd < 0)
221 		goto bad;
222 	if (fstat(fd, &st))
223 		goto close_bad;
224 	result->size = st.st_size;
225 	result->ptr = xmallocz(result->size);
226 	if (read_in_full(fd, result->ptr, result->size) != result->size) {
227 		FREE_AND_NULL(result->ptr);
228 		result->size = 0;
229 	}
230  close_bad:
231 	close(fd);
232  bad:
233 	for (i = 0; i < 3; i++)
234 		unlink_or_warn(temp[i]);
235 	strbuf_release(&cmd);
236 	strbuf_release(&path_sq);
237 	return status;
238 }
239 
240 /*
241  * merge.default and merge.driver configuration items
242  */
243 static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
244 static const char *default_ll_merge;
245 
read_merge_config(const char * var,const char * value,void * cb)246 static int read_merge_config(const char *var, const char *value, void *cb)
247 {
248 	struct ll_merge_driver *fn;
249 	const char *key, *name;
250 	int namelen;
251 
252 	if (!strcmp(var, "merge.default"))
253 		return git_config_string(&default_ll_merge, var, value);
254 
255 	/*
256 	 * We are not interested in anything but "merge.<name>.variable";
257 	 * especially, we do not want to look at variables such as
258 	 * "merge.summary", "merge.tool", and "merge.verbosity".
259 	 */
260 	if (parse_config_key(var, "merge", &name, &namelen, &key) < 0 || !name)
261 		return 0;
262 
263 	/*
264 	 * Find existing one as we might be processing merge.<name>.var2
265 	 * after seeing merge.<name>.var1.
266 	 */
267 	for (fn = ll_user_merge; fn; fn = fn->next)
268 		if (!strncmp(fn->name, name, namelen) && !fn->name[namelen])
269 			break;
270 	if (!fn) {
271 		fn = xcalloc(1, sizeof(struct ll_merge_driver));
272 		fn->name = xmemdupz(name, namelen);
273 		fn->fn = ll_ext_merge;
274 		*ll_user_merge_tail = fn;
275 		ll_user_merge_tail = &(fn->next);
276 	}
277 
278 	if (!strcmp("name", key))
279 		return git_config_string(&fn->description, var, value);
280 
281 	if (!strcmp("driver", key)) {
282 		if (!value)
283 			return error("%s: lacks value", var);
284 		/*
285 		 * merge.<name>.driver specifies the command line:
286 		 *
287 		 *	command-line
288 		 *
289 		 * The command-line will be interpolated with the following
290 		 * tokens and is given to the shell:
291 		 *
292 		 *    %O - temporary file name for the merge base.
293 		 *    %A - temporary file name for our version.
294 		 *    %B - temporary file name for the other branches' version.
295 		 *    %L - conflict marker length
296 		 *    %P - the original path (safely quoted for the shell)
297 		 *
298 		 * The external merge driver should write the results in the
299 		 * file named by %A, and signal that it has done with zero exit
300 		 * status.
301 		 */
302 		fn->cmdline = xstrdup(value);
303 		return 0;
304 	}
305 
306 	if (!strcmp("recursive", key))
307 		return git_config_string(&fn->recursive, var, value);
308 
309 	return 0;
310 }
311 
initialize_ll_merge(void)312 static void initialize_ll_merge(void)
313 {
314 	if (ll_user_merge_tail)
315 		return;
316 	ll_user_merge_tail = &ll_user_merge;
317 	git_config(read_merge_config, NULL);
318 }
319 
find_ll_merge_driver(const char * merge_attr)320 static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr)
321 {
322 	struct ll_merge_driver *fn;
323 	const char *name;
324 	int i;
325 
326 	initialize_ll_merge();
327 
328 	if (ATTR_TRUE(merge_attr))
329 		return &ll_merge_drv[LL_TEXT_MERGE];
330 	else if (ATTR_FALSE(merge_attr))
331 		return &ll_merge_drv[LL_BINARY_MERGE];
332 	else if (ATTR_UNSET(merge_attr)) {
333 		if (!default_ll_merge)
334 			return &ll_merge_drv[LL_TEXT_MERGE];
335 		else
336 			name = default_ll_merge;
337 	}
338 	else
339 		name = merge_attr;
340 
341 	for (fn = ll_user_merge; fn; fn = fn->next)
342 		if (!strcmp(fn->name, name))
343 			return fn;
344 
345 	for (i = 0; i < ARRAY_SIZE(ll_merge_drv); i++)
346 		if (!strcmp(ll_merge_drv[i].name, name))
347 			return &ll_merge_drv[i];
348 
349 	/* default to the 3-way */
350 	return &ll_merge_drv[LL_TEXT_MERGE];
351 }
352 
normalize_file(mmfile_t * mm,const char * path,struct index_state * istate)353 static void normalize_file(mmfile_t *mm, const char *path, struct index_state *istate)
354 {
355 	struct strbuf strbuf = STRBUF_INIT;
356 	if (renormalize_buffer(istate, path, mm->ptr, mm->size, &strbuf)) {
357 		free(mm->ptr);
358 		mm->size = strbuf.len;
359 		mm->ptr = strbuf_detach(&strbuf, NULL);
360 	}
361 }
362 
ll_merge(mmbuffer_t * result_buf,const char * path,mmfile_t * ancestor,const char * ancestor_label,mmfile_t * ours,const char * our_label,mmfile_t * theirs,const char * their_label,struct index_state * istate,const struct ll_merge_options * opts)363 int ll_merge(mmbuffer_t *result_buf,
364 	     const char *path,
365 	     mmfile_t *ancestor, const char *ancestor_label,
366 	     mmfile_t *ours, const char *our_label,
367 	     mmfile_t *theirs, const char *their_label,
368 	     struct index_state *istate,
369 	     const struct ll_merge_options *opts)
370 {
371 	struct attr_check *check = load_merge_attributes();
372 	static const struct ll_merge_options default_opts;
373 	const char *ll_driver_name = NULL;
374 	int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
375 	const struct ll_merge_driver *driver;
376 
377 	if (!opts)
378 		opts = &default_opts;
379 
380 	if (opts->renormalize) {
381 		normalize_file(ancestor, path, istate);
382 		normalize_file(ours, path, istate);
383 		normalize_file(theirs, path, istate);
384 	}
385 
386 	git_check_attr(istate, path, check);
387 	ll_driver_name = check->items[0].value;
388 	if (check->items[1].value) {
389 		marker_size = atoi(check->items[1].value);
390 		if (marker_size <= 0)
391 			marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
392 	}
393 	driver = find_ll_merge_driver(ll_driver_name);
394 
395 	if (opts->virtual_ancestor) {
396 		if (driver->recursive)
397 			driver = find_ll_merge_driver(driver->recursive);
398 	}
399 	if (opts->extra_marker_size) {
400 		marker_size += opts->extra_marker_size;
401 	}
402 	return driver->fn(driver, result_buf, path, ancestor, ancestor_label,
403 			  ours, our_label, theirs, their_label,
404 			  opts, marker_size);
405 }
406 
ll_merge_marker_size(struct index_state * istate,const char * path)407 int ll_merge_marker_size(struct index_state *istate, const char *path)
408 {
409 	static struct attr_check *check;
410 	int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
411 
412 	if (!check)
413 		check = attr_check_initl("conflict-marker-size", NULL);
414 	git_check_attr(istate, path, check);
415 	if (check->items[0].value) {
416 		marker_size = atoi(check->items[0].value);
417 		if (marker_size <= 0)
418 			marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
419 	}
420 	return marker_size;
421 }
422