diff-lib.con commit add storage size output to 'git verify-pack -v' (5f4347b)
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "quote.h"
   6#include "commit.h"
   7#include "diff.h"
   8#include "diffcore.h"
   9#include "revision.h"
  10#include "cache-tree.h"
  11#include "path-list.h"
  12#include "unpack-trees.h"
  13
  14/*
  15 * diff-files
  16 */
  17
  18static int read_directory(const char *path, struct path_list *list)
  19{
  20        DIR *dir;
  21        struct dirent *e;
  22
  23        if (!(dir = opendir(path)))
  24                return error("Could not open directory %s", path);
  25
  26        while ((e = readdir(dir)))
  27                if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
  28                        path_list_insert(e->d_name, list);
  29
  30        closedir(dir);
  31        return 0;
  32}
  33
  34static int get_mode(const char *path, int *mode)
  35{
  36        struct stat st;
  37
  38        if (!path || !strcmp(path, "/dev/null"))
  39                *mode = 0;
  40        else if (!strcmp(path, "-"))
  41                *mode = create_ce_mode(0666);
  42        else if (stat(path, &st))
  43                return error("Could not access '%s'", path);
  44        else
  45                *mode = st.st_mode;
  46        return 0;
  47}
  48
  49static int queue_diff(struct diff_options *o,
  50                const char *name1, const char *name2)
  51{
  52        int mode1 = 0, mode2 = 0;
  53
  54        if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
  55                return -1;
  56
  57        if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
  58                return error("file/directory conflict: %s, %s", name1, name2);
  59
  60        if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
  61                char buffer1[PATH_MAX], buffer2[PATH_MAX];
  62                struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
  63                int len1 = 0, len2 = 0, i1, i2, ret = 0;
  64
  65                if (name1 && read_directory(name1, &p1))
  66                        return -1;
  67                if (name2 && read_directory(name2, &p2)) {
  68                        path_list_clear(&p1, 0);
  69                        return -1;
  70                }
  71
  72                if (name1) {
  73                        len1 = strlen(name1);
  74                        if (len1 > 0 && name1[len1 - 1] == '/')
  75                                len1--;
  76                        memcpy(buffer1, name1, len1);
  77                        buffer1[len1++] = '/';
  78                }
  79
  80                if (name2) {
  81                        len2 = strlen(name2);
  82                        if (len2 > 0 && name2[len2 - 1] == '/')
  83                                len2--;
  84                        memcpy(buffer2, name2, len2);
  85                        buffer2[len2++] = '/';
  86                }
  87
  88                for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
  89                        const char *n1, *n2;
  90                        int comp;
  91
  92                        if (i1 == p1.nr)
  93                                comp = 1;
  94                        else if (i2 == p2.nr)
  95                                comp = -1;
  96                        else
  97                                comp = strcmp(p1.items[i1].path,
  98                                        p2.items[i2].path);
  99
 100                        if (comp > 0)
 101                                n1 = NULL;
 102                        else {
 103                                n1 = buffer1;
 104                                strncpy(buffer1 + len1, p1.items[i1++].path,
 105                                                PATH_MAX - len1);
 106                        }
 107
 108                        if (comp < 0)
 109                                n2 = NULL;
 110                        else {
 111                                n2 = buffer2;
 112                                strncpy(buffer2 + len2, p2.items[i2++].path,
 113                                                PATH_MAX - len2);
 114                        }
 115
 116                        ret = queue_diff(o, n1, n2);
 117                }
 118                path_list_clear(&p1, 0);
 119                path_list_clear(&p2, 0);
 120
 121                return ret;
 122        } else {
 123                struct diff_filespec *d1, *d2;
 124
 125                if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
 126                        unsigned tmp;
 127                        const char *tmp_c;
 128                        tmp = mode1; mode1 = mode2; mode2 = tmp;
 129                        tmp_c = name1; name1 = name2; name2 = tmp_c;
 130                }
 131
 132                if (!name1)
 133                        name1 = "/dev/null";
 134                if (!name2)
 135                        name2 = "/dev/null";
 136                d1 = alloc_filespec(name1);
 137                d2 = alloc_filespec(name2);
 138                fill_filespec(d1, null_sha1, mode1);
 139                fill_filespec(d2, null_sha1, mode2);
 140
 141                diff_queue(&diff_queued_diff, d1, d2);
 142                return 0;
 143        }
 144}
 145
 146/*
 147 * Does the path name a blob in the working tree, or a directory
 148 * in the working tree?
 149 */
 150static int is_in_index(const char *path)
 151{
 152        int len, pos;
 153        struct cache_entry *ce;
 154
 155        len = strlen(path);
 156        while (path[len-1] == '/')
 157                len--;
 158        if (!len)
 159                return 1; /* "." */
 160        pos = cache_name_pos(path, len);
 161        if (0 <= pos)
 162                return 1;
 163        pos = -1 - pos;
 164        while (pos < active_nr) {
 165                ce = active_cache[pos++];
 166                if (ce_namelen(ce) <= len ||
 167                    strncmp(ce->name, path, len) ||
 168                    (ce->name[len] > '/'))
 169                        break; /* path cannot be a prefix */
 170                if (ce->name[len] == '/')
 171                        return 1;
 172        }
 173        return 0;
 174}
 175
 176static int handle_diff_files_args(struct rev_info *revs,
 177                                  int argc, const char **argv,
 178                                  unsigned int *options)
 179{
 180        *options = 0;
 181
 182        /* revs->max_count == -2 means --no-index */
 183        while (1 < argc && argv[1][0] == '-') {
 184                if (!strcmp(argv[1], "--base"))
 185                        revs->max_count = 1;
 186                else if (!strcmp(argv[1], "--ours"))
 187                        revs->max_count = 2;
 188                else if (!strcmp(argv[1], "--theirs"))
 189                        revs->max_count = 3;
 190                else if (!strcmp(argv[1], "-n") ||
 191                                !strcmp(argv[1], "--no-index")) {
 192                        revs->max_count = -2;
 193                        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
 194                        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 195                }
 196                else if (!strcmp(argv[1], "-q"))
 197                        *options |= DIFF_SILENT_ON_REMOVED;
 198                else
 199                        return error("invalid option: %s", argv[1]);
 200                argv++; argc--;
 201        }
 202
 203        if (revs->max_count == -1 && revs->diffopt.nr_paths == 2) {
 204                /*
 205                 * If two files are specified, and at least one is untracked,
 206                 * default to no-index.
 207                 */
 208                read_cache();
 209                if (!is_in_index(revs->diffopt.paths[0]) ||
 210                                        !is_in_index(revs->diffopt.paths[1])) {
 211                        revs->max_count = -2;
 212                        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 213                }
 214        }
 215
 216        /*
 217         * Make sure there are NO revision (i.e. pending object) parameter,
 218         * rev.max_count is reasonable (0 <= n <= 3),
 219         * there is no other revision filtering parameters.
 220         */
 221        if (revs->pending.nr || revs->max_count > 3 ||
 222            revs->min_age != -1 || revs->max_age != -1)
 223                return error("no revision allowed with diff-files");
 224
 225        if (revs->max_count == -1 &&
 226            (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
 227                revs->combine_merges = revs->dense_combined_merges = 1;
 228
 229        return 0;
 230}
 231
 232static int is_outside_repo(const char *path, int nongit, const char *prefix)
 233{
 234        int i;
 235        if (nongit || !strcmp(path, "-") || is_absolute_path(path))
 236                return 1;
 237        if (prefixcmp(path, "../"))
 238                return 0;
 239        if (!prefix)
 240                return 1;
 241        for (i = strlen(prefix); !prefixcmp(path, "../"); ) {
 242                while (i > 0 && prefix[i - 1] != '/')
 243                        i--;
 244                if (--i < 0)
 245                        return 1;
 246                path += 3;
 247        }
 248        return 0;
 249}
 250
 251int setup_diff_no_index(struct rev_info *revs,
 252                int argc, const char ** argv, int nongit, const char *prefix)
 253{
 254        int i;
 255        for (i = 1; i < argc; i++)
 256                if (argv[i][0] != '-' || argv[i][1] == '\0')
 257                        break;
 258                else if (!strcmp(argv[i], "--")) {
 259                        i++;
 260                        break;
 261                } else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
 262                        i = argc - 3;
 263                        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
 264                        break;
 265                }
 266        if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
 267                                !is_outside_repo(argv[i], nongit, prefix)))
 268                return -1;
 269
 270        diff_setup(&revs->diffopt);
 271        for (i = 1; i < argc - 2; )
 272                if (!strcmp(argv[i], "--no-index"))
 273                        i++;
 274                else {
 275                        int j = diff_opt_parse(&revs->diffopt,
 276                                        argv + i, argc - i);
 277                        if (!j)
 278                                die("invalid diff option/value: %s", argv[i]);
 279                        i += j;
 280                }
 281
 282        if (prefix) {
 283                int len = strlen(prefix);
 284
 285                revs->diffopt.paths = xcalloc(2, sizeof(char*));
 286                for (i = 0; i < 2; i++) {
 287                        const char *p = argv[argc - 2 + i];
 288                        /*
 289                         * stdin should be spelled as '-'; if you have
 290                         * path that is '-', spell it as ./-.
 291                         */
 292                        p = (strcmp(p, "-")
 293                             ? xstrdup(prefix_filename(prefix, len, p))
 294                             : p);
 295                        revs->diffopt.paths[i] = p;
 296                }
 297        }
 298        else
 299                revs->diffopt.paths = argv + argc - 2;
 300        revs->diffopt.nr_paths = 2;
 301        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 302        revs->max_count = -2;
 303        if (diff_setup_done(&revs->diffopt) < 0)
 304                die("diff_setup_done failed");
 305        return 0;
 306}
 307
 308int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
 309{
 310        unsigned int options;
 311
 312        if (handle_diff_files_args(revs, argc, argv, &options))
 313                return -1;
 314
 315        if (DIFF_OPT_TST(&revs->diffopt, NO_INDEX)) {
 316                if (revs->diffopt.nr_paths != 2)
 317                        return error("need two files/directories with --no-index");
 318                if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
 319                                revs->diffopt.paths[1]))
 320                        return -1;
 321                diffcore_std(&revs->diffopt);
 322                diff_flush(&revs->diffopt);
 323                /*
 324                 * The return code for --no-index imitates diff(1):
 325                 * 0 = no changes, 1 = changes, else error
 326                 */
 327                return revs->diffopt.found_changes;
 328        }
 329
 330        if (read_cache() < 0) {
 331                perror("read_cache");
 332                return -1;
 333        }
 334        return run_diff_files(revs, options);
 335}
 336
 337int run_diff_files(struct rev_info *revs, unsigned int option)
 338{
 339        int entries, i;
 340        int diff_unmerged_stage = revs->max_count;
 341        int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
 342        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
 343                              ? CE_MATCH_RACY_IS_DIRTY : 0);
 344
 345        if (diff_unmerged_stage < 0)
 346                diff_unmerged_stage = 2;
 347        entries = active_nr;
 348        for (i = 0; i < entries; i++) {
 349                struct stat st;
 350                unsigned int oldmode, newmode;
 351                struct cache_entry *ce = active_cache[i];
 352                int changed;
 353
 354                if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
 355                        DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
 356                        break;
 357
 358                if (!ce_path_match(ce, revs->prune_data))
 359                        continue;
 360
 361                if (ce_stage(ce)) {
 362                        struct combine_diff_path *dpath;
 363                        int num_compare_stages = 0;
 364                        size_t path_len;
 365
 366                        path_len = ce_namelen(ce);
 367
 368                        dpath = xmalloc(combine_diff_path_size(5, path_len));
 369                        dpath->path = (char *) &(dpath->parent[5]);
 370
 371                        dpath->next = NULL;
 372                        dpath->len = path_len;
 373                        memcpy(dpath->path, ce->name, path_len);
 374                        dpath->path[path_len] = '\0';
 375                        hashclr(dpath->sha1);
 376                        memset(&(dpath->parent[0]), 0,
 377                               sizeof(struct combine_diff_parent)*5);
 378
 379                        if (lstat(ce->name, &st) < 0) {
 380                                if (errno != ENOENT && errno != ENOTDIR) {
 381                                        perror(ce->name);
 382                                        continue;
 383                                }
 384                                if (silent_on_removed)
 385                                        continue;
 386                        }
 387                        else
 388                                dpath->mode = ce_mode_from_stat(ce, st.st_mode);
 389
 390                        while (i < entries) {
 391                                struct cache_entry *nce = active_cache[i];
 392                                int stage;
 393
 394                                if (strcmp(ce->name, nce->name))
 395                                        break;
 396
 397                                /* Stage #2 (ours) is the first parent,
 398                                 * stage #3 (theirs) is the second.
 399                                 */
 400                                stage = ce_stage(nce);
 401                                if (2 <= stage) {
 402                                        int mode = nce->ce_mode;
 403                                        num_compare_stages++;
 404                                        hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
 405                                        dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
 406                                        dpath->parent[stage-2].status =
 407                                                DIFF_STATUS_MODIFIED;
 408                                }
 409
 410                                /* diff against the proper unmerged stage */
 411                                if (stage == diff_unmerged_stage)
 412                                        ce = nce;
 413                                i++;
 414                        }
 415                        /*
 416                         * Compensate for loop update
 417                         */
 418                        i--;
 419
 420                        if (revs->combine_merges && num_compare_stages == 2) {
 421                                show_combined_diff(dpath, 2,
 422                                                   revs->dense_combined_merges,
 423                                                   revs);
 424                                free(dpath);
 425                                continue;
 426                        }
 427                        free(dpath);
 428                        dpath = NULL;
 429
 430                        /*
 431                         * Show the diff for the 'ce' if we found the one
 432                         * from the desired stage.
 433                         */
 434                        diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
 435                        if (ce_stage(ce) != diff_unmerged_stage)
 436                                continue;
 437                }
 438
 439                if (ce_uptodate(ce))
 440                        continue;
 441                if (lstat(ce->name, &st) < 0) {
 442                        if (errno != ENOENT && errno != ENOTDIR) {
 443                                perror(ce->name);
 444                                continue;
 445                        }
 446                        if (silent_on_removed)
 447                                continue;
 448                        diff_addremove(&revs->diffopt, '-', ce->ce_mode,
 449                                       ce->sha1, ce->name, NULL);
 450                        continue;
 451                }
 452                changed = ce_match_stat(ce, &st, ce_option);
 453                if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
 454                        continue;
 455                oldmode = ce->ce_mode;
 456                newmode = ce_mode_from_stat(ce, st.st_mode);
 457                diff_change(&revs->diffopt, oldmode, newmode,
 458                            ce->sha1, (changed ? null_sha1 : ce->sha1),
 459                            ce->name, NULL);
 460
 461        }
 462        diffcore_std(&revs->diffopt);
 463        diff_flush(&revs->diffopt);
 464        return 0;
 465}
 466
 467/*
 468 * diff-index
 469 */
 470
 471/* A file entry went away or appeared */
 472static void diff_index_show_file(struct rev_info *revs,
 473                                 const char *prefix,
 474                                 struct cache_entry *ce,
 475                                 unsigned char *sha1, unsigned int mode)
 476{
 477        diff_addremove(&revs->diffopt, prefix[0], mode,
 478                       sha1, ce->name, NULL);
 479}
 480
 481static int get_stat_data(struct cache_entry *ce,
 482                         unsigned char **sha1p,
 483                         unsigned int *modep,
 484                         int cached, int match_missing)
 485{
 486        unsigned char *sha1 = ce->sha1;
 487        unsigned int mode = ce->ce_mode;
 488
 489        if (!cached) {
 490                static unsigned char no_sha1[20];
 491                int changed;
 492                struct stat st;
 493                if (lstat(ce->name, &st) < 0) {
 494                        if (errno == ENOENT && match_missing) {
 495                                *sha1p = sha1;
 496                                *modep = mode;
 497                                return 0;
 498                        }
 499                        return -1;
 500                }
 501                changed = ce_match_stat(ce, &st, 0);
 502                if (changed) {
 503                        mode = ce_mode_from_stat(ce, st.st_mode);
 504                        sha1 = no_sha1;
 505                }
 506        }
 507
 508        *sha1p = sha1;
 509        *modep = mode;
 510        return 0;
 511}
 512
 513static void show_new_file(struct rev_info *revs,
 514                          struct cache_entry *new,
 515                          int cached, int match_missing)
 516{
 517        unsigned char *sha1;
 518        unsigned int mode;
 519
 520        /* New file in the index: it might actually be different in
 521         * the working copy.
 522         */
 523        if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
 524                return;
 525
 526        diff_index_show_file(revs, "+", new, sha1, mode);
 527}
 528
 529static int show_modified(struct rev_info *revs,
 530                         struct cache_entry *old,
 531                         struct cache_entry *new,
 532                         int report_missing,
 533                         int cached, int match_missing)
 534{
 535        unsigned int mode, oldmode;
 536        unsigned char *sha1;
 537
 538        if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
 539                if (report_missing)
 540                        diff_index_show_file(revs, "-", old,
 541                                             old->sha1, old->ce_mode);
 542                return -1;
 543        }
 544
 545        if (revs->combine_merges && !cached &&
 546            (hashcmp(sha1, old->sha1) || hashcmp(old->sha1, new->sha1))) {
 547                struct combine_diff_path *p;
 548                int pathlen = ce_namelen(new);
 549
 550                p = xmalloc(combine_diff_path_size(2, pathlen));
 551                p->path = (char *) &p->parent[2];
 552                p->next = NULL;
 553                p->len = pathlen;
 554                memcpy(p->path, new->name, pathlen);
 555                p->path[pathlen] = 0;
 556                p->mode = mode;
 557                hashclr(p->sha1);
 558                memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
 559                p->parent[0].status = DIFF_STATUS_MODIFIED;
 560                p->parent[0].mode = new->ce_mode;
 561                hashcpy(p->parent[0].sha1, new->sha1);
 562                p->parent[1].status = DIFF_STATUS_MODIFIED;
 563                p->parent[1].mode = old->ce_mode;
 564                hashcpy(p->parent[1].sha1, old->sha1);
 565                show_combined_diff(p, 2, revs->dense_combined_merges, revs);
 566                free(p);
 567                return 0;
 568        }
 569
 570        oldmode = old->ce_mode;
 571        if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
 572            !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
 573                return 0;
 574
 575        diff_change(&revs->diffopt, oldmode, mode,
 576                    old->sha1, sha1, old->name, NULL);
 577        return 0;
 578}
 579
 580/*
 581 * This turns all merge entries into "stage 3". That guarantees that
 582 * when we read in the new tree (into "stage 1"), we won't lose sight
 583 * of the fact that we had unmerged entries.
 584 */
 585static void mark_merge_entries(void)
 586{
 587        int i;
 588        for (i = 0; i < active_nr; i++) {
 589                struct cache_entry *ce = active_cache[i];
 590                if (!ce_stage(ce))
 591                        continue;
 592                ce->ce_flags |= CE_STAGEMASK;
 593        }
 594}
 595
 596/*
 597 * This gets a mix of an existing index and a tree, one pathname entry
 598 * at a time. The index entry may be a single stage-0 one, but it could
 599 * also be multiple unmerged entries (in which case idx_pos/idx_nr will
 600 * give you the position and number of entries in the index).
 601 */
 602static void do_oneway_diff(struct unpack_trees_options *o,
 603        struct cache_entry *idx,
 604        struct cache_entry *tree,
 605        int idx_pos, int idx_nr)
 606{
 607        struct rev_info *revs = o->unpack_data;
 608        int match_missing, cached;
 609
 610        /*
 611         * Backward compatibility wart - "diff-index -m" does
 612         * not mean "do not ignore merges", but "match_missing".
 613         *
 614         * But with the revision flag parsing, that's found in
 615         * "!revs->ignore_merges".
 616         */
 617        cached = o->index_only;
 618        match_missing = !revs->ignore_merges;
 619
 620        if (cached && idx && ce_stage(idx)) {
 621                if (tree)
 622                        diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
 623                return;
 624        }
 625
 626        /*
 627         * Something added to the tree?
 628         */
 629        if (!tree) {
 630                show_new_file(revs, idx, cached, match_missing);
 631                return;
 632        }
 633
 634        /*
 635         * Something removed from the tree?
 636         */
 637        if (!idx) {
 638                diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode);
 639                return;
 640        }
 641
 642        /* Show difference between old and new */
 643        show_modified(revs, tree, idx, 1, cached, match_missing);
 644}
 645
 646/*
 647 * Count how many index entries go with the first one
 648 */
 649static inline int count_skip(const struct cache_entry *src, int pos)
 650{
 651        int skip = 1;
 652
 653        /* We can only have multiple entries if the first one is not stage-0 */
 654        if (ce_stage(src)) {
 655                struct cache_entry **p = active_cache + pos;
 656                int namelen = ce_namelen(src);
 657
 658                for (;;) {
 659                        const struct cache_entry *ce;
 660                        pos++;
 661                        if (pos >= active_nr)
 662                                break;
 663                        ce = *++p;
 664                        if (ce_namelen(ce) != namelen)
 665                                break;
 666                        if (memcmp(ce->name, src->name, namelen))
 667                                break;
 668                        skip++;
 669                }
 670        }
 671        return skip;
 672}
 673
 674/*
 675 * The unpack_trees() interface is designed for merging, so
 676 * the different source entries are designed primarily for
 677 * the source trees, with the old index being really mainly
 678 * used for being replaced by the result.
 679 *
 680 * For diffing, the index is more important, and we only have a
 681 * single tree.
 682 *
 683 * We're supposed to return how many index entries we want to skip.
 684 *
 685 * This wrapper makes it all more readable, and takes care of all
 686 * the fairly complex unpack_trees() semantic requirements, including
 687 * the skipping, the path matching, the type conflict cases etc.
 688 */
 689static int oneway_diff(struct cache_entry **src,
 690        struct unpack_trees_options *o,
 691        int index_pos)
 692{
 693        int skip = 0;
 694        struct cache_entry *idx = src[0];
 695        struct cache_entry *tree = src[1];
 696        struct rev_info *revs = o->unpack_data;
 697
 698        if (index_pos >= 0)
 699                skip = count_skip(idx, index_pos);
 700
 701        /*
 702         * Unpack-trees generates a DF/conflict entry if
 703         * there was a directory in the index and a tree
 704         * in the tree. From a diff standpoint, that's a
 705         * delete of the tree and a create of the file.
 706         */
 707        if (tree == o->df_conflict_entry)
 708                tree = NULL;
 709
 710        if (ce_path_match(idx ? idx : tree, revs->prune_data))
 711                do_oneway_diff(o, idx, tree, index_pos, skip);
 712
 713        return skip;
 714}
 715
 716int run_diff_index(struct rev_info *revs, int cached)
 717{
 718        struct object *ent;
 719        struct tree *tree;
 720        const char *tree_name;
 721        struct unpack_trees_options opts;
 722        struct tree_desc t;
 723
 724        mark_merge_entries();
 725
 726        ent = revs->pending.objects[0].item;
 727        tree_name = revs->pending.objects[0].name;
 728        tree = parse_tree_indirect(ent->sha1);
 729        if (!tree)
 730                return error("bad tree object %s", tree_name);
 731
 732        memset(&opts, 0, sizeof(opts));
 733        opts.head_idx = 1;
 734        opts.index_only = cached;
 735        opts.merge = 1;
 736        opts.fn = oneway_diff;
 737        opts.unpack_data = revs;
 738
 739        init_tree_desc(&t, tree->buffer, tree->size);
 740        if (unpack_trees(1, &t, &opts))
 741                exit(128);
 742
 743        diffcore_std(&revs->diffopt);
 744        diff_flush(&revs->diffopt);
 745        return 0;
 746}
 747
 748int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
 749{
 750        struct tree *tree;
 751        struct rev_info revs;
 752        int i;
 753        struct cache_entry **dst;
 754        struct cache_entry *last = NULL;
 755        struct unpack_trees_options opts;
 756        struct tree_desc t;
 757
 758        /*
 759         * This is used by git-blame to run diff-cache internally;
 760         * it potentially needs to repeatedly run this, so we will
 761         * start by removing the higher order entries the last round
 762         * left behind.
 763         */
 764        dst = active_cache;
 765        for (i = 0; i < active_nr; i++) {
 766                struct cache_entry *ce = active_cache[i];
 767                if (ce_stage(ce)) {
 768                        if (last && !strcmp(ce->name, last->name))
 769                                continue;
 770                        cache_tree_invalidate_path(active_cache_tree,
 771                                                   ce->name);
 772                        last = ce;
 773                        ce->ce_flags |= CE_REMOVE;
 774                }
 775                *dst++ = ce;
 776        }
 777        active_nr = dst - active_cache;
 778
 779        init_revisions(&revs, NULL);
 780        revs.prune_data = opt->paths;
 781        tree = parse_tree_indirect(tree_sha1);
 782        if (!tree)
 783                die("bad tree object %s", sha1_to_hex(tree_sha1));
 784
 785        memset(&opts, 0, sizeof(opts));
 786        opts.head_idx = 1;
 787        opts.index_only = 1;
 788        opts.merge = 1;
 789        opts.fn = oneway_diff;
 790        opts.unpack_data = &revs;
 791
 792        init_tree_desc(&t, tree->buffer, tree->size);
 793        if (unpack_trees(1, &t, &opts))
 794                exit(128);
 795        return 0;
 796}