merge-blobs.con commit Merge branch 'jk/pack-revindex' (4fd1359)
   1#include "cache.h"
   2#include "run-command.h"
   3#include "xdiff-interface.h"
   4#include "ll-merge.h"
   5#include "blob.h"
   6#include "merge-blobs.h"
   7
   8static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
   9{
  10        void *buf;
  11        unsigned long size;
  12        enum object_type type;
  13
  14        buf = read_sha1_file(obj->object.oid.hash, &type, &size);
  15        if (!buf)
  16                return -1;
  17        if (type != OBJ_BLOB) {
  18                free(buf);
  19                return -1;
  20        }
  21        f->ptr = buf;
  22        f->size = size;
  23        return 0;
  24}
  25
  26static void free_mmfile(mmfile_t *f)
  27{
  28        free(f->ptr);
  29}
  30
  31static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)
  32{
  33        int merge_status;
  34        mmbuffer_t res;
  35
  36        /*
  37         * This function is only used by cmd_merge_tree, which
  38         * does not respect the merge.conflictstyle option.
  39         * There is no need to worry about a label for the
  40         * common ancestor.
  41         */
  42        merge_status = ll_merge(&res, path, base, NULL,
  43                                our, ".our", their, ".their", NULL);
  44        if (merge_status < 0)
  45                return NULL;
  46
  47        *size = res.size;
  48        return res.ptr;
  49}
  50
  51static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
  52{
  53        int i;
  54        mmfile_t *dst = priv_;
  55
  56        for (i = 0; i < nbuf; i++) {
  57                memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
  58                dst->size += mb[i].size;
  59        }
  60        return 0;
  61}
  62
  63static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
  64{
  65        unsigned long size = f1->size < f2->size ? f1->size : f2->size;
  66        void *ptr = xmalloc(size);
  67        xpparam_t xpp;
  68        xdemitconf_t xecfg;
  69        xdemitcb_t ecb;
  70
  71        memset(&xpp, 0, sizeof(xpp));
  72        xpp.flags = 0;
  73        memset(&xecfg, 0, sizeof(xecfg));
  74        xecfg.ctxlen = 3;
  75        xecfg.flags = XDL_EMIT_COMMON;
  76        ecb.outf = common_outf;
  77
  78        res->ptr = ptr;
  79        res->size = 0;
  80
  81        ecb.priv = res;
  82        return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
  83}
  84
  85void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
  86{
  87        void *res = NULL;
  88        mmfile_t f1, f2, common;
  89
  90        /*
  91         * Removed in either branch?
  92         *
  93         * NOTE! This depends on the caller having done the
  94         * proper warning about removing a file that got
  95         * modified in the other branch!
  96         */
  97        if (!our || !their) {
  98                enum object_type type;
  99                if (base)
 100                        return NULL;
 101                if (!our)
 102                        our = their;
 103                return read_sha1_file(our->object.oid.hash, &type, size);
 104        }
 105
 106        if (fill_mmfile_blob(&f1, our) < 0)
 107                goto out_no_mmfile;
 108        if (fill_mmfile_blob(&f2, their) < 0)
 109                goto out_free_f1;
 110
 111        if (base) {
 112                if (fill_mmfile_blob(&common, base) < 0)
 113                        goto out_free_f2_f1;
 114        } else {
 115                if (generate_common_file(&common, &f1, &f2) < 0)
 116                        goto out_free_f2_f1;
 117        }
 118        res = three_way_filemerge(path, &common, &f1, &f2, size);
 119        free_mmfile(&common);
 120out_free_f2_f1:
 121        free_mmfile(&f2);
 122out_free_f1:
 123        free_mmfile(&f1);
 124out_no_mmfile:
 125        return res;
 126}