diff-lib.con commit sha1_file.c: cleanup hdr usage (d65a16f)
   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
  12/*
  13 * diff-files
  14 */
  15
  16int run_diff_files(struct rev_info *revs, int silent_on_removed)
  17{
  18        int entries, i;
  19        int diff_unmerged_stage = revs->max_count;
  20
  21        if (diff_unmerged_stage < 0)
  22                diff_unmerged_stage = 2;
  23        entries = read_cache();
  24        if (entries < 0) {
  25                perror("read_cache");
  26                return -1;
  27        }
  28        for (i = 0; i < entries; i++) {
  29                struct stat st;
  30                unsigned int oldmode, newmode;
  31                struct cache_entry *ce = active_cache[i];
  32                int changed;
  33
  34                if (!ce_path_match(ce, revs->prune_data))
  35                        continue;
  36
  37                if (ce_stage(ce)) {
  38                        struct combine_diff_path *dpath;
  39                        int num_compare_stages = 0;
  40                        size_t path_len;
  41
  42                        path_len = ce_namelen(ce);
  43
  44                        dpath = xmalloc(combine_diff_path_size(5, path_len));
  45                        dpath->path = (char *) &(dpath->parent[5]);
  46
  47                        dpath->next = NULL;
  48                        dpath->len = path_len;
  49                        memcpy(dpath->path, ce->name, path_len);
  50                        dpath->path[path_len] = '\0';
  51                        hashclr(dpath->sha1);
  52                        memset(&(dpath->parent[0]), 0,
  53                               sizeof(struct combine_diff_parent)*5);
  54
  55                        if (lstat(ce->name, &st) < 0) {
  56                                if (errno != ENOENT && errno != ENOTDIR) {
  57                                        perror(ce->name);
  58                                        continue;
  59                                }
  60                                if (silent_on_removed)
  61                                        continue;
  62                        }
  63                        else
  64                                dpath->mode = canon_mode(st.st_mode);
  65
  66                        while (i < entries) {
  67                                struct cache_entry *nce = active_cache[i];
  68                                int stage;
  69
  70                                if (strcmp(ce->name, nce->name))
  71                                        break;
  72
  73                                /* Stage #2 (ours) is the first parent,
  74                                 * stage #3 (theirs) is the second.
  75                                 */
  76                                stage = ce_stage(nce);
  77                                if (2 <= stage) {
  78                                        int mode = ntohl(nce->ce_mode);
  79                                        num_compare_stages++;
  80                                        hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
  81                                        dpath->parent[stage-2].mode =
  82                                                canon_mode(mode);
  83                                        dpath->parent[stage-2].status =
  84                                                DIFF_STATUS_MODIFIED;
  85                                }
  86
  87                                /* diff against the proper unmerged stage */
  88                                if (stage == diff_unmerged_stage)
  89                                        ce = nce;
  90                                i++;
  91                        }
  92                        /*
  93                         * Compensate for loop update
  94                         */
  95                        i--;
  96
  97                        if (revs->combine_merges && num_compare_stages == 2) {
  98                                show_combined_diff(dpath, 2,
  99                                                   revs->dense_combined_merges,
 100                                                   revs);
 101                                free(dpath);
 102                                continue;
 103                        }
 104                        free(dpath);
 105                        dpath = NULL;
 106
 107                        /*
 108                         * Show the diff for the 'ce' if we found the one
 109                         * from the desired stage.
 110                         */
 111                        diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
 112                        if (ce_stage(ce) != diff_unmerged_stage)
 113                                continue;
 114                }
 115
 116                if (lstat(ce->name, &st) < 0) {
 117                        if (errno != ENOENT && errno != ENOTDIR) {
 118                                perror(ce->name);
 119                                continue;
 120                        }
 121                        if (silent_on_removed)
 122                                continue;
 123                        diff_addremove(&revs->diffopt, '-', ntohl(ce->ce_mode),
 124                                       ce->sha1, ce->name, NULL);
 125                        continue;
 126                }
 127                changed = ce_match_stat(ce, &st, 0);
 128                if (!changed && !revs->diffopt.find_copies_harder)
 129                        continue;
 130                oldmode = ntohl(ce->ce_mode);
 131
 132                newmode = canon_mode(st.st_mode);
 133                if (!trust_executable_bit &&
 134                    S_ISREG(newmode) && S_ISREG(oldmode) &&
 135                    ((newmode ^ oldmode) == 0111))
 136                        newmode = oldmode;
 137                diff_change(&revs->diffopt, oldmode, newmode,
 138                            ce->sha1, (changed ? null_sha1 : ce->sha1),
 139                            ce->name, NULL);
 140
 141        }
 142        diffcore_std(&revs->diffopt);
 143        diff_flush(&revs->diffopt);
 144        return 0;
 145}
 146
 147/*
 148 * diff-index
 149 */
 150
 151/* A file entry went away or appeared */
 152static void diff_index_show_file(struct rev_info *revs,
 153                                 const char *prefix,
 154                                 struct cache_entry *ce,
 155                                 unsigned char *sha1, unsigned int mode)
 156{
 157        diff_addremove(&revs->diffopt, prefix[0], ntohl(mode),
 158                       sha1, ce->name, NULL);
 159}
 160
 161static int get_stat_data(struct cache_entry *ce,
 162                         unsigned char **sha1p,
 163                         unsigned int *modep,
 164                         int cached, int match_missing)
 165{
 166        unsigned char *sha1 = ce->sha1;
 167        unsigned int mode = ce->ce_mode;
 168
 169        if (!cached) {
 170                static unsigned char no_sha1[20];
 171                int changed;
 172                struct stat st;
 173                if (lstat(ce->name, &st) < 0) {
 174                        if (errno == ENOENT && match_missing) {
 175                                *sha1p = sha1;
 176                                *modep = mode;
 177                                return 0;
 178                        }
 179                        return -1;
 180                }
 181                changed = ce_match_stat(ce, &st, 0);
 182                if (changed) {
 183                        mode = ce_mode_from_stat(ce, st.st_mode);
 184                        sha1 = no_sha1;
 185                }
 186        }
 187
 188        *sha1p = sha1;
 189        *modep = mode;
 190        return 0;
 191}
 192
 193static void show_new_file(struct rev_info *revs,
 194                          struct cache_entry *new,
 195                          int cached, int match_missing)
 196{
 197        unsigned char *sha1;
 198        unsigned int mode;
 199
 200        /* New file in the index: it might actually be different in
 201         * the working copy.
 202         */
 203        if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
 204                return;
 205
 206        diff_index_show_file(revs, "+", new, sha1, mode);
 207}
 208
 209static int show_modified(struct rev_info *revs,
 210                         struct cache_entry *old,
 211                         struct cache_entry *new,
 212                         int report_missing,
 213                         int cached, int match_missing)
 214{
 215        unsigned int mode, oldmode;
 216        unsigned char *sha1;
 217
 218        if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
 219                if (report_missing)
 220                        diff_index_show_file(revs, "-", old,
 221                                             old->sha1, old->ce_mode);
 222                return -1;
 223        }
 224
 225        if (revs->combine_merges && !cached &&
 226            (hashcmp(sha1, old->sha1) || hashcmp(old->sha1, new->sha1))) {
 227                struct combine_diff_path *p;
 228                int pathlen = ce_namelen(new);
 229
 230                p = xmalloc(combine_diff_path_size(2, pathlen));
 231                p->path = (char *) &p->parent[2];
 232                p->next = NULL;
 233                p->len = pathlen;
 234                memcpy(p->path, new->name, pathlen);
 235                p->path[pathlen] = 0;
 236                p->mode = ntohl(mode);
 237                hashclr(p->sha1);
 238                memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
 239                p->parent[0].status = DIFF_STATUS_MODIFIED;
 240                p->parent[0].mode = ntohl(new->ce_mode);
 241                hashcpy(p->parent[0].sha1, new->sha1);
 242                p->parent[1].status = DIFF_STATUS_MODIFIED;
 243                p->parent[1].mode = ntohl(old->ce_mode);
 244                hashcpy(p->parent[1].sha1, old->sha1);
 245                show_combined_diff(p, 2, revs->dense_combined_merges, revs);
 246                free(p);
 247                return 0;
 248        }
 249
 250        oldmode = old->ce_mode;
 251        if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
 252            !revs->diffopt.find_copies_harder)
 253                return 0;
 254
 255        mode = ntohl(mode);
 256        oldmode = ntohl(oldmode);
 257
 258        diff_change(&revs->diffopt, oldmode, mode,
 259                    old->sha1, sha1, old->name, NULL);
 260        return 0;
 261}
 262
 263static int diff_cache(struct rev_info *revs,
 264                      struct cache_entry **ac, int entries,
 265                      const char **pathspec,
 266                      int cached, int match_missing)
 267{
 268        while (entries) {
 269                struct cache_entry *ce = *ac;
 270                int same = (entries > 1) && ce_same_name(ce, ac[1]);
 271
 272                if (!ce_path_match(ce, pathspec))
 273                        goto skip_entry;
 274
 275                switch (ce_stage(ce)) {
 276                case 0:
 277                        /* No stage 1 entry? That means it's a new file */
 278                        if (!same) {
 279                                show_new_file(revs, ce, cached, match_missing);
 280                                break;
 281                        }
 282                        /* Show difference between old and new */
 283                        show_modified(revs, ac[1], ce, 1,
 284                                      cached, match_missing);
 285                        break;
 286                case 1:
 287                        /* No stage 3 (merge) entry?
 288                         * That means it's been deleted.
 289                         */
 290                        if (!same) {
 291                                diff_index_show_file(revs, "-", ce,
 292                                                     ce->sha1, ce->ce_mode);
 293                                break;
 294                        }
 295                        /* We come here with ce pointing at stage 1
 296                         * (original tree) and ac[1] pointing at stage
 297                         * 3 (unmerged).  show-modified with
 298                         * report-missing set to false does not say the
 299                         * file is deleted but reports true if work
 300                         * tree does not have it, in which case we
 301                         * fall through to report the unmerged state.
 302                         * Otherwise, we show the differences between
 303                         * the original tree and the work tree.
 304                         */
 305                        if (!cached &&
 306                            !show_modified(revs, ce, ac[1], 0,
 307                                           cached, match_missing))
 308                                break;
 309                        diff_unmerge(&revs->diffopt, ce->name,
 310                                     ntohl(ce->ce_mode), ce->sha1);
 311                        break;
 312                case 3:
 313                        diff_unmerge(&revs->diffopt, ce->name,
 314                                     0, null_sha1);
 315                        break;
 316
 317                default:
 318                        die("impossible cache entry stage");
 319                }
 320
 321skip_entry:
 322                /*
 323                 * Ignore all the different stages for this file,
 324                 * we've handled the relevant cases now.
 325                 */
 326                do {
 327                        ac++;
 328                        entries--;
 329                } while (entries && ce_same_name(ce, ac[0]));
 330        }
 331        return 0;
 332}
 333
 334/*
 335 * This turns all merge entries into "stage 3". That guarantees that
 336 * when we read in the new tree (into "stage 1"), we won't lose sight
 337 * of the fact that we had unmerged entries.
 338 */
 339static void mark_merge_entries(void)
 340{
 341        int i;
 342        for (i = 0; i < active_nr; i++) {
 343                struct cache_entry *ce = active_cache[i];
 344                if (!ce_stage(ce))
 345                        continue;
 346                ce->ce_flags |= htons(CE_STAGEMASK);
 347        }
 348}
 349
 350int run_diff_index(struct rev_info *revs, int cached)
 351{
 352        int ret;
 353        struct object *ent;
 354        struct tree *tree;
 355        const char *tree_name;
 356        int match_missing = 0;
 357
 358        /* 
 359         * Backward compatibility wart - "diff-index -m" does
 360         * not mean "do not ignore merges", but totally different.
 361         */
 362        if (!revs->ignore_merges)
 363                match_missing = 1;
 364
 365        if (read_cache() < 0) {
 366                perror("read_cache");
 367                return -1;
 368        }
 369        mark_merge_entries();
 370
 371        ent = revs->pending.objects[0].item;
 372        tree_name = revs->pending.objects[0].name;
 373        tree = parse_tree_indirect(ent->sha1);
 374        if (!tree)
 375                return error("bad tree object %s", tree_name);
 376        if (read_tree(tree, 1, revs->prune_data))
 377                return error("unable to read tree object %s", tree_name);
 378        ret = diff_cache(revs, active_cache, active_nr, revs->prune_data,
 379                         cached, match_missing);
 380        diffcore_std(&revs->diffopt);
 381        diff_flush(&revs->diffopt);
 382        return ret;
 383}
 384
 385int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
 386{
 387        struct tree *tree;
 388        struct rev_info revs;
 389        int i;
 390        struct cache_entry **dst;
 391        struct cache_entry *last = NULL;
 392
 393        /*
 394         * This is used by git-blame to run diff-cache internally;
 395         * it potentially needs to repeatedly run this, so we will
 396         * start by removing the higher order entries the last round
 397         * left behind.
 398         */
 399        dst = active_cache;
 400        for (i = 0; i < active_nr; i++) {
 401                struct cache_entry *ce = active_cache[i];
 402                if (ce_stage(ce)) {
 403                        if (last && !strcmp(ce->name, last->name))
 404                                continue;
 405                        cache_tree_invalidate_path(active_cache_tree,
 406                                                   ce->name);
 407                        last = ce;
 408                        ce->ce_mode = 0;
 409                        ce->ce_flags &= ~htons(CE_STAGEMASK);
 410                }
 411                *dst++ = ce;
 412        }
 413        active_nr = dst - active_cache;
 414
 415        init_revisions(&revs, NULL);
 416        revs.prune_data = opt->paths;
 417        tree = parse_tree_indirect(tree_sha1);
 418        if (!tree)
 419                die("bad tree object %s", sha1_to_hex(tree_sha1));
 420        if (read_tree(tree, 1, opt->paths))
 421                return error("unable to read tree %s", sha1_to_hex(tree_sha1));
 422        return diff_cache(&revs, active_cache, active_nr, revs.prune_data,
 423                          1, 0);
 424}