diff.con commit [PATCH] Redo rename/copy detection logic. (25d5ea4)
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include <sys/types.h>
   5#include <sys/wait.h>
   6#include <signal.h>
   7#include "cache.h"
   8#include "diff.h"
   9#include "diffcore.h"
  10
  11static const char *diff_opts = "-pu";
  12static unsigned char null_sha1[20] = { 0, };
  13
  14static int reverse_diff;
  15
  16static const char *external_diff(void)
  17{
  18        static const char *external_diff_cmd = NULL;
  19        static int done_preparing = 0;
  20
  21        if (done_preparing)
  22                return external_diff_cmd;
  23
  24        /*
  25         * Default values above are meant to match the
  26         * Linux kernel development style.  Examples of
  27         * alternative styles you can specify via environment
  28         * variables are:
  29         *
  30         * GIT_DIFF_OPTS="-c";
  31         */
  32        if (gitenv("GIT_EXTERNAL_DIFF"))
  33                external_diff_cmd = gitenv("GIT_EXTERNAL_DIFF");
  34
  35        /* In case external diff fails... */
  36        diff_opts = gitenv("GIT_DIFF_OPTS") ? : diff_opts;
  37
  38        done_preparing = 1;
  39        return external_diff_cmd;
  40}
  41
  42/* Help to copy the thing properly quoted for the shell safety.
  43 * any single quote is replaced with '\'', and the caller is
  44 * expected to enclose the result within a single quote pair.
  45 *
  46 * E.g.
  47 *  original     sq_expand     result
  48 *  name     ==> name      ==> 'name'
  49 *  a b      ==> a b       ==> 'a b'
  50 *  a'b      ==> a'\''b    ==> 'a'\''b'
  51 */
  52static char *sq_expand(const char *src)
  53{
  54        static char *buf = NULL;
  55        int cnt, c;
  56        const char *cp;
  57        char *bp;
  58
  59        /* count bytes needed to store the quoted string. */
  60        for (cnt = 1, cp = src; *cp; cnt++, cp++)
  61                if (*cp == '\'')
  62                        cnt += 3;
  63
  64        buf = xmalloc(cnt);
  65        bp = buf;
  66        while ((c = *src++)) {
  67                if (c != '\'')
  68                        *bp++ = c;
  69                else {
  70                        bp = strcpy(bp, "'\\''");
  71                        bp += 4;
  72                }
  73        }
  74        *bp = 0;
  75        return buf;
  76}
  77
  78static struct diff_tempfile {
  79        const char *name; /* filename external diff should read from */
  80        char hex[41];
  81        char mode[10];
  82        char tmp_path[50];
  83} diff_temp[2];
  84
  85static void builtin_diff(const char *name_a,
  86                         const char *name_b,
  87                         struct diff_tempfile *temp,
  88                         const char *xfrm_msg)
  89{
  90        int i, next_at, cmd_size;
  91        const char *diff_cmd = "diff -L'%s%s' -L'%s%s'";
  92        const char *diff_arg  = "'%s' '%s'||:"; /* "||:" is to return 0 */
  93        const char *input_name_sq[2];
  94        const char *path0[2];
  95        const char *path1[2];
  96        const char *name_sq[2];
  97        char *cmd;
  98
  99        name_sq[0] = sq_expand(name_a);
 100        name_sq[1] = sq_expand(name_b);
 101
 102        /* diff_cmd and diff_arg have 6 %s in total which makes
 103         * the sum of these strings 12 bytes larger than required.
 104         * we use 2 spaces around diff-opts, and we need to count
 105         * terminating NUL, so we subtract 9 here.
 106         */
 107        cmd_size = (strlen(diff_cmd) + strlen(diff_opts) +
 108                        strlen(diff_arg) - 9);
 109        for (i = 0; i < 2; i++) {
 110                input_name_sq[i] = sq_expand(temp[i].name);
 111                if (!strcmp(temp[i].name, "/dev/null")) {
 112                        path0[i] = "/dev/null";
 113                        path1[i] = "";
 114                } else {
 115                        path0[i] = i ? "b/" : "a/";
 116                        path1[i] = name_sq[i];
 117                }
 118                cmd_size += (strlen(path0[i]) + strlen(path1[i]) +
 119                             strlen(input_name_sq[i]));
 120        }
 121
 122        cmd = xmalloc(cmd_size);
 123
 124        next_at = 0;
 125        next_at += snprintf(cmd+next_at, cmd_size-next_at,
 126                            diff_cmd,
 127                            path0[0], path1[0], path0[1], path1[1]);
 128        next_at += snprintf(cmd+next_at, cmd_size-next_at,
 129                            " %s ", diff_opts);
 130        next_at += snprintf(cmd+next_at, cmd_size-next_at,
 131                            diff_arg, input_name_sq[0], input_name_sq[1]);
 132
 133        printf("diff --git a/%s b/%s\n", name_a, name_b);
 134        if (!path1[0][0])
 135                printf("new file mode %s\n", temp[1].mode);
 136        else if (!path1[1][0])
 137                printf("deleted file mode %s\n", temp[0].mode);
 138        else {
 139                if (strcmp(temp[0].mode, temp[1].mode)) {
 140                        printf("old mode %s\n", temp[0].mode);
 141                        printf("new mode %s\n", temp[1].mode);
 142                }
 143                if (xfrm_msg && xfrm_msg[0])
 144                        fputs(xfrm_msg, stdout);
 145
 146                if (strncmp(temp[0].mode, temp[1].mode, 3))
 147                        /* we do not run diff between different kind
 148                         * of objects.
 149                         */
 150                        exit(0);
 151        }
 152        fflush(NULL);
 153        execlp("/bin/sh","sh", "-c", cmd, NULL);
 154}
 155
 156struct diff_filespec *alloc_filespec(const char *path)
 157{
 158        int namelen = strlen(path);
 159        struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
 160        spec->path = (char *)(spec + 1);
 161        strcpy(spec->path, path);
 162        spec->should_free = spec->should_munmap = 0;
 163        spec->xfrm_flags = 0;
 164        spec->size = 0;
 165        spec->data = NULL;
 166        spec->mode = 0;
 167        memset(spec->sha1, 0, 20);
 168        return spec;
 169}
 170
 171void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 172                   unsigned short mode)
 173{
 174        if (mode) { /* just playing defensive */
 175                spec->mode = mode;
 176                memcpy(spec->sha1, sha1, 20);
 177                spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
 178        }
 179}
 180
 181/*
 182 * Given a name and sha1 pair, if the dircache tells us the file in
 183 * the work tree has that object contents, return true, so that
 184 * prepare_temp_file() does not have to inflate and extract.
 185 */
 186static int work_tree_matches(const char *name, const unsigned char *sha1)
 187{
 188        struct cache_entry *ce;
 189        struct stat st;
 190        int pos, len;
 191
 192        /* We do not read the cache ourselves here, because the
 193         * benchmark with my previous version that always reads cache
 194         * shows that it makes things worse for diff-tree comparing
 195         * two linux-2.6 kernel trees in an already checked out work
 196         * tree.  This is because most diff-tree comparisons deal with
 197         * only a small number of files, while reading the cache is
 198         * expensive for a large project, and its cost outweighs the
 199         * savings we get by not inflating the object to a temporary
 200         * file.  Practically, this code only helps when we are used
 201         * by diff-cache --cached, which does read the cache before
 202         * calling us.
 203         */
 204        if (!active_cache)
 205                return 0;
 206
 207        len = strlen(name);
 208        pos = cache_name_pos(name, len);
 209        if (pos < 0)
 210                return 0;
 211        ce = active_cache[pos];
 212        if ((lstat(name, &st) < 0) ||
 213            !S_ISREG(st.st_mode) || /* careful! */
 214            ce_match_stat(ce, &st) ||
 215            memcmp(sha1, ce->sha1, 20))
 216                return 0;
 217        /* we return 1 only when we can stat, it is a regular file,
 218         * stat information matches, and sha1 recorded in the cache
 219         * matches.  I.e. we know the file in the work tree really is
 220         * the same as the <name, sha1> pair.
 221         */
 222        return 1;
 223}
 224
 225/*
 226 * While doing rename detection and pickaxe operation, we may need to
 227 * grab the data for the blob (or file) for our own in-core comparison.
 228 * diff_filespec has data and size fields for this purpose.
 229 */
 230int diff_populate_filespec(struct diff_filespec *s)
 231{
 232        int err = 0;
 233        if (!DIFF_FILE_VALID(s))
 234                die("internal error: asking to populate invalid file.");
 235        if (S_ISDIR(s->mode))
 236                return -1;
 237
 238        if (s->data)
 239                return err;
 240        if (!s->sha1_valid ||
 241            work_tree_matches(s->path, s->sha1)) {
 242                struct stat st;
 243                int fd;
 244                if (lstat(s->path, &st) < 0) {
 245                        if (errno == ENOENT) {
 246                        err_empty:
 247                                err = -1;
 248                        empty:
 249                                s->data = "";
 250                                s->size = 0;
 251                                return err;
 252                        }
 253                }
 254                s->size = st.st_size;
 255                if (!s->size)
 256                        goto empty;
 257                if (S_ISLNK(st.st_mode)) {
 258                        int ret;
 259                        s->data = xmalloc(s->size);
 260                        s->should_free = 1;
 261                        ret = readlink(s->path, s->data, s->size);
 262                        if (ret < 0) {
 263                                free(s->data);
 264                                goto err_empty;
 265                        }
 266                        return 0;
 267                }
 268                fd = open(s->path, O_RDONLY);
 269                if (fd < 0)
 270                        goto err_empty;
 271                s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
 272                s->should_munmap = 1;
 273                close(fd);
 274        }
 275        else {
 276                char type[20];
 277                s->data = read_sha1_file(s->sha1, type, &s->size);
 278                s->should_free = 1;
 279        }
 280        return 0;
 281}
 282
 283void diff_free_filespec_data(struct diff_filespec *s)
 284{
 285        if (s->should_free)
 286                free(s->data);
 287        else if (s->should_munmap)
 288                munmap(s->data, s->size);
 289        s->should_free = s->should_munmap = 0;
 290        s->data = NULL;
 291}
 292
 293static void prep_temp_blob(struct diff_tempfile *temp,
 294                           void *blob,
 295                           unsigned long size,
 296                           unsigned char *sha1,
 297                           int mode)
 298{
 299        int fd;
 300
 301        strcpy(temp->tmp_path, ".diff_XXXXXX");
 302        fd = mkstemp(temp->tmp_path);
 303        if (fd < 0)
 304                die("unable to create temp-file");
 305        if (write(fd, blob, size) != size)
 306                die("unable to write temp-file");
 307        close(fd);
 308        temp->name = temp->tmp_path;
 309        strcpy(temp->hex, sha1_to_hex(sha1));
 310        temp->hex[40] = 0;
 311        sprintf(temp->mode, "%06o", mode);
 312}
 313
 314static void prepare_temp_file(const char *name,
 315                              struct diff_tempfile *temp,
 316                              struct diff_filespec *one)
 317{
 318        if (!DIFF_FILE_VALID(one)) {
 319        not_a_valid_file:
 320                /* A '-' entry produces this for file-2, and
 321                 * a '+' entry produces this for file-1.
 322                 */
 323                temp->name = "/dev/null";
 324                strcpy(temp->hex, ".");
 325                strcpy(temp->mode, ".");
 326                return;
 327        }
 328
 329        if (!one->sha1_valid ||
 330            work_tree_matches(name, one->sha1)) {
 331                struct stat st;
 332                if (lstat(name, &st) < 0) {
 333                        if (errno == ENOENT)
 334                                goto not_a_valid_file;
 335                        die("stat(%s): %s", name, strerror(errno));
 336                }
 337                if (S_ISLNK(st.st_mode)) {
 338                        int ret;
 339                        char *buf, buf_[1024];
 340                        buf = ((sizeof(buf_) < st.st_size) ?
 341                               xmalloc(st.st_size) : buf_);
 342                        ret = readlink(name, buf, st.st_size);
 343                        if (ret < 0)
 344                                die("readlink(%s)", name);
 345                        prep_temp_blob(temp, buf, st.st_size,
 346                                       (one->sha1_valid ?
 347                                        one->sha1 : null_sha1),
 348                                       (one->sha1_valid ?
 349                                        one->mode : S_IFLNK));
 350                }
 351                else {
 352                        /* we can borrow from the file in the work tree */
 353                        temp->name = name;
 354                        if (!one->sha1_valid)
 355                                strcpy(temp->hex, sha1_to_hex(null_sha1));
 356                        else
 357                                strcpy(temp->hex, sha1_to_hex(one->sha1));
 358                        sprintf(temp->mode, "%06o",
 359                                S_IFREG |ce_permissions(st.st_mode));
 360                }
 361                return;
 362        }
 363        else {
 364                if (diff_populate_filespec(one))
 365                        die("cannot read data blob for %s", one->path);
 366                prep_temp_blob(temp, one->data, one->size,
 367                               one->sha1, one->mode);
 368        }
 369}
 370
 371static void remove_tempfile(void)
 372{
 373        int i;
 374
 375        for (i = 0; i < 2; i++)
 376                if (diff_temp[i].name == diff_temp[i].tmp_path) {
 377                        unlink(diff_temp[i].name);
 378                        diff_temp[i].name = NULL;
 379                }
 380}
 381
 382static void remove_tempfile_on_signal(int signo)
 383{
 384        remove_tempfile();
 385}
 386
 387/* An external diff command takes:
 388 *
 389 * diff-cmd name infile1 infile1-sha1 infile1-mode \
 390 *               infile2 infile2-sha1 infile2-mode [ rename-to ]
 391 *
 392 */
 393static void run_external_diff(const char *name,
 394                              const char *other,
 395                              struct diff_filespec *one,
 396                              struct diff_filespec *two,
 397                              const char *xfrm_msg)
 398{
 399        struct diff_tempfile *temp = diff_temp;
 400        pid_t pid;
 401        int status;
 402        static int atexit_asked = 0;
 403
 404        if (one && two) {
 405                prepare_temp_file(name, &temp[0], one);
 406                prepare_temp_file(other ? : name, &temp[1], two);
 407                if (! atexit_asked &&
 408                    (temp[0].name == temp[0].tmp_path ||
 409                     temp[1].name == temp[1].tmp_path)) {
 410                        atexit_asked = 1;
 411                        atexit(remove_tempfile);
 412                }
 413                signal(SIGINT, remove_tempfile_on_signal);
 414        }
 415
 416        fflush(NULL);
 417        pid = fork();
 418        if (pid < 0)
 419                die("unable to fork");
 420        if (!pid) {
 421                const char *pgm = external_diff();
 422                if (pgm) {
 423                        if (one && two) {
 424                                const char *exec_arg[10];
 425                                const char **arg = &exec_arg[0];
 426                                *arg++ = pgm;
 427                                *arg++ = name;
 428                                *arg++ = temp[0].name;
 429                                *arg++ = temp[0].hex;
 430                                *arg++ = temp[0].mode;
 431                                *arg++ = temp[1].name;
 432                                *arg++ = temp[1].hex;
 433                                *arg++ = temp[1].mode;
 434                                if (other) {
 435                                        *arg++ = other;
 436                                        *arg++ = xfrm_msg;
 437                                }
 438                                *arg = NULL;
 439                                execvp(pgm, (char *const*) exec_arg);
 440                        }
 441                        else
 442                                execlp(pgm, pgm, name, NULL);
 443                }
 444                /*
 445                 * otherwise we use the built-in one.
 446                 */
 447                if (one && two)
 448                        builtin_diff(name, other ? : name, temp, xfrm_msg);
 449                else
 450                        printf("* Unmerged path %s\n", name);
 451                exit(0);
 452        }
 453        if (waitpid(pid, &status, 0) < 0 ||
 454            !WIFEXITED(status) || WEXITSTATUS(status)) {
 455                /* Earlier we did not check the exit status because
 456                 * diff exits non-zero if files are different, and
 457                 * we are not interested in knowing that.  It was a
 458                 * mistake which made it harder to quit a diff-*
 459                 * session that uses the git-apply-patch-script as
 460                 * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
 461                 * should also exit non-zero only when it wants to
 462                 * abort the entire diff-* session.
 463                 */
 464                remove_tempfile();
 465                fprintf(stderr, "external diff died, stopping at %s.\n", name);
 466                exit(1);
 467        }
 468        remove_tempfile();
 469}
 470
 471void diff_setup(int reverse_diff_)
 472{
 473        reverse_diff = reverse_diff_;
 474}
 475
 476struct diff_queue_struct diff_queued_diff;
 477
 478void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
 479{
 480        if (queue->alloc <= queue->nr) {
 481                queue->alloc = alloc_nr(queue->alloc);
 482                queue->queue = xrealloc(queue->queue,
 483                                        sizeof(dp) * queue->alloc);
 484        }
 485        queue->queue[queue->nr++] = dp;
 486}
 487
 488struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
 489                                 struct diff_filespec *one,
 490                                 struct diff_filespec *two)
 491{
 492        struct diff_filepair *dp = xmalloc(sizeof(*dp));
 493        dp->one = one;
 494        dp->two = two;
 495        dp->score = 0;
 496        diff_q(queue, dp);
 497        return dp;
 498}
 499
 500static void diff_flush_raw(struct diff_filepair *p,
 501                           int line_termination,
 502                           int inter_name_termination)
 503{
 504        int two_paths;
 505        char status[10];
 506
 507        if (line_termination) {
 508                const char *err = "path %s cannot be expressed without -z";
 509                if (strchr(p->one->path, line_termination) ||
 510                    strchr(p->one->path, inter_name_termination))
 511                        die(err, p->one->path);
 512                if (strchr(p->two->path, line_termination) ||
 513                    strchr(p->two->path, inter_name_termination))
 514                        die(err, p->two->path);
 515        }
 516
 517        switch (p->status) {
 518        case 'C': case 'R':
 519                two_paths = 1;
 520                sprintf(status, "%c%1d", p->status, p->score);
 521                break;
 522        default:
 523                two_paths = 0;
 524                status[0] = p->status;
 525                status[1] = 0;
 526                break;
 527        }
 528        printf(":%06o %06o %s ",
 529               p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
 530        printf("%s %s%c%s",
 531               sha1_to_hex(p->two->sha1),
 532               status,
 533               inter_name_termination,
 534               p->one->path);
 535        if (two_paths)
 536                printf("%c%s", inter_name_termination, p->two->path);
 537        putchar(line_termination);
 538}
 539
 540int diff_unmodified_pair(struct diff_filepair *p)
 541{
 542        /* This function is written stricter than necessary to support
 543         * the currently implemented transformers, but the idea is to
 544         * let transformers to produce diff_filepairs any way they want,
 545         * and filter and clean them up here before producing the output.
 546         */
 547        struct diff_filespec *one, *two;
 548
 549        if (DIFF_PAIR_UNMERGED(p))
 550                return 0; /* unmerged is interesting */
 551
 552        one = p->one;
 553        two = p->two;
 554
 555        /* deletion, addition, mode change and renames are all interesting. */
 556        if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
 557            (one->mode != two->mode) ||
 558            strcmp(one->path, two->path))
 559                return 0;
 560
 561        /* both are valid and point at the same path.  that is, we are
 562         * dealing with a change.
 563         */
 564        if (one->sha1_valid && two->sha1_valid &&
 565            !memcmp(one->sha1, two->sha1, sizeof(one->sha1)))
 566                return 1; /* no change */
 567        if (!one->sha1_valid && !two->sha1_valid)
 568                return 1; /* both look at the same file on the filesystem. */
 569        return 0;
 570}
 571
 572static void diff_flush_patch(struct diff_filepair *p)
 573{
 574        const char *name, *other;
 575        char msg_[PATH_MAX*2+200], *msg;
 576
 577        if (diff_unmodified_pair(p))
 578                return;
 579
 580        name = p->one->path;
 581        other = (strcmp(name, p->two->path) ? p->two->path : NULL);
 582        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
 583            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
 584                return; /* no tree diffs in patch format */ 
 585
 586        switch (p->status) {
 587        case 'C':
 588                sprintf(msg_,
 589                        "similarity index %d%%\n"
 590                        "copy from %s\n"
 591                        "copy to %s\n",
 592                        (int)(0.5 + p->score * 100.0/MAX_SCORE),
 593                        p->one->path, p->two->path);
 594                msg = msg_;
 595                break;
 596        case 'R':
 597                sprintf(msg_,
 598                        "similarity index %d%%\n"
 599                        "rename old %s\n"
 600                        "rename new %s\n",
 601                        (int)(0.5 + p->score * 100.0/MAX_SCORE),
 602                        p->one->path, p->two->path);
 603                msg = msg_;
 604                break;
 605        default:
 606                msg = NULL;
 607        }
 608
 609        if (DIFF_PAIR_UNMERGED(p))
 610                run_external_diff(name, NULL, NULL, NULL, NULL);
 611        else
 612                run_external_diff(name, other, p->one, p->two, msg);
 613}
 614
 615int diff_needs_to_stay(struct diff_queue_struct *q, int i,
 616                       struct diff_filespec *it)
 617{
 618        /* If it will be used in later entry (either stay or used
 619         * as the source of rename/copy), we need to copy, not rename.
 620         */
 621        while (i < q->nr) {
 622                struct diff_filepair *p = q->queue[i++];
 623                if (!DIFF_FILE_VALID(p->two))
 624                        continue; /* removed is fine */
 625                if (strcmp(p->one->path, it->path))
 626                        continue; /* not relevant */
 627
 628                /* p has its src set to *it and it is not a delete;
 629                 * it will be used for in-place change, rename/copy,
 630                 * or just stays there.  We cannot rename it out.
 631                 */
 632                return 1;
 633        }
 634        return 0;
 635}
 636
 637int diff_queue_is_empty(void)
 638{
 639        struct diff_queue_struct *q = &diff_queued_diff;
 640        int i;
 641        for (i = 0; i < q->nr; i++)
 642                if (!diff_unmodified_pair(q->queue[i]))
 643                        return 0;
 644        return 1;
 645}
 646
 647#if DIFF_DEBUG
 648void diff_debug_filespec(struct diff_filespec *s, int x, const char *one)
 649{
 650        fprintf(stderr, "queue[%d] %s (%s) %s %06o %s\n",
 651                x, one ? : "",
 652                s->path,
 653                DIFF_FILE_VALID(s) ? "valid" : "invalid",
 654                s->mode,
 655                s->sha1_valid ? sha1_to_hex(s->sha1) : "");
 656        fprintf(stderr, "queue[%d] %s size %lu flags %d\n",
 657                x, one ? : "",
 658                s->size, s->xfrm_flags);
 659}
 660
 661void diff_debug_filepair(const struct diff_filepair *p, int i)
 662{
 663        diff_debug_filespec(p->one, i, "one");
 664        diff_debug_filespec(p->two, i, "two");
 665        fprintf(stderr, "score %d, status %c\n",
 666                p->score, p->status ? : '?');
 667}
 668
 669void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
 670{
 671        int i;
 672        if (msg)
 673                fprintf(stderr, "%s\n", msg);
 674        fprintf(stderr, "q->nr = %d\n", q->nr);
 675        for (i = 0; i < q->nr; i++) {
 676                struct diff_filepair *p = q->queue[i];
 677                diff_debug_filepair(p, i);
 678        }
 679}
 680#endif
 681
 682static void diff_resolve_rename_copy(void)
 683{
 684        int i, j;
 685        struct diff_filepair *p, *pp;
 686        struct diff_queue_struct *q = &diff_queued_diff;
 687
 688        /* This should not depend on the ordering of things. */
 689
 690        diff_debug_queue("resolve-rename-copy", q);
 691
 692        for (i = 0; i < q->nr; i++) {
 693                p = q->queue[i];
 694                p->status = 0;
 695                if (DIFF_PAIR_UNMERGED(p))
 696                        p->status = 'U';
 697                else if (!DIFF_FILE_VALID((p)->one))
 698                        p->status = 'N';
 699                else if (!DIFF_FILE_VALID((p)->two)) {
 700                        /* Deletion record should be omitted if there
 701                         * is another entry that is a rename or a copy
 702                         * and it uses this one as the source.  Then we
 703                         * can say the other one is a rename.
 704                         */
 705                        for (j = 0; j < q->nr; j++) {
 706                                pp = q->queue[j];
 707                                if (!strcmp(pp->one->path, p->one->path) &&
 708                                    strcmp(pp->one->path, pp->two->path))
 709                                        break;
 710                        }
 711                        if (j < q->nr)
 712                                continue; /* has rename/copy */
 713                        p->status = 'D';
 714                }
 715                else if (strcmp(p->one->path, p->two->path)) {
 716                        /* See if there is somebody else anywhere that
 717                         * will keep the path (either modified or
 718                         * unmodified).  If so, we have to be a copy,
 719                         * not a rename.  In addition, if there is
 720                         * some other rename or copy that comes later
 721                         * than us that uses the same source, we
 722                         * cannot be a rename either.
 723                         */
 724                        for (j = 0; j < q->nr; j++) {
 725                                pp = q->queue[j];
 726                                if (strcmp(pp->one->path, p->one->path))
 727                                        continue;
 728                                if (!strcmp(pp->one->path, pp->two->path)) {
 729                                        if (DIFF_FILE_VALID(pp->two)) {
 730                                                /* non-delete */
 731                                                p->status = 'C';
 732                                                break;
 733                                        }
 734                                        continue;
 735                                }
 736                                /* pp is a rename/copy ... */
 737                                if (i < j) {
 738                                        /* ... and comes later than us */
 739                                        p->status = 'C';
 740                                        break;
 741                                }
 742                        }
 743                        if (!p->status)
 744                                p->status = 'R';
 745                }
 746                else if (memcmp(p->one->sha1, p->two->sha1, 20))
 747                        p->status = 'M';
 748                else {
 749                        /* we do not need this one */
 750                        p->status = 0;
 751                }
 752        }
 753        diff_debug_queue("resolve-rename-copy done", q);
 754}
 755
 756void diff_flush(int diff_output_style, int resolve_rename_copy)
 757{
 758        struct diff_queue_struct *q = &diff_queued_diff;
 759        int i;
 760        int line_termination = '\n';
 761        int inter_name_termination = '\t';
 762
 763        if (diff_output_style == DIFF_FORMAT_MACHINE)
 764                line_termination = inter_name_termination = 0;
 765        if (resolve_rename_copy)
 766                diff_resolve_rename_copy();
 767
 768        for (i = 0; i < q->nr; i++) {
 769                struct diff_filepair *p = q->queue[i];
 770                if (p->status == 0)
 771                        continue;
 772                switch (diff_output_style) {
 773                case DIFF_FORMAT_PATCH:
 774                        diff_flush_patch(p);
 775                        break;
 776                case DIFF_FORMAT_HUMAN:
 777                case DIFF_FORMAT_MACHINE:
 778                        diff_flush_raw(p, line_termination,
 779                                       inter_name_termination);
 780                        break;
 781                }
 782        }
 783        for (i = 0; i < q->nr; i++) {
 784                struct diff_filepair *p = q->queue[i];
 785                diff_free_filespec_data(p->one);
 786                diff_free_filespec_data(p->two);
 787                free(p);
 788        }
 789        free(q->queue);
 790        q->queue = NULL;
 791        q->nr = q->alloc = 0;
 792}
 793
 794void diff_addremove(int addremove, unsigned mode,
 795                    const unsigned char *sha1,
 796                    const char *base, const char *path)
 797{
 798        char concatpath[PATH_MAX];
 799        struct diff_filespec *one, *two;
 800
 801        /* This may look odd, but it is a preparation for
 802         * feeding "there are unchanged files which should
 803         * not produce diffs, but when you are doing copy
 804         * detection you would need them, so here they are"
 805         * entries to the diff-core.  They will be prefixed
 806         * with something like '=' or '*' (I haven't decided
 807         * which but should not make any difference).
 808         * Feeding the same new and old to diff_change() 
 809         * also has the same effect.
 810         * Before the final output happens, they are pruned after
 811         * merged into rename/copy pairs as appropriate.
 812         */
 813        if (reverse_diff)
 814                addremove = (addremove == '+' ? '-' :
 815                             addremove == '-' ? '+' : addremove);
 816
 817        if (!path) path = "";
 818        sprintf(concatpath, "%s%s", base, path);
 819        one = alloc_filespec(concatpath);
 820        two = alloc_filespec(concatpath);
 821
 822        if (addremove != '+')
 823                fill_filespec(one, sha1, mode);
 824        if (addremove != '-')
 825                fill_filespec(two, sha1, mode);
 826
 827        diff_queue(&diff_queued_diff, one, two);
 828}
 829
 830void diff_helper_input(unsigned old_mode,
 831                       unsigned new_mode,
 832                       const unsigned char *old_sha1,
 833                       const unsigned char *new_sha1,
 834                       const char *old_path,
 835                       int status,
 836                       int score,
 837                       const char *new_path)
 838{
 839        struct diff_filespec *one, *two;
 840        struct diff_filepair *dp;
 841
 842        one = alloc_filespec(old_path);
 843        two = alloc_filespec(new_path);
 844        if (old_mode)
 845                fill_filespec(one, old_sha1, old_mode);
 846        if (new_mode)
 847                fill_filespec(two, new_sha1, new_mode);
 848        dp = diff_queue(&diff_queued_diff, one, two);
 849        dp->score = score;
 850        dp->status = status;
 851}
 852
 853void diff_change(unsigned old_mode, unsigned new_mode,
 854                 const unsigned char *old_sha1,
 855                 const unsigned char *new_sha1,
 856                 const char *base, const char *path) 
 857{
 858        char concatpath[PATH_MAX];
 859        struct diff_filespec *one, *two;
 860
 861        if (reverse_diff) {
 862                unsigned tmp;
 863                const unsigned char *tmp_c;
 864                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
 865                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
 866        }
 867        if (!path) path = "";
 868        sprintf(concatpath, "%s%s", base, path);
 869        one = alloc_filespec(concatpath);
 870        two = alloc_filespec(concatpath);
 871        fill_filespec(one, old_sha1, old_mode);
 872        fill_filespec(two, new_sha1, new_mode);
 873
 874        diff_queue(&diff_queued_diff, one, two);
 875}
 876
 877void diff_unmerge(const char *path)
 878{
 879        struct diff_filespec *one, *two;
 880        one = alloc_filespec(path);
 881        two = alloc_filespec(path);
 882        diff_queue(&diff_queued_diff, one, two);
 883}