Skip to content

Commit d1af002

Browse files
Nicolas PitreLinus Torvalds
authored andcommitted
[PATCH] delta check
This adds knowledge of delta objects to fsck-cache and various object parsing code. A new switch to git-fsck-cache is provided to display the maximum delta depth found in a repository. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent 91d7b8a commit d1af002

File tree

10 files changed

+202
-6
lines changed

10 files changed

+202
-6
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ install: $(PROG) $(SCRIPTS)
3636
$(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bin)
3737

3838
LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
39-
tag.o date.o index.o diff-delta.o patch-delta.o
39+
tag.o delta.o date.o index.o diff-delta.o patch-delta.o
4040
LIB_FILE=libgit.a
4141
LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h
4242

blob.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ struct blob *lookup_blob(unsigned char *sha1)
1414
ret->object.type = blob_type;
1515
return ret;
1616
}
17+
if (!obj->type)
18+
obj->type = blob_type;
1719
if (obj->type != blob_type) {
1820
error("Object %s is a %s, not a blob",
1921
sha1_to_hex(sha1), obj->type);

commit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ struct commit *lookup_commit(unsigned char *sha1)
3737
ret->object.type = commit_type;
3838
return ret;
3939
}
40+
if (!obj->type)
41+
obj->type = commit_type;
4042
return check_commit(obj, sha1);
4143
}
4244

delta.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "object.h"
2+
#include "blob.h"
3+
#include "tree.h"
4+
#include "commit.h"
5+
#include "tag.h"
6+
#include "delta.h"
7+
#include "cache.h"
8+
#include <string.h>
9+
10+
/* the delta object definition (it can alias any other object) */
11+
struct delta {
12+
union {
13+
struct object object;
14+
struct blob blob;
15+
struct tree tree;
16+
struct commit commit;
17+
struct tag tag;
18+
} u;
19+
};
20+
21+
struct delta *lookup_delta(unsigned char *sha1)
22+
{
23+
struct object *obj = lookup_object(sha1);
24+
if (!obj) {
25+
struct delta *ret = xmalloc(sizeof(struct delta));
26+
memset(ret, 0, sizeof(struct delta));
27+
created_object(sha1, &ret->u.object);
28+
return ret;
29+
}
30+
return (struct delta *) obj;
31+
}
32+
33+
int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size)
34+
{
35+
struct object *reference;
36+
struct object_list *p;
37+
38+
if (item->u.object.delta)
39+
return 0;
40+
item->u.object.delta = 1;
41+
if (size <= 20)
42+
return -1;
43+
reference = lookup_object(buffer);
44+
if (!reference) {
45+
struct delta *ref = xmalloc(sizeof(struct delta));
46+
memset(ref, 0, sizeof(struct delta));
47+
created_object(buffer, &ref->u.object);
48+
reference = &ref->u.object;
49+
}
50+
51+
p = xmalloc(sizeof(*p));
52+
p->item = &item->u.object;
53+
p->next = reference->attached_deltas;
54+
reference->attached_deltas = p;
55+
return 0;
56+
}
57+
58+
int process_deltas(void *src, unsigned long src_size, const char *src_type,
59+
struct object_list *delta_list)
60+
{
61+
int deepest = 0;
62+
do {
63+
struct object *obj = delta_list->item;
64+
static char type[10];
65+
void *map, *delta, *buf;
66+
unsigned long map_size, delta_size, buf_size;
67+
map = map_sha1_file(obj->sha1, &map_size);
68+
if (!map)
69+
continue;
70+
delta = unpack_sha1_file(map, map_size, type, &delta_size);
71+
munmap(map, map_size);
72+
if (!delta)
73+
continue;
74+
if (strcmp(type, "delta") || delta_size <= 20) {
75+
free(delta);
76+
continue;
77+
}
78+
buf = patch_delta(src, src_size,
79+
delta+20, delta_size-20,
80+
&buf_size);
81+
free(delta);
82+
if (!buf)
83+
continue;
84+
if (check_sha1_signature(obj->sha1, buf, buf_size, src_type) < 0)
85+
printf("sha1 mismatch for delta %s\n", sha1_to_hex(obj->sha1));
86+
if (obj->type && obj->type != src_type) {
87+
error("got %s when expecting %s for delta %s",
88+
src_type, obj->type, sha1_to_hex(obj->sha1));
89+
free(buf);
90+
continue;
91+
}
92+
obj->type = src_type;
93+
if (src_type == blob_type) {
94+
parse_blob_buffer((struct blob *)obj, buf, buf_size);
95+
} else if (src_type == tree_type) {
96+
parse_tree_buffer((struct tree *)obj, buf, buf_size);
97+
} else if (src_type == commit_type) {
98+
parse_commit_buffer((struct commit *)obj, buf, buf_size);
99+
} else if (src_type == tag_type) {
100+
parse_tag_buffer((struct tag *)obj, buf, buf_size);
101+
} else {
102+
error("unknown object type %s", src_type);
103+
free(buf);
104+
continue;
105+
}
106+
if (obj->attached_deltas) {
107+
int depth = process_deltas(buf, buf_size, src_type,
108+
obj->attached_deltas);
109+
if (deepest < depth)
110+
deepest = depth;
111+
}
112+
free(buf);
113+
} while ((delta_list = delta_list->next));
114+
return deepest + 1;
115+
}

delta.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1+
#ifndef DELTA_H
2+
#define DELTA_H
3+
4+
/* handling of delta buffers */
15
extern void *diff_delta(void *from_buf, unsigned long from_size,
26
void *to_buf, unsigned long to_size,
37
unsigned long *delta_size);
48
extern void *patch_delta(void *src_buf, unsigned long src_size,
59
void *delta_buf, unsigned long delta_size,
610
unsigned long *dst_size);
11+
12+
/* handling of delta objects */
13+
struct delta;
14+
struct object_list;
15+
extern struct delta *lookup_delta(unsigned char *sha1);
16+
extern int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size);
17+
extern int parse_delta(struct delta *item, unsigned char sha1);
18+
extern int process_deltas(void *src, unsigned long src_size,
19+
const char *src_type, struct object_list *delta);
20+
21+
#endif

fsck-cache.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,46 @@
66
#include "tree.h"
77
#include "blob.h"
88
#include "tag.h"
9+
#include "delta.h"
910

1011
#define REACHABLE 0x0001
1112

1213
static int show_root = 0;
1314
static int show_tags = 0;
1415
static int show_unreachable = 0;
16+
static int show_max_delta_depth = 0;
1517
static int keep_cache_objects = 0;
1618
static unsigned char head_sha1[20];
1719

20+
static void expand_deltas(void)
21+
{
22+
int i, max_depth = 0;
23+
24+
/*
25+
* To be as efficient as possible we look for delta heads and
26+
* recursively process them going backward, and parsing
27+
* resulting objects along the way. This allows for processing
28+
* each delta objects only once regardless of the delta depth.
29+
*/
30+
for (i = 0; i < nr_objs; i++) {
31+
struct object *obj = objs[i];
32+
if (obj->parsed && !obj->delta && obj->attached_deltas) {
33+
int depth = 0;
34+
char type[10];
35+
unsigned long size;
36+
void *buf = read_sha1_file(obj->sha1, type, &size);
37+
if (!buf)
38+
continue;
39+
depth = process_deltas(buf, size, obj->type,
40+
obj->attached_deltas);
41+
if (max_depth < depth)
42+
max_depth = depth;
43+
}
44+
}
45+
if (show_max_delta_depth)
46+
printf("maximum delta depth = %d\n", max_depth);
47+
}
48+
1849
static void check_connectivity(void)
1950
{
2051
int i;
@@ -25,7 +56,12 @@ static void check_connectivity(void)
2556
struct object_list *refs;
2657

2758
if (!obj->parsed) {
28-
printf("missing %s %s\n", obj->type, sha1_to_hex(obj->sha1));
59+
if (obj->delta)
60+
printf("unresolved delta %s\n",
61+
sha1_to_hex(obj->sha1));
62+
else
63+
printf("missing %s %s\n",
64+
obj->type, sha1_to_hex(obj->sha1));
2965
continue;
3066
}
3167

@@ -43,7 +79,12 @@ static void check_connectivity(void)
4379
continue;
4480

4581
if (show_unreachable && !(obj->flags & REACHABLE)) {
46-
printf("unreachable %s %s\n", obj->type, sha1_to_hex(obj->sha1));
82+
if (obj->attached_deltas)
83+
printf("foreign delta reference %s\n",
84+
sha1_to_hex(obj->sha1));
85+
else
86+
printf("unreachable %s %s\n",
87+
obj->type, sha1_to_hex(obj->sha1));
4788
continue;
4889
}
4990

@@ -201,6 +242,8 @@ static int fsck_sha1(unsigned char *sha1)
201242
return fsck_commit((struct commit *) obj);
202243
if (obj->type == tag_type)
203244
return fsck_tag((struct tag *) obj);
245+
if (!obj->type && obj->delta)
246+
return 0;
204247
return -1;
205248
}
206249

@@ -384,6 +427,10 @@ int main(int argc, char **argv)
384427
show_root = 1;
385428
continue;
386429
}
430+
if (!strcmp(arg, "--delta-depth")) {
431+
show_max_delta_depth = 1;
432+
continue;
433+
}
387434
if (!strcmp(arg, "--cache")) {
388435
keep_cache_objects = 1;
389436
continue;
@@ -400,6 +447,8 @@ int main(int argc, char **argv)
400447
}
401448
fsck_sha1_list();
402449

450+
expand_deltas();
451+
403452
heads = 0;
404453
for (i = 1; i < argc; i++) {
405454
const char *arg = argv[i];
@@ -423,7 +472,7 @@ int main(int argc, char **argv)
423472
}
424473

425474
/*
426-
* If we've not been gived any explicit head information, do the
475+
* If we've not been given any explicit head information, do the
427476
* default ones from .git/refs. We also consider the index file
428477
* in this case (ie this implies --cache).
429478
*/

object.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "commit.h"
55
#include "cache.h"
66
#include "tag.h"
7+
#include "delta.h"
78
#include <stdlib.h>
89
#include <string.h>
910

@@ -104,16 +105,22 @@ struct object *parse_object(unsigned char *sha1)
104105
unsigned long mapsize;
105106
void *map = map_sha1_file(sha1, &mapsize);
106107
if (map) {
108+
int is_delta;
107109
struct object *obj;
108110
char type[100];
109111
unsigned long size;
110112
void *buffer = unpack_sha1_file(map, mapsize, type, &size);
111113
munmap(map, mapsize);
112114
if (!buffer)
113115
return NULL;
114-
if (check_sha1_signature(sha1, buffer, size, type) < 0)
116+
is_delta = !strcmp(type, "delta");
117+
if (!is_delta && check_sha1_signature(sha1, buffer, size, type) < 0)
115118
printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
116-
if (!strcmp(type, "blob")) {
119+
if (is_delta) {
120+
struct delta *delta = lookup_delta(sha1);
121+
parse_delta_buffer(delta, buffer, size);
122+
obj = (struct object *) delta;
123+
} else if (!strcmp(type, "blob")) {
117124
struct blob *blob = lookup_blob(sha1);
118125
parse_blob_buffer(blob, buffer, size);
119126
obj = &blob->object;

object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ struct object_list {
99
struct object {
1010
unsigned parsed : 1;
1111
unsigned used : 1;
12+
unsigned delta : 1;
1213
unsigned int flags;
1314
unsigned char sha1[20];
1415
const char *type;
1516
struct object_list *refs;
17+
struct object_list *attached_deltas;
1618
};
1719

1820
extern int nr_objs;

tag.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ struct tag *lookup_tag(unsigned char *sha1)
1313
ret->object.type = tag_type;
1414
return ret;
1515
}
16+
if (!obj->type)
17+
obj->type = tag_type;
1618
if (obj->type != tag_type) {
1719
error("Object %s is a %s, not a tree",
1820
sha1_to_hex(sha1), obj->type);

tree.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ struct tree *lookup_tree(unsigned char *sha1)
8383
ret->object.type = tree_type;
8484
return ret;
8585
}
86+
if (!obj->type)
87+
obj->type = tree_type;
8688
if (obj->type != tree_type) {
8789
error("Object %s is a %s, not a tree",
8890
sha1_to_hex(sha1), obj->type);

0 commit comments

Comments
 (0)