Staging
v0.5.2
https://github.com/git/git
Revision 6490a3383f1d0d96c122069e510ef1af1d019fbb authored by Junio C Hamano on 02 August 2007, 22:10:56 UTC, committed by Junio C Hamano on 03 August 2007, 00:26:26 UTC
In set_work_tree(), variable rel needs to be reinitialized to
NULL on every call (it should not be static).

Make sure the incoming dir variable is not too long before
copying to the temporary buffer, and make sure chdir to the
resulting directory succeeds.

This was spotted and fixed by Alex and Johannes in a handful
patch exchanges.  Here is the final version.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Acked-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
1 parent 29093c2
Raw File
Tip revision: 6490a3383f1d0d96c122069e510ef1af1d019fbb authored by Junio C Hamano on 02 August 2007, 22:10:56 UTC
Fix work-tree related breakages
Tip revision: 6490a33
merge-file.c
#include "cache.h"
#include "run-command.h"
#include "xdiff-interface.h"
#include "blob.h"

static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
{
	void *buf;
	unsigned long size;
	enum object_type type;

	buf = read_sha1_file(obj->object.sha1, &type, &size);
	if (!buf)
		return -1;
	if (type != OBJ_BLOB)
		return -1;
	f->ptr = buf;
	f->size = size;
	return 0;
}

static void free_mmfile(mmfile_t *f)
{
	free(f->ptr);
}

static void *three_way_filemerge(mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)
{
	mmbuffer_t res;
	xpparam_t xpp;
	int merge_status;

	memset(&xpp, 0, sizeof(xpp));
	merge_status = xdl_merge(base, our, ".our", their, ".their",
		&xpp, XDL_MERGE_ZEALOUS, &res);

	if (merge_status < 0)
		return NULL;

	*size = res.size;
	return res.ptr;
}

static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
{
	int i;
	mmfile_t *dst = priv_;

	for (i = 0; i < nbuf; i++) {
		memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
		dst->size += mb[i].size;
	}
	return 0;
}

static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
{
	unsigned long size = f1->size < f2->size ? f1->size : f2->size;
	void *ptr = xmalloc(size);
	xpparam_t xpp;
	xdemitconf_t xecfg;
	xdemitcb_t ecb;

	xpp.flags = XDF_NEED_MINIMAL;
	memset(&xecfg, 0, sizeof(xecfg));
	xecfg.ctxlen = 3;
	xecfg.flags = XDL_EMIT_COMMON;
	ecb.outf = common_outf;

	res->ptr = ptr;
	res->size = 0;

	ecb.priv = res;
	return xdl_diff(f1, f2, &xpp, &xecfg, &ecb);
}

void *merge_file(struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
{
	void *res = NULL;
	mmfile_t f1, f2, common;

	/*
	 * Removed in either branch?
	 *
	 * NOTE! This depends on the caller having done the
	 * proper warning about removing a file that got
	 * modified in the other branch!
	 */
	if (!our || !their) {
		enum object_type type;
		if (base)
			return NULL;
		if (!our)
			our = their;
		return read_sha1_file(our->object.sha1, &type, size);
	}

	if (fill_mmfile_blob(&f1, our) < 0)
		goto out_no_mmfile;
	if (fill_mmfile_blob(&f2, their) < 0)
		goto out_free_f1;

	if (base) {
		if (fill_mmfile_blob(&common, base) < 0)
			goto out_free_f2_f1;
	} else {
		if (generate_common_file(&common, &f1, &f2) < 0)
			goto out_free_f2_f1;
	}
	res = three_way_filemerge(&common, &f1, &f2, size);
	free_mmfile(&common);
out_free_f2_f1:
	free_mmfile(&f2);
out_free_f1:
	free_mmfile(&f1);
out_no_mmfile:
	return res;
}
back to top