2f04d1eb9d9569b18b77220398f3a340d3352bf9
   1#include "cache.h"
   2
   3struct tree_entry;
   4
   5static struct tree_entry *update_tree_entry(void **bufp, unsigned long *sizep)
   6{
   7        void *buf = *bufp;
   8        unsigned long size = *sizep;
   9        int len = strlen(buf) + 1 + 20;
  10
  11        if (size < len)
  12                usage("corrupt tree file");
  13        *bufp = buf + len;
  14        *sizep = size - len;
  15        return buf;
  16}
  17
  18static const unsigned char *extract(void *tree, unsigned long size, const char **pathp, unsigned int *modep)
  19{
  20        int len = strlen(tree)+1;
  21        const unsigned char *sha1 = tree + len;
  22        const char *path = strchr(tree, ' ');
  23
  24        if (!path || size < len + 20 || sscanf(tree, "%o", modep) != 1)
  25                usage("corrupt tree file");
  26        *pathp = path+1;
  27        return sha1;
  28}
  29
  30static void show_file(const char *prefix, void *tree, unsigned long size)
  31{
  32        unsigned mode;
  33        const char *path;
  34        const unsigned char *sha1 = extract(tree, size, &path, &mode);
  35        printf("%s%o %s %s%c", prefix, mode, sha1_to_hex(sha1), path, 0);
  36}
  37
  38static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2)
  39{
  40        unsigned mode1, mode2;
  41        const char *path1, *path2;
  42        const unsigned char *sha1, *sha2;
  43        int cmp;
  44
  45        sha1 = extract(tree1, size1, &path1, &mode1);
  46        sha2 = extract(tree2, size2, &path2, &mode2);
  47
  48        cmp = cache_name_compare(path1, strlen(path1), path2, strlen(path2));
  49        if (cmp < 0) {
  50                show_file("-", tree1, size1);
  51                return -1;
  52        }
  53        if (cmp > 0) {
  54                show_file("+", tree2, size2);
  55                return 1;
  56        }
  57        if (!memcmp(sha1, sha2, 20) && mode1 == mode2)
  58                return 0;
  59        show_file("<", tree1, size1);
  60        show_file(">", tree2, size2);
  61        return 0;
  62}
  63
  64static int diff_tree(void *tree1, unsigned long size1, void *tree2, unsigned long size2)
  65{
  66        while (size1 | size2) {
  67                if (!size1) {
  68                        show_file("+", tree2, size2);
  69                        update_tree_entry(&tree2, &size2);
  70                        continue;
  71                }
  72                if (!size2) {
  73                        show_file("-", tree1, size1);
  74                        update_tree_entry(&tree1, &size1);
  75                        continue;
  76                }
  77                switch (compare_tree_entry(tree1, size1, tree2, size2)) {
  78                case -1:
  79                        update_tree_entry(&tree1, &size1);
  80                        continue;
  81                case 0:
  82                        update_tree_entry(&tree1, &size1);
  83                        /* Fallthrough */
  84                case 1:
  85                        update_tree_entry(&tree2, &size2);
  86                        continue;
  87                }
  88                usage("diff-tree: internal error");
  89        }
  90        return 0;
  91}
  92
  93int main(int argc, char **argv)
  94{
  95        unsigned char old[20], new[20];
  96        void *tree1, *tree2;
  97        unsigned long size1, size2;
  98        char type[20];
  99
 100        if (argc != 3 || get_sha1_hex(argv[1], old) || get_sha1_hex(argv[2], new))
 101                usage("diff-tree <tree sha1> <tree sha1>");
 102        tree1 = read_sha1_file(old, type, &size1);
 103        if (!tree1 || strcmp(type, "tree"))
 104                usage("unable to read source tree");
 105        tree2 = read_sha1_file(new, type, &size2);
 106        if (!tree2 || strcmp(type, "tree"))
 107                usage("unable to read destination tree");
 108        return diff_tree(tree1, size1, tree2, size2);
 109}