3 static int recursive
= 0;
5 static int diff_tree_sha1(const unsigned char *old
, const unsigned char *new, const char *src
, const char *dst
);
7 static void update_tree_entry(void **bufp
, unsigned long *sizep
)
10 unsigned long size
= *sizep
;
11 int len
= strlen(buf
) + 1 + 20;
14 usage("corrupt tree file");
19 static const unsigned char *extract(void *tree
, unsigned long size
, const char **pathp
, unsigned int *modep
)
21 int len
= strlen(tree
)+1;
22 const unsigned char *sha1
= tree
+ len
;
23 const char *path
= strchr(tree
, ' ');
25 if (!path
|| size
< len
+ 20 || sscanf(tree
, "%o", modep
) != 1)
26 usage("corrupt tree file");
31 static void show_file(const char *prefix
, void *tree
, unsigned long size
, const char *base
)
35 const unsigned char *sha1
= extract(tree
, size
, &path
, &mode
);
36 printf("%s%o %s %s%s%c", prefix
, mode
, sha1_to_hex(sha1
), base
, path
, 0);
39 static int compare_tree_entry(void *tree1
, unsigned long size1
, void *tree2
, unsigned long size2
, const char *src
, const char *dst
)
41 unsigned mode1
, mode2
;
42 const char *path1
, *path2
;
43 const unsigned char *sha1
, *sha2
;
44 int cmp
, pathlen1
, pathlen2
;
46 sha1
= extract(tree1
, size1
, &path1
, &mode1
);
47 sha2
= extract(tree2
, size2
, &path2
, &mode2
);
49 pathlen1
= strlen(path1
);
50 pathlen2
= strlen(path2
);
51 cmp
= cache_name_compare(path1
, pathlen1
, path2
, pathlen2
);
53 show_file("-", tree1
, size1
, src
);
57 show_file("+", tree2
, size2
, dst
);
60 if (!memcmp(sha1
, sha2
, 20) && mode1
== mode2
)
62 if (recursive
&& S_ISDIR(mode1
) && S_ISDIR(mode2
)) {
63 int srclen
= strlen(src
);
64 int dstlen
= strlen(dst
);
65 char *srcbase
= malloc(srclen
+ pathlen1
+ 2);
66 char *dstbase
= malloc(srclen
+ pathlen1
+ 2);
67 memcpy(srcbase
, src
, srclen
);
68 memcpy(srcbase
+ srclen
, path1
, pathlen1
);
69 memcpy(srcbase
+ srclen
+ pathlen1
, "/", 2);
70 memcpy(dstbase
, dst
, dstlen
);
71 memcpy(dstbase
+ dstlen
, path2
, pathlen2
);
72 memcpy(dstbase
+ dstlen
+ pathlen2
, "/", 2);
73 return diff_tree_sha1(sha1
, sha2
, srcbase
, dstbase
);
76 show_file("<", tree1
, size1
, src
);
77 show_file(">", tree2
, size2
, dst
);
81 static int diff_tree(void *tree1
, unsigned long size1
, void *tree2
, unsigned long size2
, const char *src
, const char *dst
)
83 while (size1
| size2
) {
85 show_file("+", tree2
, size2
, dst
);
86 update_tree_entry(&tree2
, &size2
);
90 show_file("-", tree1
, size1
, src
);
91 update_tree_entry(&tree1
, &size1
);
94 switch (compare_tree_entry(tree1
, size1
, tree2
, size2
, src
, dst
)) {
96 update_tree_entry(&tree1
, &size1
);
99 update_tree_entry(&tree1
, &size1
);
102 update_tree_entry(&tree2
, &size2
);
105 usage("diff-tree: internal error");
110 static int diff_tree_sha1(const unsigned char *old
, const unsigned char *new, const char *src
, const char *dst
)
113 unsigned long size1
, size2
;
117 tree1
= read_sha1_file(old
, type
, &size1
);
118 if (!tree1
|| strcmp(type
, "tree"))
119 usage("unable to read source tree");
120 tree2
= read_sha1_file(new, type
, &size2
);
121 if (!tree2
|| strcmp(type
, "tree"))
122 usage("unable to read destination tree");
123 retval
= diff_tree(tree1
, size1
, tree2
, size2
, src
, dst
);
129 int main(int argc
, char **argv
)
131 unsigned char old
[20], new[20];
137 if (!strcmp(arg
, "-R")) {
141 usage("diff-tree [-R] <tree sha1> <tree sha1>");
144 if (argc
!= 3 || get_sha1_hex(argv
[1], old
) || get_sha1_hex(argv
[2], new))
145 usage("diff-tree <tree sha1> <tree sha1>");
146 return diff_tree_sha1(old
, new, "", "");