3 static int cached_only
= 0;
4 static int recursive
= 0;
5 static int line_termination
= '\n';
7 static int diff_cache(void *tree
, unsigned long size
, struct cache_entry
**ac
, int entries
, const char *base
);
9 static void update_tree_entry(void **bufp
, unsigned long *sizep
)
12 unsigned long size
= *sizep
;
13 int len
= strlen(buf
) + 1 + 20;
16 die("corrupt tree file 1 (%s)", size
);
21 static const unsigned char *extract(void *tree
, unsigned long size
, const char **pathp
, unsigned int *modep
)
23 int len
= strlen(tree
)+1;
24 const unsigned char *sha1
= tree
+ len
;
25 const char *path
= strchr(tree
, ' ');
27 if (!path
|| size
< len
+ 20 || sscanf(tree
, "%o", modep
) != 1)
28 die("corrupt tree file 2 (%d)", size
);
33 static char *malloc_base(const char *base
, const char *path
, int pathlen
)
35 int baselen
= strlen(base
);
36 char *newbase
= malloc(baselen
+ pathlen
+ 2);
37 memcpy(newbase
, base
, baselen
);
38 memcpy(newbase
+ baselen
, path
, pathlen
);
39 memcpy(newbase
+ baselen
+ pathlen
, "/", 2);
43 static void show_file(const char *prefix
, const char *path
, unsigned int mode
, const unsigned char *sha1
, const char *base
);
45 /* A whole sub-tree went away or appeared */
46 static void show_tree(const char *prefix
, void *tree
, unsigned long size
, const char *base
)
51 const unsigned char *sha1
= extract(tree
, size
, &path
, &mode
);
53 show_file(prefix
, path
, mode
, sha1
, base
);
54 update_tree_entry(&tree
, &size
);
58 /* A file entry went away or appeared */
59 static void show_file(const char *prefix
, const char *path
, unsigned int mode
, const unsigned char *sha1
, const char *base
)
61 if (recursive
&& S_ISDIR(mode
)) {
64 char *newbase
= malloc_base(base
, path
, strlen(path
));
67 tree
= read_sha1_file(sha1
, type
, &size
);
68 if (!tree
|| strcmp(type
, "tree"))
69 die("corrupt tree sha %s", sha1_to_hex(sha1
));
71 show_tree(prefix
, tree
, size
, newbase
);
78 printf("%s%o\t%s\t%s\t%s%s%c", prefix
, mode
,
79 S_ISDIR(mode
) ? "tree" : "blob",
80 sha1_to_hex(sha1
), base
, path
,
84 static int compare_tree_entry(const char *path1
, unsigned int mode1
, const unsigned char *sha1
,
85 struct cache_entry
**ac
, int *entries
, const char *base
)
87 int baselen
= strlen(base
);
88 struct cache_entry
*ce
= *ac
;
89 const char *path2
= ce
->name
+ baselen
;
90 unsigned int mode2
= ntohl(ce
->ce_mode
);
91 const unsigned char *sha2
= ce
->sha1
;
92 int cmp
, pathlen1
, pathlen2
;
93 char old_sha1_hex
[50];
95 pathlen1
= strlen(path1
);
96 pathlen2
= strlen(path2
);
97 cmp
= cache_name_compare(path1
, pathlen1
, path2
, pathlen2
);
102 void *tree
= read_sha1_file(sha1
, type
, &size
);
103 char *newbase
= malloc(baselen
+ 2 + pathlen1
);
105 memcpy(newbase
, base
, baselen
);
106 memcpy(newbase
+ baselen
, path1
, pathlen1
);
107 memcpy(newbase
+ baselen
+ pathlen1
, "/", 2);
108 if (!tree
|| strcmp(type
, "tree"))
109 die("unable to read tree object %s", sha1_to_hex(sha1
));
110 *entries
= diff_cache(tree
, size
, ac
, *entries
, newbase
);
115 show_file("-", path1
, mode1
, sha1
, base
);
120 static unsigned char no_sha1
[20];
123 fd
= open(ce
->name
, O_RDONLY
);
124 if (fd
< 0 || fstat(fd
, &st
) < 0) {
125 show_file("-", path1
, mode1
, sha1
, base
);
128 changed
= cache_match_stat(ce
, &st
);
137 show_file("+", path2
, mode2
, sha2
, base
);
140 if (!memcmp(sha1
, sha2
, 20) && mode1
== mode2
)
144 * If the filemode has changed to/from a directory from/to a regular
145 * file, we need to consider it a remove and an add.
147 if (S_ISDIR(mode1
) || S_ISDIR(mode2
)) {
148 show_file("-", path1
, mode1
, sha1
, base
);
149 show_file("+", path2
, mode2
, sha2
, base
);
153 strcpy(old_sha1_hex
, sha1_to_hex(sha1
));
154 printf("*%o->%o\t%s\t%s->%s\t%s%s%c", mode1
, mode2
,
155 S_ISDIR(mode1
) ? "tree" : "blob",
156 old_sha1_hex
, sha1_to_hex(sha2
), base
, path1
,
161 static int diff_cache(void *tree
, unsigned long size
, struct cache_entry
**ac
, int entries
, const char *base
)
163 int baselen
= strlen(base
);
166 struct cache_entry
*ce
;
169 const unsigned char *sha1
;
173 * No entries in the cache (with this base)?
174 * Output the tree contents.
176 if (!entries
|| ce_namelen(ce
= *ac
) < baselen
|| memcmp(ce
->name
, base
, baselen
)) {
179 sha1
= extract(tree
, size
, &path
, &mode
);
180 show_file("-", path
, mode
, sha1
, base
);
181 update_tree_entry(&tree
, &size
);
186 * No entries in the tree? Output the cache contents
189 show_file("+", ce
->name
, ntohl(ce
->ce_mode
), ce
->sha1
, "");
195 sha1
= extract(tree
, size
, &path
, &mode
);
197 switch (compare_tree_entry(path
, mode
, sha1
, ac
, &left
, base
)) {
199 update_tree_entry(&tree
, &size
);
200 if (left
< entries
) {
201 ac
+= (entries
- left
);
206 update_tree_entry(&tree
, &size
);
213 die("diff-cache: internal error");
218 static char *diff_cache_usage
= "diff-cache [-r] [-z] [--cached] <tree sha1>";
220 int main(int argc
, char **argv
)
222 unsigned char tree_sha1
[20];
231 if (!strcmp(arg
, "-r")) {
235 if (!strcmp(arg
, "-z")) {
236 line_termination
= '\0';
239 if (!strcmp(arg
, "--cached")) {
243 usage(diff_cache_usage
);
246 if (argc
!= 2 || get_sha1_hex(argv
[1], tree_sha1
))
247 usage(diff_cache_usage
);
249 tree
= read_tree_with_tree_or_commit_sha1(tree_sha1
, &size
, 0);
251 die("bad tree object %s", argv
[1]);
253 return diff_cache(tree
, size
, active_cache
, active_nr
, "");